From 9566641eaaeabdbaa516411a11ddf7f11e31840a Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Tue, 24 Sep 2019 17:28:11 +0800 Subject: [PATCH 01/93] Update cmpt_06_phonon.py --- dpgen/auto_test/cmpt_06_phonon.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/dpgen/auto_test/cmpt_06_phonon.py b/dpgen/auto_test/cmpt_06_phonon.py index 92395bb8e..9408aa873 100644 --- a/dpgen/auto_test/cmpt_06_phonon.py +++ b/dpgen/auto_test/cmpt_06_phonon.py @@ -74,17 +74,12 @@ def cmpt_vasp(jdata, conf_dir) : -def cmpt_deepmd_lammps(jdata, conf_dir) : - deepmd_model_dir = jdata['deepmd_model_dir'] - deepmd_type_map = jdata['deepmd_type_map'] - ntypes = len(deepmd_type_map) - deepmd_model_dir = os.path.abspath(deepmd_model_dir) - deepmd_models = glob.glob(os.path.join(deepmd_model_dir, '*pb')) +def cmpt_lammps(jdata, conf_dir, task_type) : supercell_matrix=jdata['supercell_matrix'] conf_path = os.path.abspath(conf_dir) task_path = re.sub('confs', global_task_name, conf_path) - task_path = os.path.join(task_path, 'deepmd') + task_path = os.path.join(task_path, task_type) task_poscar = os.path.join(task_path, 'POSCAR') os.chdir(task_path) @@ -112,10 +107,8 @@ def _main() : # print('generate %s task with conf %s' % (args.TASK, args.CONF)) if args.TASK == 'vasp': cmpt_vasp(jdata, args.CONF) - elif args.TASK == 'deepmd' : - cmpt_deepmd_lammps(jdata, args.CONF) - elif args.TASK == 'meam' : - cmpt_meam_lammps(jdata, args.CONF) + elif args.TASK == 'deepmd' or args.TASK =='meam' : + cmptlammps(jdata, args.CONF,args.TASK) else : raise RuntimeError("unknow task ", args.TASK) From 11ad4b4375cc02699c19acaaf166155070ee7b1c Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 3 Oct 2019 18:42:00 +0800 Subject: [PATCH 02/93] Update cmpt_06_phonon.py --- dpgen/auto_test/cmpt_06_phonon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpgen/auto_test/cmpt_06_phonon.py b/dpgen/auto_test/cmpt_06_phonon.py index 9408aa873..cefa615fe 100644 --- a/dpgen/auto_test/cmpt_06_phonon.py +++ b/dpgen/auto_test/cmpt_06_phonon.py @@ -108,7 +108,7 @@ def _main() : if args.TASK == 'vasp': cmpt_vasp(jdata, args.CONF) elif args.TASK == 'deepmd' or args.TASK =='meam' : - cmptlammps(jdata, args.CONF,args.TASK) + cmpt_lammps(jdata, args.CONF,args.TASK) else : raise RuntimeError("unknow task ", args.TASK) From 3b822e7e8cc413d543406e54691d2919e50ac6eb Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 3 Oct 2019 18:43:57 +0800 Subject: [PATCH 03/93] Update cmpt_01_eos.py --- dpgen/auto_test/cmpt_01_eos.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/dpgen/auto_test/cmpt_01_eos.py b/dpgen/auto_test/cmpt_01_eos.py index 7c73ae057..93177148f 100755 --- a/dpgen/auto_test/cmpt_01_eos.py +++ b/dpgen/auto_test/cmpt_01_eos.py @@ -13,10 +13,13 @@ def comput_lmp_eos(conf_dir, task_name) : vol_paths = glob.glob(os.path.join(conf_path, 'vol-*')) vol_paths.sort() print('Vpa(A^3)\tEpA(eV)') - for ii in vol_paths : - log_lammps = os.path.join(ii, 'log.lammps') - natoms, epa, vpa = lammps.get_nev(log_lammps) - print(vpa, epa) + with open(os.path.join(conf_path,'result'),'w') as fp: + fp.write('conf_dir:%s\n VpA(A^3) EpA(eV)\n'% (conf_dir)) + for ii in vol_paths : + log_lammps = os.path.join(ii, 'log.lammps') + natoms, epa, vpa = lammps.get_nev(log_lammps) + print(vpa, epa) + fp.write('%7.3f %8.4f \n' % (vpa,epa)) def comput_vasp_eos(jdata, conf_dir) : conf_path = re.sub('confs', global_task_name, conf_dir) @@ -31,10 +34,13 @@ def comput_vasp_eos(jdata, conf_dir) : vol_paths = glob.glob(os.path.join(task_path, 'vol-*')) vol_paths.sort() print('Vpa(A^3)\tEpA(eV)') - for ii in vol_paths : - outcar = os.path.join(ii, 'OUTCAR') - natoms, epa, vpa = vasp.get_nev(outcar) - print(vpa, epa) + with open(os.path.join(conf_path,'result'),'w') as fp: + fp.write('conf_dir:%s\n VpA(A^3) EpA(eV)\n'% (conf_dir)) + for ii in vol_paths : + outcar = os.path.join(ii, 'OUTCAR') + natoms, epa, vpa = vasp.get_nev(outcar) + print(vpa, epa) + fp.write('%7.3f %8.4f \n' % (vpa,epa)) def _main(): parser = argparse.ArgumentParser( From 8b7cea3d6102d6760cce5cede005bb38fc11ceb0 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 3 Oct 2019 18:44:51 +0800 Subject: [PATCH 04/93] Update cmpt_02_elastic.py --- dpgen/auto_test/cmpt_02_elastic.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dpgen/auto_test/cmpt_02_elastic.py b/dpgen/auto_test/cmpt_02_elastic.py index e1a93cf3f..cc60582c8 100755 --- a/dpgen/auto_test/cmpt_02_elastic.py +++ b/dpgen/auto_test/cmpt_02_elastic.py @@ -12,6 +12,22 @@ global_equi_name = '00.equi' global_task_name = '02.elastic' +def result_et(et,conf_dir,task_path): + with open(os.path.join(task_path,'result'),'w') as fp: + fp.write('conf_dir:%s\n'% (conf_dir)) + for ii in range(6) : + for jj in range(6) : + fp.write ("%7.2f " % (et.voigt[ii][jj] / 1e4)) + fp.write('\n') + BV = et.k_voigt / 1e4 + GV = et.g_voigt / 1e4 + EV = 9*BV*GV/(3*BV+GV) + uV = 0.5*(3*BV-2*GV)/(3*BV+GV) + fp.write("# Bulk Modulus BV = %.2f GPa\n" % (BV)) + fp.write("# Shear Modulus GV = %.2f GPa\n" % (GV)) + fp.write("# Youngs Modulus EV = %.2f GPa\n" % (EV)) + fp.write("# Poission Ratio uV = %.2f \n" % (uV)) + def print_et (et): for ii in range(6) : for jj in range(6) : @@ -57,6 +73,7 @@ def cmpt_vasp(jdata, conf_dir) : # bar to GPa # et = -et / 1e4 print_et(et) + result_et(et,conf_dir,task_path) def cmpt_deepmd_lammps(jdata, conf_dir, task_name) : deepmd_model_dir = jdata['deepmd_model_dir'] @@ -84,6 +101,7 @@ def cmpt_deepmd_lammps(jdata, conf_dir, task_name) : # bar to GPa # et = -et / 1e4 print_et(et) + result_et(et,conf_dir,task_path) def _main() : parser = argparse.ArgumentParser( From a5f68b92e70ee254a442a9e24c50afb95d4d8e43 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 3 Oct 2019 18:46:26 +0800 Subject: [PATCH 05/93] Update cmpt_05_surf.py --- dpgen/auto_test/cmpt_05_surf.py | 49 +++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/dpgen/auto_test/cmpt_05_surf.py b/dpgen/auto_test/cmpt_05_surf.py index 672095c45..1c1f9cb23 100755 --- a/dpgen/auto_test/cmpt_05_surf.py +++ b/dpgen/auto_test/cmpt_05_surf.py @@ -44,18 +44,23 @@ def cmpt_vasp(jdata, conf_dir, static = False) : if len(struct_path_list) == 0: print("# cannot find results for conf %s" % (conf_dir)) sys.stdout.write ("Miller_Indices: \tSurf_E(J/m^2) EpA(eV) equi_EpA(eV)\n") - for ii in struct_path_list : - structure_dir = os.path.basename(ii) - outcar = os.path.join(ii, 'OUTCAR') - natoms, epa, vpa = vasp.get_nev(outcar) - if static : - e0 = np.array(vasp.get_energies(outcar)) / natoms - epa = e0[0] - boxes = vasp.get_boxes(outcar) - AA = np.linalg.norm(np.cross(boxes[0][0], boxes[0][1])) - Cf = 1.60217657e-16 / (1e-20 * 2) * 0.001 - evac = (epa * natoms - equi_epa * natoms) / AA * Cf - sys.stdout.write ("%s:\t %7.3f %8.3f %8.3f\n" % (structure_dir, evac, epa, equi_epa)) + + with open(os.path.join(task_path,'result'),'w') as fp: + fp.write('conf_dir:%s\n'% (conf_dir)) + fp.write("Miller_Indices: \tSurf_E(J/m^2) EpA(eV) equi_EpA(eV)\n") + for ii in struct_path_list : + structure_dir = os.path.basename(ii) + outcar = os.path.join(ii, 'OUTCAR') + natoms, epa, vpa = vasp.get_nev(outcar) + if static : + e0 = np.array(vasp.get_energies(outcar)) / natoms + epa = e0[0] + boxes = vasp.get_boxes(outcar) + AA = np.linalg.norm(np.cross(boxes[0][0], boxes[0][1])) + Cf = 1.60217657e-16 / (1e-20 * 2) * 0.001 + evac = (epa * natoms - equi_epa * natoms) / AA * Cf + sys.stdout.write ("%s:\t %7.3f %8.3f %8.3f\n" % (structure_dir, evac, epa, equi_epa)) + fp.write("%s:\t %7.3f %8.3f %8.3f\n" % (structure_dir, evac, epa, equi_epa)) def cmpt_deepmd_lammps(jdata, conf_dir, task_name, static = False) : equi_path = re.sub('confs', global_equi_name, conf_dir) @@ -74,14 +79,18 @@ def cmpt_deepmd_lammps(jdata, conf_dir, task_name, static = False) : if len(struct_path_list) == 0: print("# cannot find results for conf %s" % (conf_dir)) sys.stdout.write ("Miller_Indices: \tSurf_E(J/m^2) EpA(eV) equi_EpA(eV)\n") - for ii in struct_path_list : - structure_dir = os.path.basename(ii) - lmp_log = os.path.join(ii, 'log.lammps') - natoms, epa, vpa = lammps.get_nev(lmp_log) - AA = lammps.get_base_area(lmp_log) - Cf = 1.60217657e-16 / (1e-20 * 2) * 0.001 - evac = (epa * natoms - equi_epa * natoms) / AA * Cf - sys.stdout.write ("%s: \t%7.3f %8.3f %8.3f\n" % (structure_dir, evac, epa, equi_epa)) + with open(os.path.join(task_path,'result'),'w') as fp: + fp.write('conf_dir:%s\n'% (conf_dir)) + fp.write("Miller_Indices: \tSurf_E(J/m^2) EpA(eV) equi_EpA(eV)\n") + for ii in struct_path_list : + structure_dir = os.path.basename(ii) + lmp_log = os.path.join(ii, 'log.lammps') + natoms, epa, vpa = lammps.get_nev(lmp_log) + AA = lammps.get_base_area(lmp_log) + Cf = 1.60217657e-16 / (1e-20 * 2) * 0.001 + evac = (epa * natoms - equi_epa * natoms) / AA * Cf + sys.stdout.write ("%s: \t%7.3f %8.3f %8.3f\n" % (structure_dir, evac, epa, equi_epa)) + fp.write("%s:\t %7.3f %8.3f %8.3f\n" % (structure_dir, evac, epa, equi_epa)) def _main() : parser = argparse.ArgumentParser( From 6f356f7834a924080b839c7671771b7987d0d8e0 Mon Sep 17 00:00:00 2001 From: felix5572 Date: Sun, 6 Oct 2019 06:56:02 +0000 Subject: [PATCH 06/93] new class AWS --- dpgen/dispatcher/AWS.py | 128 +++++++++++++++++++++++++++++++++ dpgen/dispatcher/Dispatcher.py | 3 + 2 files changed, 131 insertions(+) create mode 100644 dpgen/dispatcher/AWS.py diff --git a/dpgen/dispatcher/AWS.py b/dpgen/dispatcher/AWS.py new file mode 100644 index 000000000..d983efce1 --- /dev/null +++ b/dpgen/dispatcher/AWS.py @@ -0,0 +1,128 @@ +import os,getpass,time +from datetime import datetime +from itertools import zip_longest +from dpgen.dispatcher.Batch import Batch +from dpgen.dispatcher.JobStatus import JobStatus +from dpgen import dlog + +class AWS(Batch): + try : + import boto3 + batch = boto3.client('batch') + except ModuleNotFoundError: + pass + _query_max_results = 1000 + _query_time_interval = 30 + _job_id_map_status = {} + _jobQueue = "" + _query_next_allow_time = datetime.now().timestamp() + + @classmethod + def AWS_check_status(cls, caller_instance=None): + """ + to aviod query jobStatus too often, set a time interval + query_dict example: + {job_id: JobStatus} + + {'40fb24b2-d0ca-4443-8e3a-c0906ea03622': , + '41bda50c-0a23-4372-806c-87d16a680d85': } + + + """ + if datetime.now().timestamp() > cls._query_next_allow_time: + cls._query_next_allow_time=datetime.now().timestamp()+cls._query_time_interval + query_dict ={} + for status in ['SUBMITTED', 'PENDING', 'RUNNABLE', 'STARTING', 'RUNNING','SUCCEEDED', 'FAILED']: + status_response = cls.batch.list_jobs(jobQueue=cls._jobQueue, jobStatus=status, maxResults=cls._query_max_results) + status_list=status_response.get('jobSummaryList', []) + for job_dict in status_list: + query_dict.update({job_dict['jobId']: job_dict['status']}) + for job in cls._job_id_map_status: + cls._job_id_map_status[job]= cls.map_aws_status_to_dpgen_status(query_dict.get(job, 'UNKNOWN')) + dlog.debug('20000: _query: %s, _map: %s' %(query_dict, cls._job_id_map_status)) + if caller_instance: + return cls._job_id_map_status.get(caller_instance.job_id, JobStatus.unknown) + return cls._job_id_map_status + + @staticmethod + def map_aws_status_to_dpgen_status(aws_status): + map_dict = {'SUBMITTED': JobStatus.waiting, + 'PENDING': JobStatus.waiting, + 'RUNNABLE': JobStatus.waiting, + 'STARTING': JobStatus.waiting, + 'RUNNING': JobStatus.running, + 'SUCCEEDED': JobStatus.finished, + 'FAILED': JobStatus.terminated, + 'UNKNOWN': JobStatus.unknown} + return map_dict.get(aws_status, JobStatus.unknown) + + @property + def job_id(self): + return self._job_id + + @job_id.setter + def job_id(self, values): + response, jobQueue = values + self._job_id = response['jobId'] + self._job_name = response['jobName'] + self.__class__._jobQueue = jobQueue + self.__class__._job_id_map_status[self._job_id] = JobStatus.waiting + dlog.debug("15000, _job_id:%s, _job_name:%s, _map:%s, _Queue:%s" % (self._job_id, self._job_name, self.__class__._job_id_map_status, self.__class__._jobQueue)) + + def check_status(self): + return self.__class__.AWS_check_status(caller_instance=self) + + def sub_script(self, job_dirs, cmd, args, res, outlog, errlog): + """ + return a command_Str like(indeed withoud tailing \n): + ((cd /home/ec2-user/Ag_init/run_gen/iter.000000/00.train/001 && /usr/bin/dp_train input.json 2>>train.log |tee -a train.log)&& touch tag_0_finished);wait; + ((cd /home/ec2-user/Ag_init/run_gen/iter.000000/00.train/001 && /usr/bin/dp_frz 2>>train.log |tee -a train.log)&& touch tag_1_finished);wait; + ((cd /home/ec2-user/Ag_init/run_gen/iter.000000/00.train/003 && /usr/bin/dp_train input.json 2>>train.log |tee -a train.log)&& touch tag_0_finished);wait; + ((cd /home/ec2-user/Ag_init/run_gen/iter.000000/00.train/003 && /usr/bin/dp_frz 2>>train.log |tee -a train.log)&& touch tag_1_finished);wait; + """ + if args is None: + args=[] + multi_command = "" + for job_dir in job_dirs: + for idx,t in enumerate(zip_longest(cmd, args, fillvalue='')): + c_str = f"((cd {self.context.remote_root}/{job_dir} && {t[0]} {t[1]} 2>>{errlog} |tee -a {outlog})&& touch tag_{idx}_finished);wait;" + multi_command += c_str + dlog.debug("10000, %s" % multi_command) + return multi_command + + def default_resources(self, res): + if res == None: + res = {} + else: + # res.setdefault(jobDefinition) + res.setdefault('cpu_num', 32) + res.setdefault('memory_size', 120000) + res.setdefault('jobQueue', 'deepmd_m5_v1_7') + return res + + def submit(self, + job_dirs, + cmd, + args = None, + res = None, + outlog = 'log', + errlog = 'err'): + + res = self.default_resources(res) + dlog.debug("2000, params=(%s, %s, %s, %s, %s, %s, )" % (job_dirs, cmd, args, res, outlog, errlog )) + dlog.debug('2200, self.context.remote_root: %s , self.context.local_root: %s' % (self.context.remote_root, self.context.local_root)) + # concreate_command = + script_str = self.sub_script(job_dirs, cmd, args=args, res=res, outlog=outlog, errlog=errlog) + dlog.debug('2300, script_str: %s, self.sub_script_name: %s' % (script_str, self.sub_script_name)) + """ + jobName example: + home-ec2-user-Ag_init-run_gen-iter_000000-01_model_devi-task_000_000048 + """ + jobName = os.path.join(self.context.remote_root,job_dirs.pop())[1:].replace('/','-').replace('.','_') + response = self.__class__.batch.submit_job(jobName=jobName, + jobQueue=res['jobQueue'], + jobDefinition=res['jobDefinition'], + parameters={'task_command':script_str}, + containerOverrides={'vcpus':res['cpu_num'], 'memory':res['memory_size']}) + dlog.debug('4000, response:%s' % response) + self.job_id = (response, res['jobQueue']) diff --git a/dpgen/dispatcher/Dispatcher.py b/dpgen/dispatcher/Dispatcher.py index 19aed2668..5fb2af693 100644 --- a/dpgen/dispatcher/Dispatcher.py +++ b/dpgen/dispatcher/Dispatcher.py @@ -9,6 +9,7 @@ from dpgen.dispatcher.LSF import LSF from dpgen.dispatcher.PBS import PBS from dpgen.dispatcher.Shell import Shell +from dpgen.dispatcher.AWS import AWS from dpgen.dispatcher.JobStatus import JobStatus from dpgen import dlog from hashlib import sha1 @@ -58,6 +59,8 @@ def __init__ (self, self.batch = PBS elif batch_type == 'shell': self.batch = Shell + elif batch_type == 'aws': + self.batch = AWS else : raise RuntimeError('unknown batch ' + batch_type) From f4cc0114a8761b6bb137b31f4a2fc9c698f38925 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 6 Oct 2019 17:25:39 +0800 Subject: [PATCH 07/93] mv tools. nicer brief report --- dpgen/generator/run.py | 2 +- dpgen/{generator => }/tools/__init__.py | 0 dpgen/{generator => }/tools/collect_data.py | 0 dpgen/{generator => }/tools/relabel.py | 0 dpgen/{generator => }/tools/stat_data.py | 2 -- 5 files changed, 1 insertion(+), 3 deletions(-) rename dpgen/{generator => }/tools/__init__.py (100%) rename dpgen/{generator => }/tools/collect_data.py (100%) rename dpgen/{generator => }/tools/relabel.py (100%) rename dpgen/{generator => }/tools/stat_data.py (98%) diff --git a/dpgen/generator/run.py b/dpgen/generator/run.py index 1baab1385..70c5033d3 100644 --- a/dpgen/generator/run.py +++ b/dpgen/generator/run.py @@ -762,7 +762,7 @@ def _make_fp_vasp_inner (modd_path, # print a report fp_sum = sum(counter.values()) for cc_key, cc_value in counter.items(): - dlog.info("{}: {} {}".format(cc_key, cc_value, cc_value/fp_sum)) + dlog.info("system {0:s} {1:9s} : {2:6d} {3:6.2f} %".format(ss, cc_key, cc_value, cc_value/fp_sum*100)) random.shuffle(fp_candidate) if detailed_report_make_fp: random.shuffle(fp_rest_failed) diff --git a/dpgen/generator/tools/__init__.py b/dpgen/tools/__init__.py similarity index 100% rename from dpgen/generator/tools/__init__.py rename to dpgen/tools/__init__.py diff --git a/dpgen/generator/tools/collect_data.py b/dpgen/tools/collect_data.py similarity index 100% rename from dpgen/generator/tools/collect_data.py rename to dpgen/tools/collect_data.py diff --git a/dpgen/generator/tools/relabel.py b/dpgen/tools/relabel.py similarity index 100% rename from dpgen/generator/tools/relabel.py rename to dpgen/tools/relabel.py diff --git a/dpgen/generator/tools/stat_data.py b/dpgen/tools/stat_data.py similarity index 98% rename from dpgen/generator/tools/stat_data.py rename to dpgen/tools/stat_data.py index 43904fdb0..c69b13b04 100755 --- a/dpgen/generator/tools/stat_data.py +++ b/dpgen/tools/stat_data.py @@ -4,8 +4,6 @@ import numpy as np import subprocess as sp sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')) -from lib.vasp import make_vasp_incar -from lib.vasp import system_from_poscar from relabel import get_lmp_info def ascii_hist(count) : From fe495b75d9004b0d15890c14a0160b1807955fb8 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 6 Oct 2019 18:09:59 +0800 Subject: [PATCH 08/93] fix bug: record job_uuid for lazy mode in pmap --- dpgen/dispatcher/Dispatcher.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dpgen/dispatcher/Dispatcher.py b/dpgen/dispatcher/Dispatcher.py index 19aed2668..6acea3540 100644 --- a/dpgen/dispatcher/Dispatcher.py +++ b/dpgen/dispatcher/Dispatcher.py @@ -93,7 +93,8 @@ def run_jobs(self, chunk_sha1 = sha1(task_chunks_[ii].encode('utf-8')).hexdigest() # if hash in map, recover job, else start a new job if chunk_sha1 in path_map: - job_uuid = path_map[chunk_sha1][1].split('/')[-1] + # job_uuid = path_map[chunk_sha1][1].split('/')[-1] + job_uuid = path_map[chunk_sha1][2] dlog.debug("load uuid %s for chunk %s" % (job_uuid, task_chunks_[ii])) else: job_uuid = None @@ -113,14 +114,15 @@ def run_jobs(self, # submit new or recover old submission if job_uuid is None: rjob['batch'].submit(chunk, command, res = resources, outlog=outlog, errlog=errlog) - dlog.debug('assigned uudi %s for %s ' % (rjob['context'].job_uuid, task_chunks_[ii])) - dlog.info('new submission of %s' % rjob['context'].job_uuid) + job_uuid = rjob['context'].job_uuid + dlog.debug('assigned uudi %s for %s ' % (job_uuid, task_chunks_[ii])) + dlog.info('new submission of %s' % job_uuid) else: rjob['batch'].submit(chunk, command, res = resources, outlog=outlog, errlog=errlog, restart = True) dlog.info('restart from old submission %s ' % job_uuid) # record job and its hash job_list.append(rjob) - path_map[chunk_sha1] = [context.local_root,context.remote_root] + path_map[chunk_sha1] = [context.local_root, context.remote_root, job_uuid] else : # finished job, append a None to list job_list.append(None) From f2b3e5988775d3d1d14209e520de3fbfaae061ae Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 6 Oct 2019 18:21:36 +0800 Subject: [PATCH 09/93] brief report total number of explored configs of a system --- dpgen/generator/run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpgen/generator/run.py b/dpgen/generator/run.py index 70c5033d3..ecb4469d5 100644 --- a/dpgen/generator/run.py +++ b/dpgen/generator/run.py @@ -762,7 +762,7 @@ def _make_fp_vasp_inner (modd_path, # print a report fp_sum = sum(counter.values()) for cc_key, cc_value in counter.items(): - dlog.info("system {0:s} {1:9s} : {2:6d} {3:6.2f} %".format(ss, cc_key, cc_value, cc_value/fp_sum*100)) + dlog.info("system {0:s} {1:9s} : {2:6d} in {3:6d} {4:6.2f} %".format(ss, cc_key, cc_value, fp_sum, cc_value/fp_sum*100)) random.shuffle(fp_candidate) if detailed_report_make_fp: random.shuffle(fp_rest_failed) From 9e1e31681d4a31ea595565eeda0e7f4a6342a0c0 Mon Sep 17 00:00:00 2001 From: felix5572 Date: Sun, 6 Oct 2019 14:02:19 +0000 Subject: [PATCH 10/93] AWS support restrat --- dpgen/dispatcher/AWS.py | 63 +++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/dpgen/dispatcher/AWS.py b/dpgen/dispatcher/AWS.py index d983efce1..c7d774e67 100644 --- a/dpgen/dispatcher/AWS.py +++ b/dpgen/dispatcher/AWS.py @@ -17,8 +17,20 @@ class AWS(Batch): _jobQueue = "" _query_next_allow_time = datetime.now().timestamp() + @staticmethod + def map_aws_status_to_dpgen_status(aws_status): + map_dict = {'SUBMITTED': JobStatus.waiting, + 'PENDING': JobStatus.waiting, + 'RUNNABLE': JobStatus.waiting, + 'STARTING': JobStatus.waiting, + 'RUNNING': JobStatus.running, + 'SUCCEEDED': JobStatus.finished, + 'FAILED': JobStatus.terminated, + 'UNKNOWN': JobStatus.unknown} + return map_dict.get(aws_status, JobStatus.unknown) + @classmethod - def AWS_check_status(cls, caller_instance=None): + def AWS_check_status(cls, job_id=""): """ to aviod query jobStatus too often, set a time interval query_dict example: @@ -26,38 +38,43 @@ def AWS_check_status(cls, caller_instance=None): {'40fb24b2-d0ca-4443-8e3a-c0906ea03622': , '41bda50c-0a23-4372-806c-87d16a680d85': } - """ + query_dict ={} if datetime.now().timestamp() > cls._query_next_allow_time: cls._query_next_allow_time=datetime.now().timestamp()+cls._query_time_interval - query_dict ={} for status in ['SUBMITTED', 'PENDING', 'RUNNABLE', 'STARTING', 'RUNNING','SUCCEEDED', 'FAILED']: status_response = cls.batch.list_jobs(jobQueue=cls._jobQueue, jobStatus=status, maxResults=cls._query_max_results) status_list=status_response.get('jobSummaryList', []) for job_dict in status_list: - query_dict.update({job_dict['jobId']: job_dict['status']}) + query_dict.update({job_dict['jobId']: cls.map_aws_status_to_dpgen_status(job_dict['status'])}) for job in cls._job_id_map_status: - cls._job_id_map_status[job]= cls.map_aws_status_to_dpgen_status(query_dict.get(job, 'UNKNOWN')) + cls._job_id_map_status[job]=query_dict.get(job, JobStatus.unknown) dlog.debug('20000: _query: %s, _map: %s' %(query_dict, cls._job_id_map_status)) - if caller_instance: - return cls._job_id_map_status.get(caller_instance.job_id, JobStatus.unknown) + dlog.debug('62000:job_id:%s, _query: %s, _map: %s' %(job_id, query_dict, cls._job_id_map_status)) + if job_id: + return cls._job_id_map_status.get(job_id, query_dict.get(job_id,JobStatus.unknown)) + return cls._job_id_map_status - @staticmethod - def map_aws_status_to_dpgen_status(aws_status): - map_dict = {'SUBMITTED': JobStatus.waiting, - 'PENDING': JobStatus.waiting, - 'RUNNABLE': JobStatus.waiting, - 'STARTING': JobStatus.waiting, - 'RUNNING': JobStatus.running, - 'SUCCEEDED': JobStatus.finished, - 'FAILED': JobStatus.terminated, - 'UNKNOWN': JobStatus.unknown} - return map_dict.get(aws_status, JobStatus.unknown) - @property def job_id(self): + try: + self._job_id + except AttributeError: + if self.context.check_file_exists(self.job_id_name): + self._job_id = self.context.read_file(self.job_id_name) + response_list = self.__class__.batch.describe_jobs(jobs=[self._job_id]).get('jobs') + try: + response = response_list[0] + jobQueue = response['jobQueue'] + except IndexError: + pass + else: + self.job_id = (response, jobQueue) + return self._job_id + dlog.debug("50000, self._job_id:%s,_Queue:%s,_map:%s,"%(self._job_id, self.__class__._jobQueue, self.__class__._job_id_map_status )) + return "" return self._job_id @job_id.setter @@ -66,11 +83,12 @@ def job_id(self, values): self._job_id = response['jobId'] self._job_name = response['jobName'] self.__class__._jobQueue = jobQueue - self.__class__._job_id_map_status[self._job_id] = JobStatus.waiting + self.__class__._job_id_map_status[self._job_id] = self.map_aws_status_to_dpgen_status(response.get('status', 'SUBMITTED')) + self.context.write_file(self.job_id_name, self._job_id) dlog.debug("15000, _job_id:%s, _job_name:%s, _map:%s, _Queue:%s" % (self._job_id, self._job_name, self.__class__._job_id_map_status, self.__class__._jobQueue)) def check_status(self): - return self.__class__.AWS_check_status(caller_instance=self) + return self.__class__.AWS_check_status(job_id=self.job_id) def sub_script(self, job_dirs, cmd, args, res, outlog, errlog): """ @@ -100,7 +118,7 @@ def default_resources(self, res): res.setdefault('jobQueue', 'deepmd_m5_v1_7') return res - def submit(self, + def do_submit(self, job_dirs, cmd, args = None, @@ -119,6 +137,7 @@ def submit(self, home-ec2-user-Ag_init-run_gen-iter_000000-01_model_devi-task_000_000048 """ jobName = os.path.join(self.context.remote_root,job_dirs.pop())[1:].replace('/','-').replace('.','_') + jobName += ("_" + str(self.context.job_uuid)) response = self.__class__.batch.submit_job(jobName=jobName, jobQueue=res['jobQueue'], jobDefinition=res['jobDefinition'], From bc6a30043caec0652c09831a3bb829b6382d6db1 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 6 Oct 2019 23:24:55 +0800 Subject: [PATCH 11/93] provide run/report, which reports the number of labels for systems and thermodyanmic conditions --- dpgen/main.py | 17 +++- dpgen/tools/relabel.py | 11 +-- dpgen/tools/{stat_data.py => run_report.py} | 35 +++++--- setup.py | 3 +- tests/tools/context.py | 10 +++ tests/tools/run_report_test_output/param.json | 89 +++++++++++++++++++ tests/tools/test_run_report.py | 18 ++++ 7 files changed, 162 insertions(+), 21 deletions(-) rename dpgen/tools/{stat_data.py => run_report.py} (76%) create mode 100644 tests/tools/context.py create mode 100644 tests/tools/run_report_test_output/param.json create mode 100644 tests/tools/test_run_report.py diff --git a/dpgen/main.py b/dpgen/main.py index 370763a68..ae4f57250 100644 --- a/dpgen/main.py +++ b/dpgen/main.py @@ -11,6 +11,7 @@ from dpgen.data.surf import gen_init_surf from dpgen.auto_test.run import gen_test from dpgen.database.run import db_run +from dpgen.tools.run_report import run_report from dpgen import info, __version__, __date__ @@ -69,7 +70,7 @@ def main(): # run parser_run = subparsers.add_parser( "run", - help="Main process of Deep Generator.") + help="Main process of Deep Potential Generator.") parser_run.add_argument('PARAM', type=str, help="parameter file, json/yaml format") parser_run.add_argument('MACHINE', type=str, @@ -78,13 +79,25 @@ def main(): help="log debug info") parser_run.set_defaults(func=gen_run) + # run/report + parser_rr = subparsers.add_parser( + "run/report", + help="Report the systems and the thermodynamic conditions of the labeled frames.") + parser_rr.add_argument("JOB_DIR", type=str, + help="the directory of the DP-GEN job") + parser_rr.add_argument('-p',"--param", type=str, default = 'param.json', + help="the json file provides DP-GEN paramters, should be located in JOB_DIR") + parser_rr.add_argument('-v',"--verbose", action = 'store_true', + help="being loud") + parser_rr.set_defaults(func=run_report) + # test parser_test = subparsers.add_parser("test", help="Auto-test for Deep Potential.") parser_test.add_argument('PARAM', type=str, help="parameter file, json/yaml format") parser_test.add_argument('MACHINE', type=str, help="machine file, json/yaml format") - parser_test.set_defaults(func=gen_test) + parser_test.set_defaults(func=gen_test) # db parser_db = subparsers.add_parser( diff --git a/dpgen/tools/relabel.py b/dpgen/tools/relabel.py index fd8fdd192..5aa1ea8df 100755 --- a/dpgen/tools/relabel.py +++ b/dpgen/tools/relabel.py @@ -4,14 +4,15 @@ import numpy as np import subprocess as sp sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')) -from lib.pwscf import make_pwscf_input -from lib.siesta import make_siesta_input -from lib.vasp import make_vasp_incar -from lib.vasp import system_from_poscar +from dpgen.generator.lib.pwscf import make_pwscf_input +from dpgen.generator.lib.siesta import make_siesta_input +from dpgen.generator.lib.vasp import make_vasp_incar +from dpgen.generator.lib.vasp import system_from_poscar import dpdata def get_lmp_info(input_file) : - lines = [line.rstrip('\n') for line in open(input_file)] + with open(input_file) as fp: + lines = [line.rstrip('\n') for line in fp] for ii in lines : words = ii.split() if len(words) >= 4 and words[0] == 'variable' : diff --git a/dpgen/tools/stat_data.py b/dpgen/tools/run_report.py similarity index 76% rename from dpgen/tools/stat_data.py rename to dpgen/tools/run_report.py index c69b13b04..4cded779b 100755 --- a/dpgen/tools/stat_data.py +++ b/dpgen/tools/run_report.py @@ -4,7 +4,7 @@ import numpy as np import subprocess as sp sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')) -from relabel import get_lmp_info +from dpgen.tools.relabel import get_lmp_info def ascii_hist(count) : np = (count-1) // 5 + 1 @@ -13,10 +13,13 @@ def ascii_hist(count) : ret += '=' return ret -def stat_tasks(target_folder, param_file, verbose = True) : +def stat_tasks(target_folder, + param_file = 'param.json', + verbose = True, + mute = False) : target_folder = os.path.abspath(target_folder) - tool_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'template') - jdata = json.load(open(os.path.join(target_folder, param_file))) + with open(os.path.join(target_folder, param_file)) as fp: + jdata = json.load(fp) # goto input cwd = os.getcwd() os.chdir(target_folder) @@ -37,7 +40,7 @@ def stat_tasks(target_folder, param_file, verbose = True) : for jj in iter_tasks : sys_idx = int(os.path.basename(jj).split('.')[-2]) sys_tasks_count[sys_idx] += 1 - linked_file = os.path.realpath(os.path.join(jj, 'conf.lmp')) + linked_file = os.path.realpath(os.path.join(jj, 'conf.dump')) linked_keys = linked_file.split('/') task_record = linked_keys[-5] + '.' + linked_keys[-3] + '.' + linked_keys[-1].split('.')[0] task_record_keys = task_record.split('.') @@ -65,26 +68,32 @@ def stat_tasks(target_folder, param_file, verbose = True) : str_blk += " " trait_fmt = str_blk + 'ens: %s T: %10.2f P: %12.2f count: %6d' for ii in range(numb_sys): - print(sys_fmt % (str(sys[ii]), sys_tasks_count[ii])) + if not mute: + print(sys_fmt % (str(sys[ii]), sys_tasks_count[ii])) for jj in range(len(sys_tasks_all[ii])): hist_str = ascii_hist(sys_tasks_all[ii][jj][3]) - print((trait_fmt + hist_str) % (sys_tasks_all[ii][jj][0], - sys_tasks_all[ii][jj][1], - sys_tasks_all[ii][jj][2], - sys_tasks_all[ii][jj][3])) - + if not mute: + print((trait_fmt + hist_str) % (sys_tasks_all[ii][jj][0], + sys_tasks_all[ii][jj][1], + sys_tasks_all[ii][jj][2], + sys_tasks_all[ii][jj][3])) + return sys, sys_tasks_count, sys_tasks_all + +def run_report(args): + stat_tasks(args.JOB_DIR, args.param, args.verbose) + def _main() : parser = argparse.ArgumentParser(description='Some data statistics of DP-GEN iterations') parser.add_argument("JOB_DIR", type=str, help="the directory of the DP-GEN job") - parser.add_argument('-p',"--parameter", type=str, default = 'param.json', + parser.add_argument('-p',"--param", type=str, default = 'param.json', help="the json file provides DP-GEN paramters, should be located in JOB_DIR") parser.add_argument('-v',"--verbose", action = 'store_true', help="being loud") args = parser.parse_args() - stat_tasks(args.JOB_DIR, args.parameter, args.verbose) + stat_tasks(args.JOB_DIR, args.param, args.verbose) if __name__ == '__main__': diff --git a/setup.py b/setup.py index 20496d7f5..8e1b8747b 100755 --- a/setup.py +++ b/setup.py @@ -39,7 +39,8 @@ 'dpgen/data/tools', 'dpgen/remote', 'dpgen/dispatcher', - 'dpgen/database' + 'dpgen/database', + 'dpgen/tools' ], # package_data={'example':['*.json']}, classifiers=[ diff --git a/tests/tools/context.py b/tests/tools/context.py new file mode 100644 index 000000000..d4e70a8c5 --- /dev/null +++ b/tests/tools/context.py @@ -0,0 +1,10 @@ +import sys,os + +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))) +from dpgen.tools.run_report import * + +def my_file_cmp(test, f0, f1): + with open(f0) as fp0 : + with open(f1) as fp1: + test.assertTrue(fp0.read() == fp1.read()) + diff --git a/tests/tools/run_report_test_output/param.json b/tests/tools/run_report_test_output/param.json new file mode 100644 index 000000000..202232382 --- /dev/null +++ b/tests/tools/run_report_test_output/param.json @@ -0,0 +1,89 @@ +{ + "type_map": ["Al", "Mg"], + "mass_map": [27, 24], + + "init_data_prefix": "/home/wanghan/study/deep.md/data/almgop.20/init//", + + "init_data_sys": [ + "al.fcc.01x01x01/02.md/sys-0004/deepmd", + "mg.fcc.01x01x01/02.md/sys-0004/deepmd" + ], + "init_batch_size": [1,1], + "sys_configs": [ + ["/home/wanghan/study/deep.md/data/almgop.20/init/al.fcc.02x02x02/01.scale_pert/sys-0032/scale-1.000/00000[0-4]/POSCAR"], + ["/home/wanghan/study/deep.md/data/almgop.20/init/mg.fcc.02x02x02/01.scale_pert/sys-0032/scale-1.000/00000[0-4]/POSCAR"] + ], + "sys_batch_size": [1,1], + + "_comment": " 00.train ", + "numb_models": 4, + "default_training_param" : { + "_comment": " model parameters", + "use_smooth": true, + "sel_a": [90, 90], + "rcut_smth": 2.00, + "rcut": 6.00, + "filter_neuron": [10, 20, 40], + "filter_resnet_dt": false, + "n_axis_neuron": 4, + "n_neuron": [120, 120, 120], + "resnet_dt": true, + "coord_norm": true, + "type_fitting_net": false, + + "_comment": " traing controls", + "systems": [], + "set_prefix": "set", + "stop_batch": 1000, + "batch_size": 1, + "start_lr": 0.001, + "decay_steps": 2000, + "decay_rate": 0.95, + "seed": 0, + + "start_pref_e": 0.02, + "limit_pref_e": 2, + "start_pref_f": 1000, + "limit_pref_f": 1, + "start_pref_v": 0.0, + "limit_pref_v": 0.0, + + "_comment": " display and restart", + "_comment": " frequencies counted in batch", + "disp_file": "lcurve.out", + "disp_freq": 1000, + "numb_test": 1, + "save_freq": 1000, + "save_ckpt": "model.ckpt", + "load_ckpt": "model.ckpt", + "disp_training": true, + "time_training": true, + "profiling": false, + "profiling_file": "timeline.json", + + "_comment": "that's all" + }, + + "_comment": " 01.model_devi ", + "_comment": "model_devi_skip: the first x of the recorded frames", + "model_devi_dt": 0.002, + "model_devi_skip": 0, + "model_devi_f_trust_lo": 0.05, + "model_devi_f_trust_hi": 0.20, + "model_devi_e_trust_lo": 1e10, + "model_devi_e_trust_hi": 1e10, + "model_devi_clean_traj": false, + "model_devi_jobs": [ + { "_idx": 0, "ensemble": "npt", "nsteps": 50, "press": [1.0,2.0], "sys_idx": [0, 1], "temps": [50,100], "trj_freq": 10 } + ], + "_comment": " 02.fp ", + "fp_style": "vasp", + "shuffle_poscar": false, + "fp_task_max": 8, + "fp_task_min": 2, + "fp_pp_path": "/home/wanghan/study/deep.md/dpgen/almg/vasp", + "fp_pp_files": ["POTCAR.Al", "POTCAR.Mg"], + "fp_incar": "/home/wanghan/study/deep.md/dpgen/almg/vasp/INCAR", + "_comment": " that's all " +} + diff --git a/tests/tools/test_run_report.py b/tests/tools/test_run_report.py new file mode 100644 index 000000000..825b9bb6e --- /dev/null +++ b/tests/tools/test_run_report.py @@ -0,0 +1,18 @@ +import os,sys,json +import unittest + +test_dir = os.path.abspath(os.path.join(os.path.dirname(__file__))) +sys.path.insert(0, os.path.join(test_dir, '..')) +__package__ = 'tools' +from .context import stat_tasks + +class TestRunReport(unittest.TestCase): + def test (self): + folder = 'run_report_test_output' + sys, sys_count, sys_all = stat_tasks(folder, verbose = False, mute = True) + with open(os.path.join(test_dir, folder, 'param.json')) as fp: + jdata = json.load(fp) + self.assertEqual(sys, jdata['sys_configs']) + self.assertEqual(sys_count, [jdata['fp_task_max'], jdata['fp_task_max']]) + ref_all = [[['npt', 50.0, 1.0, 4], ['npt', 50.0, 2.0, 1], ['npt', 100.0, 1.0, 2], ['npt', 100.0, 2.0, 1]], [['npt', 50.0, 1.0, 2], ['npt', 50.0, 2.0, 4], ['npt', 100.0, 1.0, 2]]] + self.assertEqual(sys_all, ref_all) From dd05827738d8140a79db6d69f2a58045b6380324 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 6 Oct 2019 23:25:48 +0800 Subject: [PATCH 12/93] update .gitignores --- .gitignore | 1 + dpgen/.gitignore | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 dpgen/.gitignore diff --git a/.gitignore b/.gitignore index 5ed154bc1..a2dff0063 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,4 @@ dpgen.egg-info */__pycache__ *.swp .eggs +.coverage diff --git a/dpgen/.gitignore b/dpgen/.gitignore new file mode 100644 index 000000000..cca703c23 --- /dev/null +++ b/dpgen/.gitignore @@ -0,0 +1,2 @@ +_date.py +_version.py From 109487d7c830dcddaca7b3cb4923a9f3cb5f5951 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 7 Oct 2019 00:17:04 +0800 Subject: [PATCH 13/93] fix bug in unittest for tools --- tests/tools/__init__.py | 0 .../task.000.000000/input.lammps | 31 +++++++++++++++++++ .../task.000.000001/input.lammps | 31 +++++++++++++++++++ .../task.000.000002/input.lammps | 31 +++++++++++++++++++ .../task.000.000003/input.lammps | 31 +++++++++++++++++++ .../task.000.000004/input.lammps | 31 +++++++++++++++++++ .../task.000.000005/input.lammps | 31 +++++++++++++++++++ .../task.000.000006/input.lammps | 31 +++++++++++++++++++ .../task.000.000007/input.lammps | 31 +++++++++++++++++++ .../task.000.000008/input.lammps | 31 +++++++++++++++++++ .../task.000.000009/input.lammps | 31 +++++++++++++++++++ .../task.000.000010/input.lammps | 31 +++++++++++++++++++ .../task.000.000011/input.lammps | 31 +++++++++++++++++++ .../task.000.000012/input.lammps | 31 +++++++++++++++++++ .../task.000.000013/input.lammps | 31 +++++++++++++++++++ .../task.000.000014/input.lammps | 31 +++++++++++++++++++ .../task.000.000015/input.lammps | 31 +++++++++++++++++++ .../task.000.000016/input.lammps | 31 +++++++++++++++++++ .../task.000.000017/input.lammps | 31 +++++++++++++++++++ .../task.000.000018/input.lammps | 31 +++++++++++++++++++ .../task.000.000019/input.lammps | 31 +++++++++++++++++++ .../task.001.000000/input.lammps | 31 +++++++++++++++++++ .../task.001.000001/input.lammps | 31 +++++++++++++++++++ .../task.001.000002/input.lammps | 31 +++++++++++++++++++ .../task.001.000003/input.lammps | 31 +++++++++++++++++++ .../task.001.000004/input.lammps | 31 +++++++++++++++++++ .../task.001.000005/input.lammps | 31 +++++++++++++++++++ .../task.001.000006/input.lammps | 31 +++++++++++++++++++ .../task.001.000007/input.lammps | 31 +++++++++++++++++++ .../task.001.000008/input.lammps | 31 +++++++++++++++++++ .../task.001.000009/input.lammps | 31 +++++++++++++++++++ .../task.001.000010/input.lammps | 31 +++++++++++++++++++ .../task.001.000011/input.lammps | 31 +++++++++++++++++++ .../task.001.000012/input.lammps | 31 +++++++++++++++++++ .../task.001.000013/input.lammps | 31 +++++++++++++++++++ .../task.001.000014/input.lammps | 31 +++++++++++++++++++ .../task.001.000015/input.lammps | 31 +++++++++++++++++++ .../task.001.000016/input.lammps | 31 +++++++++++++++++++ .../task.001.000017/input.lammps | 31 +++++++++++++++++++ .../task.001.000018/input.lammps | 31 +++++++++++++++++++ .../task.001.000019/input.lammps | 31 +++++++++++++++++++ .../02.fp/task.000.000000/conf.dump | 1 + .../02.fp/task.000.000001/conf.dump | 1 + .../02.fp/task.000.000002/conf.dump | 1 + .../02.fp/task.000.000003/conf.dump | 1 + .../02.fp/task.000.000004/conf.dump | 1 + .../02.fp/task.000.000005/conf.dump | 1 + .../02.fp/task.000.000006/conf.dump | 1 + .../02.fp/task.000.000007/conf.dump | 1 + .../02.fp/task.001.000000/conf.dump | 1 + .../02.fp/task.001.000001/conf.dump | 1 + .../02.fp/task.001.000002/conf.dump | 1 + .../02.fp/task.001.000003/conf.dump | 1 + .../02.fp/task.001.000004/conf.dump | 1 + .../02.fp/task.001.000005/conf.dump | 1 + .../02.fp/task.001.000006/conf.dump | 1 + .../02.fp/task.001.000007/conf.dump | 1 + tests/tools/test_run_report.py | 2 +- 58 files changed, 1257 insertions(+), 1 deletion(-) create mode 100644 tests/tools/__init__.py create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000000/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000001/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000002/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000003/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000004/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000005/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000006/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000007/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000008/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000009/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000010/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000011/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000012/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000013/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000014/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000015/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000016/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000017/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000018/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000019/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000000/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000001/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000002/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000003/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000004/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000005/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000006/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000007/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000008/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000009/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000010/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000011/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000012/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000013/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000014/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000015/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000016/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000017/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000018/input.lammps create mode 100644 tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000019/input.lammps create mode 120000 tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000000/conf.dump create mode 120000 tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000001/conf.dump create mode 120000 tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000002/conf.dump create mode 120000 tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000003/conf.dump create mode 120000 tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000004/conf.dump create mode 120000 tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000005/conf.dump create mode 120000 tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000006/conf.dump create mode 120000 tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000007/conf.dump create mode 120000 tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000000/conf.dump create mode 120000 tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000001/conf.dump create mode 120000 tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000002/conf.dump create mode 120000 tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000003/conf.dump create mode 120000 tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000004/conf.dump create mode 120000 tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000005/conf.dump create mode 120000 tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000006/conf.dump create mode 120000 tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000007/conf.dump diff --git a/tests/tools/__init__.py b/tests/tools/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000000/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000000/input.lammps new file mode 100644 index 000000000..467435d8a --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000000/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 40913 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000001/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000001/input.lammps new file mode 100644 index 000000000..33a064d41 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000001/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 848424 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000002/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000002/input.lammps new file mode 100644 index 000000000..69b683f85 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000002/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 357198 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000003/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000003/input.lammps new file mode 100644 index 000000000..4531a98fa --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000003/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 747362 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000004/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000004/input.lammps new file mode 100644 index 000000000..61c3be01b --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000004/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 499638 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000005/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000005/input.lammps new file mode 100644 index 000000000..76626314c --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000005/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 869864 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000006/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000006/input.lammps new file mode 100644 index 000000000..59ca011f0 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000006/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 701845 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000007/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000007/input.lammps new file mode 100644 index 000000000..f8b7a3826 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000007/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 76887 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000008/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000008/input.lammps new file mode 100644 index 000000000..42ecd5b0f --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000008/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 70061 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000009/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000009/input.lammps new file mode 100644 index 000000000..637e62791 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000009/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 96680 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000010/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000010/input.lammps new file mode 100644 index 000000000..d4c54614e --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000010/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 96737 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000011/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000011/input.lammps new file mode 100644 index 000000000..33ca90a00 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000011/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 641044 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000012/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000012/input.lammps new file mode 100644 index 000000000..68530feda --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000012/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 224550 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000013/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000013/input.lammps new file mode 100644 index 000000000..94b1a9896 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000013/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 566339 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000014/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000014/input.lammps new file mode 100644 index 000000000..c0d503a5f --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000014/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 48117 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000015/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000015/input.lammps new file mode 100644 index 000000000..687e96b5a --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000015/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 824400 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000016/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000016/input.lammps new file mode 100644 index 000000000..2f07135ca --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000016/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 96860 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000017/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000017/input.lammps new file mode 100644 index 000000000..f03904b8c --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000017/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 523691 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000018/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000018/input.lammps new file mode 100644 index 000000000..213735fc6 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000018/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 305757 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000019/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000019/input.lammps new file mode 100644 index 000000000..d3dabf58f --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.000.000019/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 860842 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000000/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000000/input.lammps new file mode 100644 index 000000000..0216e3be8 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000000/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 295802 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000001/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000001/input.lammps new file mode 100644 index 000000000..077465731 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000001/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 681000 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000002/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000002/input.lammps new file mode 100644 index 000000000..cc4e86638 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000002/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 618462 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000003/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000003/input.lammps new file mode 100644 index 000000000..49c0480c8 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000003/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 126966 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000004/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000004/input.lammps new file mode 100644 index 000000000..3feb07f3a --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000004/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 13923 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000005/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000005/input.lammps new file mode 100644 index 000000000..69b1941b8 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000005/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 210218 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000006/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000006/input.lammps new file mode 100644 index 000000000..113e45a9c --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000006/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 424518 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000007/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000007/input.lammps new file mode 100644 index 000000000..bd32fb144 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000007/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 136621 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000008/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000008/input.lammps new file mode 100644 index 000000000..27462a413 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000008/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 312495 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000009/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000009/input.lammps new file mode 100644 index 000000000..44467a3d8 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000009/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 590507 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000010/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000010/input.lammps new file mode 100644 index 000000000..28e996e94 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000010/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 664121 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000011/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000011/input.lammps new file mode 100644 index 000000000..3cb5397c8 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000011/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 810736 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000012/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000012/input.lammps new file mode 100644 index 000000000..68d16e6e1 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000012/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 382423 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000013/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000013/input.lammps new file mode 100644 index 000000000..f58d3b132 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000013/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 216872 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000014/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000014/input.lammps new file mode 100644 index 000000000..138fc70d0 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000014/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 216100 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000015/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000015/input.lammps new file mode 100644 index 000000000..a9d01bc15 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000015/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 379255 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000016/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000016/input.lammps new file mode 100644 index 000000000..f179a813e --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000016/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 13909 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000017/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000017/input.lammps new file mode 100644 index 000000000..3da736377 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000017/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 50.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 207854 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000018/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000018/input.lammps new file mode 100644 index 000000000..ef139ef13 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000018/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 1.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 163957 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000019/input.lammps b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000019/input.lammps new file mode 100644 index 000000000..d79b17d4e --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/01.model_devi/task.001.000019/input.lammps @@ -0,0 +1,31 @@ +variable NSTEPS equal 50 +variable THERMO_FREQ equal 10 +variable DUMP_FREQ equal 10 +variable TEMP equal 100.000000 +variable PRES equal 2.000000 +variable TAU_T equal 0.100000 +variable TAU_P equal 0.500000 + +units metal +boundary p p p +atom_style atomic + +neighbor 1.0 bin + +box tilt large +read_data conf.lmp +change_box all triclinic +mass 1 27.000000 +mass 2 24.000000 +pair_style deepmd ../graph.003.pb ../graph.001.pb ../graph.002.pb ../graph.000.pb ${THERMO_FREQ} model_devi.out +pair_coeff + +thermo_style custom step temp pe ke etotal press vol lx ly lz xy xz yz +thermo ${THERMO_FREQ} +dump 1 all custom ${DUMP_FREQ} traj/*.lammpstrj id type x y z + +velocity all create ${TEMP} 435064 +fix 1 all npt temp ${TEMP} ${TEMP} ${TAU_T} iso ${PRES} ${PRES} ${TAU_P} + +timestep 0.002000 +run ${NSTEPS} diff --git a/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000000/conf.dump b/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000000/conf.dump new file mode 120000 index 000000000..cd2517412 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000000/conf.dump @@ -0,0 +1 @@ +../../01.model_devi/task.000.000017/traj/20.lammpstrj \ No newline at end of file diff --git a/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000001/conf.dump b/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000001/conf.dump new file mode 120000 index 000000000..d7bfc06f9 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000001/conf.dump @@ -0,0 +1 @@ +../../01.model_devi/task.000.000004/traj/40.lammpstrj \ No newline at end of file diff --git a/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000002/conf.dump b/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000002/conf.dump new file mode 120000 index 000000000..c1ace91e3 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000002/conf.dump @@ -0,0 +1 @@ +../../01.model_devi/task.000.000016/traj/50.lammpstrj \ No newline at end of file diff --git a/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000003/conf.dump b/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000003/conf.dump new file mode 120000 index 000000000..827ae12bd --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000003/conf.dump @@ -0,0 +1 @@ +../../01.model_devi/task.000.000006/traj/30.lammpstrj \ No newline at end of file diff --git a/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000004/conf.dump b/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000004/conf.dump new file mode 120000 index 000000000..873f93196 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000004/conf.dump @@ -0,0 +1 @@ +../../01.model_devi/task.000.000012/traj/10.lammpstrj \ No newline at end of file diff --git a/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000005/conf.dump b/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000005/conf.dump new file mode 120000 index 000000000..da0b0c8a4 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000005/conf.dump @@ -0,0 +1 @@ +../../01.model_devi/task.000.000019/traj/40.lammpstrj \ No newline at end of file diff --git a/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000006/conf.dump b/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000006/conf.dump new file mode 120000 index 000000000..2c17c22e3 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000006/conf.dump @@ -0,0 +1 @@ +../../01.model_devi/task.000.000012/traj/30.lammpstrj \ No newline at end of file diff --git a/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000007/conf.dump b/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000007/conf.dump new file mode 120000 index 000000000..bce18ca1a --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/02.fp/task.000.000007/conf.dump @@ -0,0 +1 @@ +../../01.model_devi/task.000.000014/traj/20.lammpstrj \ No newline at end of file diff --git a/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000000/conf.dump b/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000000/conf.dump new file mode 120000 index 000000000..a201d8f23 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000000/conf.dump @@ -0,0 +1 @@ +../../01.model_devi/task.001.000005/traj/20.lammpstrj \ No newline at end of file diff --git a/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000001/conf.dump b/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000001/conf.dump new file mode 120000 index 000000000..c68381e29 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000001/conf.dump @@ -0,0 +1 @@ +../../01.model_devi/task.001.000001/traj/50.lammpstrj \ No newline at end of file diff --git a/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000002/conf.dump b/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000002/conf.dump new file mode 120000 index 000000000..b6a98bf8c --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000002/conf.dump @@ -0,0 +1 @@ +../../01.model_devi/task.001.000017/traj/10.lammpstrj \ No newline at end of file diff --git a/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000003/conf.dump b/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000003/conf.dump new file mode 120000 index 000000000..10d8ccd66 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000003/conf.dump @@ -0,0 +1 @@ +../../01.model_devi/task.001.000010/traj/20.lammpstrj \ No newline at end of file diff --git a/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000004/conf.dump b/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000004/conf.dump new file mode 120000 index 000000000..c916269b3 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000004/conf.dump @@ -0,0 +1 @@ +../../01.model_devi/task.001.000001/traj/40.lammpstrj \ No newline at end of file diff --git a/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000005/conf.dump b/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000005/conf.dump new file mode 120000 index 000000000..32cd32d07 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000005/conf.dump @@ -0,0 +1 @@ +../../01.model_devi/task.001.000000/traj/30.lammpstrj \ No newline at end of file diff --git a/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000006/conf.dump b/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000006/conf.dump new file mode 120000 index 000000000..d3bf7c777 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000006/conf.dump @@ -0,0 +1 @@ +../../01.model_devi/task.001.000012/traj/50.lammpstrj \ No newline at end of file diff --git a/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000007/conf.dump b/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000007/conf.dump new file mode 120000 index 000000000..71b3526f0 --- /dev/null +++ b/tests/tools/run_report_test_output/iter.000000/02.fp/task.001.000007/conf.dump @@ -0,0 +1 @@ +../../01.model_devi/task.001.000010/traj/10.lammpstrj \ No newline at end of file diff --git a/tests/tools/test_run_report.py b/tests/tools/test_run_report.py index 825b9bb6e..b19b89b36 100644 --- a/tests/tools/test_run_report.py +++ b/tests/tools/test_run_report.py @@ -9,7 +9,7 @@ class TestRunReport(unittest.TestCase): def test (self): folder = 'run_report_test_output' - sys, sys_count, sys_all = stat_tasks(folder, verbose = False, mute = True) + sys, sys_count, sys_all = stat_tasks(os.path.join(test_dir,folder), verbose = False, mute = True) with open(os.path.join(test_dir, folder, 'param.json')) as fp: jdata = json.load(fp) self.assertEqual(sys, jdata['sys_configs']) From 53bd4432f967d9ffcc15bad10baeb239b9f87f39 Mon Sep 17 00:00:00 2001 From: haidi Date: Mon, 7 Oct 2019 15:22:55 +0800 Subject: [PATCH 14/93] build surface by using ASE interface --- README.md | 4 ++-- dpgen/auto_test/__init__.py | 0 dpgen/auto_test/lib/__init__.py | 0 dpgen/data/surf.py | 25 +++++++++++++++++++------ dpgen/data/tools/__init__.py | 0 dpgen/data/tools/bcc.py | 2 +- dpgen/dispatcher/__init__.py | 0 dpgen/main.py | 4 ++-- tests/data/surf-100.POSCAR | 32 +++++++++++++++++++------------- tests/data/surf.json | 2 +- 10 files changed, 44 insertions(+), 25 deletions(-) create mode 100644 dpgen/auto_test/__init__.py create mode 100644 dpgen/auto_test/lib/__init__.py create mode 100644 dpgen/data/tools/__init__.py create mode 100644 dpgen/dispatcher/__init__.py diff --git a/README.md b/README.md index efe8a0bfe..da2fe8427 100644 --- a/README.md +++ b/README.md @@ -199,7 +199,7 @@ Following is an example for `PARAM`, which generates data from a typical structu 2, 2 ], - "z_min": 9, + "layer_numb": 3, "vacuum_max": 9, "vacuum_resol": [ 0.5, @@ -251,7 +251,7 @@ The bold notation of key (such as **Elements**) means that it's a necessary key. | **Elements** | List of String | ["Mg"] | Atom types | **cell_type** | String | "hcp" | Specifying which typical structure to be generated. **Options** include fcc, hcp, bcc, sc, diamond. | **latt** | Float | 4.479 | Lattice constant for single cell. -| **z_min** | Float | 9 | Thickness of slab (Angstrom). +| **layer_numb** | Integer | 3 | Number of equavilent layers of slab. | **vacuum_max** | Float | 9 | Maximal thickness of vacuum (Angstrom). | **vacuum_resol** | List of float | [0.5, 1 ] | Interval of thichness of vacuum. If size of `vacuum_resol` is 1, the interval is fixed to its value. If size of `vacuum_resol` is 2, the interval is `vacuum_resol[0]` before `mid_point`, otherwise `vacuum_resol[1]` after `mid_point`. | **millers** | List of list of Integer | [[1,0,0]] | Miller indices. diff --git a/dpgen/auto_test/__init__.py b/dpgen/auto_test/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/dpgen/auto_test/lib/__init__.py b/dpgen/auto_test/lib/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/dpgen/data/surf.py b/dpgen/data/surf.py index 641511a9b..81753df5e 100755 --- a/dpgen/data/surf.py +++ b/dpgen/data/surf.py @@ -15,6 +15,11 @@ from dpgen.remote.RemoteJob import SSHSession, JobStatus, SlurmJob, PBSJob, CloudMachineJob from pymatgen.core.surface import SlabGenerator,generate_all_slabs, Structure from pymatgen.io.vasp import Poscar +#-----ASE------- +from pymatgen.io.ase import AseAtomsAdaptor +from ase.io import read +from ase.build import general_surface + def create_path (path) : path += '/' @@ -195,10 +200,16 @@ def make_super_cell_pymatgen (jdata) : from_path = path_uc from_file = os.path.join(from_path, 'POSCAR.unit') ss = Structure.from_file(from_file) + # ase only support X type element + for i in range(len(ss)): + ss[i]='X' + ss=AseAtomsAdaptor.get_atoms(ss) + all_millers = jdata['millers'] path_sc = os.path.join(out_dir, global_dirname_02) - z_min = jdata['z_min'] + #z_min = jdata['z_min'] + layer_numb = jdata['layer_numb'] super_cell = jdata['super_cell'] cwd = os.getcwd() @@ -211,11 +222,13 @@ def make_super_cell_pymatgen (jdata) : miller_str += str(ii) path_cur_surf = create_path('surf-'+miller_str) os.chdir(path_cur_surf) - slabgen = SlabGenerator(ss, miller, z_min, 1e-3) - all_slabs = slabgen.get_slabs() + #slabgen = SlabGenerator(ss, miller, z_min, 1e-3) + slab=general_surface.surface(ss,indices=miller,vacuum=1e-3,layers=layer_numb) + #all_slabs = slabgen.get_slabs() dlog.info(os.getcwd()) - dlog.info("Miller %s: The slab has %s termination, use the first one" %(str(miller), len(all_slabs))) - all_slabs[0].to('POSCAR', 'POSCAR') + #dlog.info("Miller %s: The slab has %s termination, use the first one" %(str(miller), len(all_slabs))) + #all_slabs[0].to('POSCAR', 'POSCAR') + slab.write('POSCAR',vasp5=True) if super_cell[0] > 1 or super_cell[1] > 1 : st=Structure.from_file('POSCAR') st.make_supercell([super_cell[0], super_cell[1], 1]) @@ -408,7 +421,7 @@ def pert_scaled(jdata) : tail_elongs = np.arange(mid_point, vacuum_max, vacuum_resol[1]).tolist() elongs = np.unique(head_elongs+tail_elongs).tolist() else: - raise RuntimeError("the length of vacuum_resol must equal 2") + raise RuntimeError("the length of vacuum_resol must equal 1 or 2") else: vacuum_num = jdata['vacuum_numb'] diff --git a/dpgen/data/tools/__init__.py b/dpgen/data/tools/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/dpgen/data/tools/bcc.py b/dpgen/data/tools/bcc.py index 02b7d5d3a..e02483b32 100644 --- a/dpgen/data/tools/bcc.py +++ b/dpgen/data/tools/bcc.py @@ -9,7 +9,7 @@ def gen_box () : def poscar_unit (latt) : box = gen_box() ret = "" - ret += "FCC : a = %f \n" % latt + ret += "BCC : a = %f \n" % latt ret += "%.16f\n" % (latt) ret += "%.16f %.16f %.16f\n" % (box[0][0], box[0][1], box[0][2]) ret += "%.16f %.16f %.16f\n" % (box[1][0], box[1][1], box[1][2]) diff --git a/dpgen/dispatcher/__init__.py b/dpgen/dispatcher/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/dpgen/main.py b/dpgen/main.py index ae4f57250..f5b03a9b5 100644 --- a/dpgen/main.py +++ b/dpgen/main.py @@ -105,8 +105,8 @@ def main(): help="Collecting data from Deep Generator.") parser_db.add_argument('PATH', type=str, help="root path for dpgen modeling") - parser_db.add_argument('CALCULATOR', type=str, - help="calculator used for labeling: vasp/pwscf/gaussian") + parser_db.add_argument('ENGINE', type=str, + help="engine used for labeling: vasp/pwscf/cp2k/gaussian/siesta") parser_db.add_argument('OUTPUT', type=str, help="output filename : file.json/file.yaml") parser_db.add_argument("ID_PREFIX", type=str, default=None, diff --git a/tests/data/surf-100.POSCAR b/tests/data/surf-100.POSCAR index f9ee253b3..22073df90 100644 --- a/tests/data/surf-100.POSCAR +++ b/tests/data/surf-100.POSCAR @@ -1,14 +1,20 @@ -Type6 -1.0 -2.899138 0.000000 0.000000 -0.000000 2.899138 0.000000 -0.000000 0.000000 16.400000 + X + 1.0000000000000000 + 4.0999999999999996 0.0000000000000000 0.0000000000000000 + 0.0000000000000000 4.0999999999999996 0.0000000000000000 + 0.0000000000000000 0.0000000000000000 10.2520000000000007 Al -6 -direct -0.000000 0.000000 0.812500 Type0+ -0.000000 0.000000 0.312500 Type0+ -0.500000 0.500000 0.937500 Type0+ -0.000000 0.000000 0.562500 Type0+ -0.500000 0.500000 0.687500 Type0+ -0.500000 0.500000 0.437500 Type0+ +12 +Cartesian + 2.0499999999999998 2.0499999999999998 4.1010000000000000 + 0.0000000000000000 2.0499999999999998 6.1509999999999998 + 0.0000000000000000 0.0000000000000000 4.1010000000000000 + 0.0000000000000000 0.0000000000000000 8.2010000000000005 + 2.0499999999999998 2.0499999999999998 8.2010000000000005 + 2.0499999999999998 0.0000000000000000 10.2510000000000012 + 2.0499999999999998 0.0000000000000000 2.0510000000000002 + 0.0000000000000000 2.0499999999999998 10.2510000000000012 + 2.0499999999999998 0.0000000000000000 6.1509999999999998 + 2.0499999999999998 2.0499999999999998 0.0010000000000003 + 0.0000000000000000 2.0499999999999998 2.0510000000000002 + 0.0000000000000000 0.0000000000000000 0.0010000000000003 diff --git a/tests/data/surf.json b/tests/data/surf.json index 1f22f2bab..63c7bc418 100644 --- a/tests/data/surf.json +++ b/tests/data/surf.json @@ -10,7 +10,7 @@ 1, 1 ], - "z_min": 9, + "layer_numb": 3, "vacuum_max": 9, "vacuum_resol": [ 0.5, From e374f42f8414e57fa8f83fcd65e9d908ba43dcca Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Tue, 8 Oct 2019 22:43:00 -0400 Subject: [PATCH 15/93] bugfix --- dpgen/generator/lib/gaussian.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpgen/generator/lib/gaussian.py b/dpgen/generator/lib/gaussian.py index 9ac89610e..e8ec40a5b 100644 --- a/dpgen/generator/lib/gaussian.py +++ b/dpgen/generator/lib/gaussian.py @@ -21,8 +21,8 @@ def _crd2frag(symbols, crds, pbc=False, cell=None, return_bonds=False): atomnumber = len(symbols) + all_atoms = Atoms(symbols = symbols, positions = crds, pbc=pbc, cell=cell) if pbc: - all_atoms = Atoms(symbols = symbols, positions = crds, pbc=True, cell=cell) repeated_atoms = all_atoms.repeat(2)[atomnumber:] tree = cKDTree(crds) d = tree.query(repeated_atoms.get_positions(), k=1)[0] From c3bf692c2ea52a7e084bd4c986e6aae29b3b59fb Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 9 Oct 2019 20:47:27 +0800 Subject: [PATCH 16/93] cleanup the generator/lib/vasp --- dpgen/generator/lib/vasp.py | 109 ------------------------------------ 1 file changed, 109 deletions(-) diff --git a/dpgen/generator/lib/vasp.py b/dpgen/generator/lib/vasp.py index 7c22cf4e3..ebd87fc75 100644 --- a/dpgen/generator/lib/vasp.py +++ b/dpgen/generator/lib/vasp.py @@ -3,76 +3,6 @@ import os import numpy as np -def system_from_poscar(poscar) : - lines = open(poscar, 'r').read().split('\n') - system = {} - system['atom_names'] = [str(ii) for ii in lines[5].split()] - system['atom_numbs'] = [int(ii) for ii in lines[6].split()] - scale = float(lines[1]) - cell = [] - for ii in range(2,5) : - boxv = [float(jj) for jj in lines[ii].split()] - boxv = np.array(boxv) * scale - cell.append(boxv) - system['cell'] = np.array(cell) - natoms = sum(system['atom_numbs']) - coord = [] - for ii in range(8, 8+natoms) : - tmpv = [float(jj) for jj in lines[ii].split()] - tmpv = np.array(tmpv) * scale - coord.append(tmpv) - system['coordinates'] = np.array(coord) - return system - -def make_vasp_kpoints (kpoints) : - ret = "" - ret += "Automatic mesh\n" - ret += "0\n" - ret += "Gamma\n" - ret += "%d %d %d\n" % (kpoints[0], kpoints[1], kpoints[2]) - ret += "0 0 0\n" - return ret - -def _make_vasp_incar (ecut, ediff, npar, kpar, - kspacing = 0.5, kgamma = True, - smearing = None, sigma = None, - metagga = None) : - ret = '' - ret += 'PREC=A\n' - ret += 'ENCUT=%d\n' % ecut - ret += 'ISYM=0\n' - ret += 'ALGO=fast\n' - ret += 'EDIFF=%e\n' % ediff - ret += 'LREAL=A\n' - ret += 'NPAR=%d\n' % npar - ret += 'KPAR=%d\n' % kpar - ret += "\n" - ret += 'NELMIN=4\n' - ret += 'ISIF=2\n' - if smearing is not None : - ret += 'ISMEAR=%d\n' % smearing - if sigma is not None : - ret += 'SIGMA=%f\n' % sigma - ret += 'IBRION=-1\n' - ret += "\n" - ret += 'NSW=0\n' - ret += "\n" - ret += 'LWAVE=F\n' - ret += 'LCHARG=F\n' - ret += 'PSTRESS=0\n' - ret += "\n" - ret += 'KSPACING=%f\n' % kspacing - if kgamma: - ret += 'KGAMMA=.TRUE.\n' - else : - ret += 'KGAMMA=.FALSE.\n' - if metagga is not None : - ret += '\n' - ret += 'LASPH=T\n' - ret += 'METAGGA=%s\n' % metagga - return ret - - def _make_vasp_incar_dict (ecut, ediff, npar, kpar, kspacing = 0.5, kgamma = True, smearing = None, sigma = None, @@ -107,7 +37,6 @@ def _make_vasp_incar_dict (ecut, ediff, npar, kpar, incar_dict['METAGGA'] = metagga return incar_dict - def _update_incar_dict(incar_dict_, user_dict) : if user_dict is None: return incar_dict_ @@ -162,21 +91,6 @@ def _make_metagga(fp_params) : elif metagga not in [None,'SCAN', 'TPSS', 'RTPSS', 'M06L', 'MBJ'] : raise RuntimeError ("unknown metagga method " + metagga) return metagga - -def make_vasp_incar(fp_params) : - ecut = fp_params['ecut'] - ediff = fp_params['ediff'] - npar = fp_params['npar'] - kpar = fp_params['kpar'] - kspacing = fp_params['kspacing'] - smearing, sigma = _make_smearing(fp_params) - metagga = _make_metagga(fp_params) - incar = _make_vasp_incar(ecut, ediff, npar, kpar, - kspacing = kspacing, kgamma = False, - smearing = smearing, sigma = sigma, - metagga = metagga - ) - return incar def make_vasp_incar_user_dict(fp_params) : ecut = fp_params['ecut'] @@ -199,26 +113,3 @@ def make_vasp_incar_user_dict(fp_params) : incar = write_incar_dict(incar_dict) return incar -def make_vasp_kpoints_gamma (kpoints) : - ret = '' - ret += 'Automatic mesh\n' - ret += '0\n' - ret += 'Gamma\n' - ret += '%d %d %d\n' % (kpoints[0], kpoints[1], kpoints[2]) - ret += '0 0 0\n' - return ret - -def make_vasp_kpoints (kpoints) : - return make_vasp_kpoints_gamma(kpoints) - - -if __name__ == '__main__' : - import json - jdata = json.load(open('param.json')) - incar_1 = make_vasp_incar(jdata['fp_params']) - incar_2 = make_vasp_incar_user_dict(jdata['fp_params']) - with open('tmp1.out', 'w') as fp: - fp.write(incar_1) - with open('tmp2.out', 'w') as fp: - fp.write(incar_2) - From 73947584faa858e4d1b58a38fac4508c5e9526f0 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 9 Oct 2019 20:51:46 +0800 Subject: [PATCH 17/93] add auto calculator for nbands. not extensively tested! --- dpgen/generator/lib/ele_temp.py | 92 +++++++++++++++++++ tests/generator/context.py | 1 + tests/generator/out_data_nbands_esti/POSCAR | 40 ++++++++ tests/generator/out_data_nbands_esti/POTCAR | 5 + .../generator/out_data_nbands_esti/POTCAR.dbl | 8 ++ .../out_data_nbands_esti/md.000300K/INCAR | 33 +++++++ .../out_data_nbands_esti/md.000300K/POSCAR | 1 + .../out_data_nbands_esti/md.001000K/INCAR | 33 +++++++ .../out_data_nbands_esti/md.001000K/POSCAR | 1 + .../out_data_nbands_esti/md.005000K/INCAR | 33 +++++++ .../out_data_nbands_esti/md.005000K/POSCAR | 1 + .../out_data_nbands_esti/md.010000K/INCAR | 35 +++++++ .../out_data_nbands_esti/md.010000K/POSCAR | 1 + .../out_data_nbands_esti/md.020000K/INCAR | 35 +++++++ .../out_data_nbands_esti/md.020000K/POSCAR | 1 + .../out_data_nbands_esti/md.040000K/INCAR | 36 ++++++++ .../out_data_nbands_esti/md.040000K/POSCAR | 1 + .../out_data_nbands_esti/md.080000K/INCAR | 36 ++++++++ .../out_data_nbands_esti/md.080000K/POSCAR | 1 + .../out_data_nbands_esti/md.160000K/INCAR | 36 ++++++++ .../out_data_nbands_esti/md.160000K/POSCAR | 1 + .../out_data_nbands_esti/md.240000K/INCAR | 36 ++++++++ .../out_data_nbands_esti/md.240000K/POSCAR | 1 + .../generator/out_data_nbands_esti/mgal/INCAR | 33 +++++++ .../out_data_nbands_esti/mgal/POSCAR | 40 ++++++++ tests/generator/test_nbands_esti.py | 75 +++++++++++++++ 26 files changed, 616 insertions(+) create mode 100644 dpgen/generator/lib/ele_temp.py create mode 100644 tests/generator/out_data_nbands_esti/POSCAR create mode 100644 tests/generator/out_data_nbands_esti/POTCAR create mode 100644 tests/generator/out_data_nbands_esti/POTCAR.dbl create mode 100644 tests/generator/out_data_nbands_esti/md.000300K/INCAR create mode 120000 tests/generator/out_data_nbands_esti/md.000300K/POSCAR create mode 100644 tests/generator/out_data_nbands_esti/md.001000K/INCAR create mode 120000 tests/generator/out_data_nbands_esti/md.001000K/POSCAR create mode 100644 tests/generator/out_data_nbands_esti/md.005000K/INCAR create mode 120000 tests/generator/out_data_nbands_esti/md.005000K/POSCAR create mode 100644 tests/generator/out_data_nbands_esti/md.010000K/INCAR create mode 120000 tests/generator/out_data_nbands_esti/md.010000K/POSCAR create mode 100644 tests/generator/out_data_nbands_esti/md.020000K/INCAR create mode 120000 tests/generator/out_data_nbands_esti/md.020000K/POSCAR create mode 100644 tests/generator/out_data_nbands_esti/md.040000K/INCAR create mode 120000 tests/generator/out_data_nbands_esti/md.040000K/POSCAR create mode 100644 tests/generator/out_data_nbands_esti/md.080000K/INCAR create mode 120000 tests/generator/out_data_nbands_esti/md.080000K/POSCAR create mode 100644 tests/generator/out_data_nbands_esti/md.160000K/INCAR create mode 120000 tests/generator/out_data_nbands_esti/md.160000K/POSCAR create mode 100644 tests/generator/out_data_nbands_esti/md.240000K/INCAR create mode 120000 tests/generator/out_data_nbands_esti/md.240000K/POSCAR create mode 100644 tests/generator/out_data_nbands_esti/mgal/INCAR create mode 100644 tests/generator/out_data_nbands_esti/mgal/POSCAR create mode 100644 tests/generator/test_nbands_esti.py diff --git a/dpgen/generator/lib/ele_temp.py b/dpgen/generator/lib/ele_temp.py new file mode 100644 index 000000000..90372e1a1 --- /dev/null +++ b/dpgen/generator/lib/ele_temp.py @@ -0,0 +1,92 @@ +import os,dpdata,json +import numpy as np +import scipy.constants as pc +from pymatgen.io.vasp.inputs import Incar + + +class NBandsEsti(object): + def __init__ (self, + test_list): + if type(test_list) is list: + ele_t = [] + vol = [] + d_nbd = [] + nbd = [] + for ii in test_list: + res = NBandsEsti._get_res(ii) + ele_t.append(res['ele_temp']) + vol.append(res['vol']) + d_nbd.append(NBandsEsti._get_default_nbands(res)) + nbd.append(res['nbands']) + ele_t = np.array(ele_t) + vol = np.array(vol) + d_nbd = np.array(d_nbd) + nbd = np.array(nbd) + alpha = (nbd - d_nbd) / vol / ele_t**1.5 + self.err = np.std(alpha) + self.pref = np.average(alpha) + # print(np.average(alpha), np.std(alpha), self.err/self.pref) + # print((ele_t), vol, d_nbd, nbd, alpha) + elif type(test_list) is str: + with open(test_list) as fp: + self.pref = float(fp.readline()) + self.err = float(fp.readline()) + else: + raise RuntimeError('unknown input type ' + type(test_list)) + + def save(self, fname): + with open(fname, 'w') as fp: + fp.write(str(self.pref) + '\n') + fp.write(str(self.err) + '\n') + + def predict(self, + target_dir, + tolerance = 0.5): + res = NBandsEsti._get_res(target_dir) + ele_t=(res['ele_temp']) + vol=(res['vol']) + d_nbd=(NBandsEsti._get_default_nbands(res)) + nbd=(res['nbands']) + esti = (self.pref + tolerance*self.err) * ele_t**1.5 * vol + d_nbd + return int(esti)+1 + + @classmethod + def _get_res(self, res_dir): + res = {} + sys = dpdata.System(os.path.join(res_dir, 'POSCAR')) + res['natoms'] = (sys['atom_numbs']) + res['vol'] = np.linalg.det(sys['cells'][0]) + res['nvalence'] = (self._get_potcar_nvalence(os.path.join(res_dir, 'POTCAR'))) + res['ele_temp'] = self._get_incar_ele_temp(os.path.join(res_dir, 'INCAR')) * pc.electron_volt / pc.Boltzmann + res['nbands'] = self._get_incar_nbands(os.path.join(res_dir, 'INCAR')) + return res + + @classmethod + def _get_default_nbands(self, res): + ret = 0 + for ii,jj in zip(res['natoms'], res['nvalence']): + ret += ii * jj // 2 + ii // 2 + 2 + return ret + + @classmethod + def _get_potcar_nvalence(self, fname): + with open(fname) as fp: + pot_str = fp.read().split('\n') + head_idx = [] + for idx,ii in enumerate(pot_str): + if ('PAW_' in ii) and ('TITEL' not in ii): + head_idx.append(idx) + res = [] + for ii in head_idx: + res.append(float(pot_str[ii+1])) + return res + + @classmethod + def _get_incar_ele_temp(self, fname): + incar = Incar.from_file(fname) + return incar['SIGMA'] + + @classmethod + def _get_incar_nbands(self, fname): + incar = Incar.from_file(fname) + return incar.get('NBANDS') diff --git a/tests/generator/context.py b/tests/generator/context.py index 9137dbdfe..7a4302212 100644 --- a/tests/generator/context.py +++ b/tests/generator/context.py @@ -3,6 +3,7 @@ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))) from dpgen.generator.run import * from dpgen.generator.lib.gaussian import detect_multiplicity +from dpgen.generator.lib.ele_temp import NBandsEsti param_file = 'param-mg-vasp.json' param_old_file = 'param-mg-vasp-old.json' diff --git a/tests/generator/out_data_nbands_esti/POSCAR b/tests/generator/out_data_nbands_esti/POSCAR new file mode 100644 index 000000000..7222f7ac2 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/POSCAR @@ -0,0 +1,40 @@ +POSCAR file written by OVITO +0.64 + 8.0852460528260064 0.0000000700556454 0.0000000165920926 + 0.0000000700459398 8.0852460812690730 -0.0000000878331783 + 0.0000000165994710 -0.0000000878293815 8.0852460822851544 + Al + 32 +Direct + 0.2500000074218809 -0.0000000006822529 0.2500000011219505 + 0.0000000017515228 0.4999999968593779 0.5000000121259237 + 0.0000000043319078 0.7499999907276940 0.7500000023288846 + 0.5000000030383994 0.5000000063795264 -0.0000000001750512 + 0.5000000069922398 0.2500000092556521 0.7499999925172053 + 0.7500000002384054 0.5000000058460430 0.2499999970004410 + 0.5000000100332991 0.2500000001020252 0.2500000061404412 + 0.7499999967294295 0.4999999938307768 0.7500000077731870 + -0.0000000102302524 0.2500000011729165 0.2500000007828680 + 0.2500000021034525 0.0000000026582450 0.7499999979035360 + 0.2500000064022705 0.7499999919020213 0.0000000019913002 + 0.5000000083231070 -0.0000000011197416 0.0000000014389411 + 0.2500000097291175 0.5000000129780301 0.2499999975347162 + 0.5000000055222689 0.0000000095334217 0.4999999965645718 + 0.5000000034529869 0.7499999969981677 0.2499999981901819 + 0.7499999985377536 0.7499999945443449 0.0000000074372283 + -0.0000000004748536 0.0000000005310409 0.0000000063786655 + 0.2499999999857682 0.5000000028441646 0.7500000018075699 + 0.0000000000448991 0.0000000048734801 0.5000000037789456 + 0.2500000115215270 0.2500000006209973 0.5000000113478330 + 0.7500000009516035 0.2500000011452493 0.5000000093672294 + 0.2500000006602736 0.2500000097862060 -0.0000000026740404 + -0.0000000040407868 0.7499999975356930 0.2499999972984601 + 0.7499999995103841 0.0000000012827216 0.2499999977659152 + -0.0000000041345229 0.2500000119032792 0.7499999956587747 + 0.2500000030261135 0.7499999944555688 0.5000000026313640 + 0.7499999954414514 0.2500000084865056 -0.0000000006412232 + 0.5000000035346804 0.7499999971754691 0.7500000063111742 + 0.7499999910768409 0.0000000040350684 0.7499999999698314 + -0.0000000013440370 0.5000000065441171 -0.0000000011351674 + 0.7499999970723630 0.7499999983979078 0.4999999968129619 + 0.5000000022954397 0.4999999989012168 0.5000000041503138 diff --git a/tests/generator/out_data_nbands_esti/POTCAR b/tests/generator/out_data_nbands_esti/POTCAR new file mode 100644 index 000000000..dfc902686 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/POTCAR @@ -0,0 +1,5 @@ + PAW_PBE Al 04Jan2001 + 3.00000000000000 + parameters from PSCTR are: + TITEL = PAW_PBE Al 04Jan2001 + End of Dataset diff --git a/tests/generator/out_data_nbands_esti/POTCAR.dbl b/tests/generator/out_data_nbands_esti/POTCAR.dbl new file mode 100644 index 000000000..23b637d85 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/POTCAR.dbl @@ -0,0 +1,8 @@ + PAW_PBE Mg_sv 12Apr2007 + 10.0000000000000 + TITEL = PAW_PBE Mg_sv 12Apr2007 + End of Dataset + PAW_PBE Al 04Jan2001 + 3.00000000000000 + TITEL = PAW_PBE Al 04Jan2001 + End of Dataset diff --git a/tests/generator/out_data_nbands_esti/md.000300K/INCAR b/tests/generator/out_data_nbands_esti/md.000300K/INCAR new file mode 100644 index 000000000..e22978528 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.000300K/INCAR @@ -0,0 +1,33 @@ +PREC=A +ENCUT=600 +ISYM=0 +SYMPREC=1e-10 +ALGO=fast +EDIFF=1E-4 +LREAL=A +NPAR=2 +KPAR=2 + +ISTART=0 +ICHARG=2 +ISIF=2 +ISMEAR=-1 +SIGMA=0.025851991011651636 +IBRION=0 +MAXMIX=50 +NBLOCK=1 +KBLOCK=100 + +SMASS=0 +POTIM=2 +TEBEG=300 +TEEND=300 + +NSW=2000 + +LWAVE=F +LCHARG=F +PSTRESS=0 + +KSPACING=0.32 +KGAMMA=F diff --git a/tests/generator/out_data_nbands_esti/md.000300K/POSCAR b/tests/generator/out_data_nbands_esti/md.000300K/POSCAR new file mode 120000 index 000000000..fbebe8cb9 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.000300K/POSCAR @@ -0,0 +1 @@ +../POSCAR \ No newline at end of file diff --git a/tests/generator/out_data_nbands_esti/md.001000K/INCAR b/tests/generator/out_data_nbands_esti/md.001000K/INCAR new file mode 100644 index 000000000..855659e1c --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.001000K/INCAR @@ -0,0 +1,33 @@ +PREC=A +ENCUT=600 +ISYM=0 +SYMPREC=1e-10 +ALGO=fast +EDIFF=1E-4 +LREAL=A +NPAR=2 +KPAR=2 + +ISTART=0 +ICHARG=2 +ISIF=2 +ISMEAR=-1 +SIGMA=0.08617330337217212 +IBRION=0 +MAXMIX=50 +NBLOCK=1 +KBLOCK=100 + +SMASS=0 +POTIM=2 +TEBEG=1000 +TEEND=1000 + +NSW=2000 + +LWAVE=F +LCHARG=F +PSTRESS=0 + +KSPACING=0.32 +KGAMMA=F diff --git a/tests/generator/out_data_nbands_esti/md.001000K/POSCAR b/tests/generator/out_data_nbands_esti/md.001000K/POSCAR new file mode 120000 index 000000000..fbebe8cb9 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.001000K/POSCAR @@ -0,0 +1 @@ +../POSCAR \ No newline at end of file diff --git a/tests/generator/out_data_nbands_esti/md.005000K/INCAR b/tests/generator/out_data_nbands_esti/md.005000K/INCAR new file mode 100644 index 000000000..b56714e4f --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.005000K/INCAR @@ -0,0 +1,33 @@ +PREC=A +ENCUT=600 +ISYM=0 +SYMPREC=1e-10 +ALGO=fast +EDIFF=1E-4 +LREAL=A +NPAR=2 +KPAR=2 + +ISTART=0 +ICHARG=2 +ISIF=2 +ISMEAR=-1 +SIGMA=0.43086651686086064 +IBRION=0 +MAXMIX=50 +NBLOCK=1 +KBLOCK=100 + +SMASS=0 +POTIM=2 +TEBEG=5000 +TEEND=5000 + +NSW=2000 + +LWAVE=F +LCHARG=F +PSTRESS=0 + +KSPACING=0.32 +KGAMMA=F diff --git a/tests/generator/out_data_nbands_esti/md.005000K/POSCAR b/tests/generator/out_data_nbands_esti/md.005000K/POSCAR new file mode 120000 index 000000000..fbebe8cb9 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.005000K/POSCAR @@ -0,0 +1 @@ +../POSCAR \ No newline at end of file diff --git a/tests/generator/out_data_nbands_esti/md.010000K/INCAR b/tests/generator/out_data_nbands_esti/md.010000K/INCAR new file mode 100644 index 000000000..814230bd0 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.010000K/INCAR @@ -0,0 +1,35 @@ +PREC=A +ENCUT=600 +ISYM=0 +SYMPREC=1e-10 +ALGO=fast +EDIFF=1E-4 +LREAL=A +NPAR=2 +KPAR=2 + +ISTART=0 +ICHARG=2 +ISIF=2 +ISMEAR=-1 +SIGMA=0.8617330337217213 +IBRION=0 +MAXMIX=50 +NBLOCK=1 +KBLOCK=100 + +SMASS=0 +POTIM=1 +TEBEG=10000 +TEEND=10000 + +NSW=4000 + +LWAVE=F +LCHARG=F +PSTRESS=0 + +KSPACING=0.32 +KGAMMA=F + +NBANDS=69 diff --git a/tests/generator/out_data_nbands_esti/md.010000K/POSCAR b/tests/generator/out_data_nbands_esti/md.010000K/POSCAR new file mode 120000 index 000000000..fbebe8cb9 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.010000K/POSCAR @@ -0,0 +1 @@ +../POSCAR \ No newline at end of file diff --git a/tests/generator/out_data_nbands_esti/md.020000K/INCAR b/tests/generator/out_data_nbands_esti/md.020000K/INCAR new file mode 100644 index 000000000..e6ae8f3e1 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.020000K/INCAR @@ -0,0 +1,35 @@ +PREC=A +ENCUT=600 +ISYM=0 +SYMPREC=1e-10 +ALGO=fast +EDIFF=1E-4 +LREAL=A +NPAR=2 +KPAR=2 + +ISTART=0 +ICHARG=2 +ISIF=2 +ISMEAR=-1 +SIGMA=1.7234660674434426 +IBRION=0 +MAXMIX=50 +NBLOCK=1 +KBLOCK=100 + +SMASS=0 +POTIM=1 +TEBEG=20000 +TEEND=20000 + +NSW=4000 + +LWAVE=F +LCHARG=F +PSTRESS=0 + +KSPACING=0.32 +KGAMMA=F + +NBANDS=81 diff --git a/tests/generator/out_data_nbands_esti/md.020000K/POSCAR b/tests/generator/out_data_nbands_esti/md.020000K/POSCAR new file mode 120000 index 000000000..fbebe8cb9 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.020000K/POSCAR @@ -0,0 +1 @@ +../POSCAR \ No newline at end of file diff --git a/tests/generator/out_data_nbands_esti/md.040000K/INCAR b/tests/generator/out_data_nbands_esti/md.040000K/INCAR new file mode 100644 index 000000000..d9eaaeee5 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.040000K/INCAR @@ -0,0 +1,36 @@ +PREC=A +ENCUT=600 +ISYM=0 +SYMPREC=1e-10 +ALGO=fast +EDIFF=1E-4 +LREAL=A +NPAR=2 +KPAR=2 + +ISTART=0 +ICHARG=2 +ISIF=2 +ISMEAR=-1 +SIGMA=3.446932134886885 +IBRION=0 +MAXMIX=50 +NBLOCK=1 +KBLOCK=100 + +SMASS=0 +POTIM=0.5 +TEBEG=40000 +TEEND=40000 + +NSW=8000 + +LWAVE=F +LCHARG=F +PSTRESS=0 + +KSPACING=0.32 +KGAMMA=F + +NBANDS=120 + diff --git a/tests/generator/out_data_nbands_esti/md.040000K/POSCAR b/tests/generator/out_data_nbands_esti/md.040000K/POSCAR new file mode 120000 index 000000000..fbebe8cb9 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.040000K/POSCAR @@ -0,0 +1 @@ +../POSCAR \ No newline at end of file diff --git a/tests/generator/out_data_nbands_esti/md.080000K/INCAR b/tests/generator/out_data_nbands_esti/md.080000K/INCAR new file mode 100644 index 000000000..e2fefc924 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.080000K/INCAR @@ -0,0 +1,36 @@ +PREC=A +ENCUT=600 +ISYM=0 +SYMPREC=1e-10 +ALGO=fast +EDIFF=1E-4 +LREAL=A +NPAR=2 +KPAR=2 + +ISTART=0 +ICHARG=2 +ISIF=2 +ISMEAR=-1 +SIGMA=6.89386426977377 +IBRION=0 +MAXMIX=50 +NBLOCK=1 +KBLOCK=100 + +SMASS=0 +POTIM=0.5 +TEBEG=80000 +TEEND=80000 + +NSW=8000 + +LWAVE=F +LCHARG=F +PSTRESS=0 + +KSPACING=0.32 +KGAMMA=F + +NBANDS=180 + diff --git a/tests/generator/out_data_nbands_esti/md.080000K/POSCAR b/tests/generator/out_data_nbands_esti/md.080000K/POSCAR new file mode 120000 index 000000000..fbebe8cb9 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.080000K/POSCAR @@ -0,0 +1 @@ +../POSCAR \ No newline at end of file diff --git a/tests/generator/out_data_nbands_esti/md.160000K/INCAR b/tests/generator/out_data_nbands_esti/md.160000K/INCAR new file mode 100644 index 000000000..bcf89cd9c --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.160000K/INCAR @@ -0,0 +1,36 @@ +PREC=A +ENCUT=600 +ISYM=0 +SYMPREC=1e-10 +ALGO=fast +EDIFF=1E-4 +LREAL=A +NPAR=4 +KPAR=2 + +ISTART=0 +ICHARG=2 +ISIF=2 +ISMEAR=-1 +SIGMA=13.78772853954754 +IBRION=0 +MAXMIX=50 +NBLOCK=1 +KBLOCK=100 + +SMASS=0 +POTIM=0.25 +TEBEG=160000 +TEEND=160000 + +NSW=8000 + +LWAVE=F +LCHARG=F +PSTRESS=0 + +KSPACING=0.64 +KGAMMA=F + +NBANDS=400 + diff --git a/tests/generator/out_data_nbands_esti/md.160000K/POSCAR b/tests/generator/out_data_nbands_esti/md.160000K/POSCAR new file mode 120000 index 000000000..fbebe8cb9 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.160000K/POSCAR @@ -0,0 +1 @@ +../POSCAR \ No newline at end of file diff --git a/tests/generator/out_data_nbands_esti/md.240000K/INCAR b/tests/generator/out_data_nbands_esti/md.240000K/INCAR new file mode 100644 index 000000000..bb9f1c9f2 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.240000K/INCAR @@ -0,0 +1,36 @@ +PREC=A +ENCUT=600 +ISYM=0 +SYMPREC=1e-10 +ALGO=fast +EDIFF=1E-4 +LREAL=A +NPAR=4 +KPAR=2 + +ISTART=0 +ICHARG=2 +ISIF=2 +ISMEAR=-1 +SIGMA=20.68159280932131 +IBRION=0 +MAXMIX=50 +NBLOCK=1 +KBLOCK=100 + +SMASS=0 +POTIM=0.25 +TEBEG=240000 +TEEND=240000 + +NSW=8000 + +LWAVE=F +LCHARG=F +PSTRESS=0 + +KSPACING=0.64 +KGAMMA=F + +NBANDS=764 + diff --git a/tests/generator/out_data_nbands_esti/md.240000K/POSCAR b/tests/generator/out_data_nbands_esti/md.240000K/POSCAR new file mode 120000 index 000000000..fbebe8cb9 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.240000K/POSCAR @@ -0,0 +1 @@ +../POSCAR \ No newline at end of file diff --git a/tests/generator/out_data_nbands_esti/mgal/INCAR b/tests/generator/out_data_nbands_esti/mgal/INCAR new file mode 100644 index 000000000..e4c9592d5 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/mgal/INCAR @@ -0,0 +1,33 @@ +PREC=A +ENCUT=600 +ISYM=0 +SYMPREC=1e-10 +ALGO=fast +EDIFF=1E-4 +LREAL=A +NPAR=2 +KPAR=2 + +ISTART=0 +ICHARG=2 +ISIF=2 +ISMEAR=-1 +SIGMA=0.025851991011651636 +IBRION=0 +MAXMIX=50 +NBLOCK=1 +KBLOCK=100 + +SMASS=0 +POTIM=2 +TEBEG=300 +TEEND=300 + +NSW=1 + +LWAVE=F +LCHARG=F +PSTRESS=0 + +KSPACING=32 +KGAMMA=F diff --git a/tests/generator/out_data_nbands_esti/mgal/POSCAR b/tests/generator/out_data_nbands_esti/mgal/POSCAR new file mode 100644 index 000000000..49d340e8d --- /dev/null +++ b/tests/generator/out_data_nbands_esti/mgal/POSCAR @@ -0,0 +1,40 @@ +POSCAR file written by OVITO +0.9 + 8.0852460528260064 0.0000000700556454 0.0000000165920926 + 0.0000000700459398 8.0852460812690730 -0.0000000878331783 + 0.0000000165994710 -0.0000000878293815 8.0852460822851544 + Mg Al + 16 16 +Direct + 0.2500000074218809 -0.0000000006822529 0.2500000011219505 + 0.0000000017515228 0.4999999968593779 0.5000000121259237 + 0.0000000043319078 0.7499999907276940 0.7500000023288846 + 0.5000000030383994 0.5000000063795264 -0.0000000001750512 + 0.5000000069922398 0.2500000092556521 0.7499999925172053 + 0.7500000002384054 0.5000000058460430 0.2499999970004410 + 0.5000000100332991 0.2500000001020252 0.2500000061404412 + 0.7499999967294295 0.4999999938307768 0.7500000077731870 + -0.0000000102302524 0.2500000011729165 0.2500000007828680 + 0.2500000021034525 0.0000000026582450 0.7499999979035360 + 0.2500000064022705 0.7499999919020213 0.0000000019913002 + 0.5000000083231070 -0.0000000011197416 0.0000000014389411 + 0.2500000097291175 0.5000000129780301 0.2499999975347162 + 0.5000000055222689 0.0000000095334217 0.4999999965645718 + 0.5000000034529869 0.7499999969981677 0.2499999981901819 + 0.7499999985377536 0.7499999945443449 0.0000000074372283 + -0.0000000004748536 0.0000000005310409 0.0000000063786655 + 0.2499999999857682 0.5000000028441646 0.7500000018075699 + 0.0000000000448991 0.0000000048734801 0.5000000037789456 + 0.2500000115215270 0.2500000006209973 0.5000000113478330 + 0.7500000009516035 0.2500000011452493 0.5000000093672294 + 0.2500000006602736 0.2500000097862060 -0.0000000026740404 + -0.0000000040407868 0.7499999975356930 0.2499999972984601 + 0.7499999995103841 0.0000000012827216 0.2499999977659152 + -0.0000000041345229 0.2500000119032792 0.7499999956587747 + 0.2500000030261135 0.7499999944555688 0.5000000026313640 + 0.7499999954414514 0.2500000084865056 -0.0000000006412232 + 0.5000000035346804 0.7499999971754691 0.7500000063111742 + 0.7499999910768409 0.0000000040350684 0.7499999999698314 + -0.0000000013440370 0.5000000065441171 -0.0000000011351674 + 0.7499999970723630 0.7499999983979078 0.4999999968129619 + 0.5000000022954397 0.4999999989012168 0.5000000041503138 diff --git a/tests/generator/test_nbands_esti.py b/tests/generator/test_nbands_esti.py new file mode 100644 index 000000000..3e1c39756 --- /dev/null +++ b/tests/generator/test_nbands_esti.py @@ -0,0 +1,75 @@ +import os,sys +import dpdata +import numpy as np +import unittest +import importlib + +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +__package__ = 'generator' +from .context import NBandsEsti + +class TestNBandsEsti(unittest.TestCase): + def test_predict(self): + self.nbe = NBandsEsti(['out_data_nbands_esti/md.010000K', + 'out_data_nbands_esti/md.020000K', + 'out_data_nbands_esti/md.040000K', + 'out_data_nbands_esti/md.080000K', + 'out_data_nbands_esti/md.160000K', + ]) + self.assertEqual(self.nbe.predict('out_data_nbands_esti/md.010000K'), 72) + self.assertEqual(self.nbe.predict('out_data_nbands_esti/md.020000K'), 83) + self.assertEqual(self.nbe.predict('out_data_nbands_esti/md.040000K'), 112) + self.assertEqual(self.nbe.predict('out_data_nbands_esti/md.080000K'), 195) + self.assertEqual(self.nbe.predict('out_data_nbands_esti/md.160000K'), 429) + self.assertEqual(self.nbe.predict('out_data_nbands_esti/md.240000K'), 732) + + def test_save_load(self): + self.nbe2 = NBandsEsti(['out_data_nbands_esti/md.010000K', + 'out_data_nbands_esti/md.020000K', + 'out_data_nbands_esti/md.040000K', + 'out_data_nbands_esti/md.080000K', + 'out_data_nbands_esti/md.160000K', + ]) + self.nbe2.save('tmp.log') + self.nbe = NBandsEsti('tmp.log') + self.assertEqual(self.nbe.predict('out_data_nbands_esti/md.010000K'), 72) + self.assertEqual(self.nbe.predict('out_data_nbands_esti/md.020000K'), 83) + self.assertEqual(self.nbe.predict('out_data_nbands_esti/md.040000K'), 112) + self.assertEqual(self.nbe.predict('out_data_nbands_esti/md.080000K'), 195) + self.assertEqual(self.nbe.predict('out_data_nbands_esti/md.160000K'), 429) + self.assertEqual(self.nbe.predict('out_data_nbands_esti/md.240000K'), 732) + os.remove('tmp.log') + + def test_get_default_nbands(self): + res = NBandsEsti._get_res('out_data_nbands_esti/md.020000K/') + nb = NBandsEsti._get_default_nbands(res) + self.assertEqual(nb, 66) + + def test_get_default_nbands(self): + res = NBandsEsti._get_res('out_data_nbands_esti/mgal/') + nb = NBandsEsti._get_default_nbands(res) + self.assertEqual(nb, 124) + + def test_potcar_nvalence (self) : + res = NBandsEsti._get_potcar_nvalence('out_data_nbands_esti/POTCAR.dbl') + self.assertEqual(res, [10., 3.]) + + def test_incar_ele_temp (self) : + res = NBandsEsti._get_incar_ele_temp('out_data_nbands_esti/md.000300K/INCAR') + self.assertAlmostEqual(res, 0.025851991011651636) + + def test_incar_nbands (self) : + res = NBandsEsti._get_incar_nbands('out_data_nbands_esti/md.020000K/INCAR') + self.assertEqual(res, 81) + + def test_get_res(self): + res = NBandsEsti._get_res('out_data_nbands_esti/md.020000K/') + ref = { + 'natoms': [32], + 'vol': 138.55418502346618, + 'nvalence': [3.], + 'ele_temp': 20000.0, + 'nbands': 81 + } + self.assertEqual(res, ref) + From e093d89620bf262c07384dc8022cfeaf181dd623 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Wed, 9 Oct 2019 12:50:47 -0400 Subject: [PATCH 18/93] add an example --- .../dp_lammps_gaussian/dodecane/dodecane.json | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 examples/run/dp_lammps_gaussian/dodecane/dodecane.json diff --git a/examples/run/dp_lammps_gaussian/dodecane/dodecane.json b/examples/run/dp_lammps_gaussian/dodecane/dodecane.json new file mode 100644 index 000000000..74f6678d3 --- /dev/null +++ b/examples/run/dp_lammps_gaussian/dodecane/dodecane.json @@ -0,0 +1,92 @@ +{ + "type_map": ["C", "H"], + "mass_map": [12.011, 1.008], + "init_data_prefix": "/home/jzzeng/0719dodecane/gen/", + "init_data_sys": ["init_data"], + "init_multi_systems": true, + "init_batch_size": ["auto"], + "sys_configs": [ + ["/home/jzzeng/0719dodecane/gen/data.dodecane.atomic"] + ], + "sys_batch_size": ["auto"], + "sys_format":"lammps/lmp", + "numb_models": 4, + "train_param": "input.json", + "default_training_param" : { + "model":{ + "type_map": ["C","H"], + "descriptor":{ + "type":"se_a", + "sel": [40, 80], + "rcut_smth": 1.00, + "rcut": 6.00, + "neuron": [25, 50, 100], + "resnet_dt": false, + "axis_neuron": 12 + }, + "fitting_net":{ + "neuron": [240, 240, 240], + "resnet_dt": true + } + }, + "learning_rate":{ + "type": "exp", + "start_lr": 0.001, + "decay_steps": 400, + "decay_rate": 0.99 + }, + "loss":{ + "start_pref_e": 0.02, + "limit_pref_e": 1, + "start_pref_f": 1000, + "limit_pref_f": 1, + "start_pref_v": 0, + "limit_pref_v": 0, + "start_pref_pf": 0, + "limit_pref_pf": 0 + }, + "training":{ + "set_prefix": "set", + "stop_batch": 400000, + "disp_file": "lcurve.out", + "disp_freq": 1000, + "numb_test": 1, + "save_freq": 1000, + "save_ckpt": "model.ckpt", + "load_ckpt": "model.ckpt", + "disp_training": true, + "time_training": true, + "profiling": false, + "profiling_file": "timeline.json" + }, + }, + "use_clusters": true, + "cluster_cutoff": 3.5, + "cluster_minify": true, + "use_relative": true, + "epsilon": 1.0, + "model_devi_dt": 0.0001, + "model_devi_skip": 100, + "model_devi_f_trust_lo": 0.20, + "model_devi_f_trust_hi": 0.45, + "model_devi_e_trust_lo": 1e10, + "model_devi_e_trust_hi": 1e10, + "model_devi_clean_traj": false, + "model_devi_jobs": [ + {"sys_idx": [0], "temps": [ 3000], "trj_freq": 10, "nsteps": 2000, "ensemble": "nvt", "_idx": "00"}, + {"sys_idx": [0], "temps": [ 3000], "trj_freq": 10, "nsteps": 4000, "ensemble": "nvt", "_idx": "01"}, + {"sys_idx": [0], "temps": [ 3000], "trj_freq": 10, "nsteps": 8000, "ensemble": "nvt", "_idx": "02"}, + {"sys_idx": [0], "temps": [ 3000], "trj_freq": 10, "nsteps": 16000, "ensemble": "nvt", "_idx": "03"} + ], + "fp_style": "gaussian", + "shuffle_poscar": false, + "fp_task_max": 1000, + "fp_task_min": 10, + "fp_pp_path": "/home/jzzeng/", + "fp_pp_files": [], + "fp_params": { + "keywords": "force mn15/6-31g**", + "nproc": 4, + "multiplicity": "auto" + } +} From 8f09038fbf096dd21403f8ab81e4ca3d035291ab Mon Sep 17 00:00:00 2001 From: Han Wang Date: Thu, 10 Oct 2019 09:42:29 +0800 Subject: [PATCH 19/93] make vasp incar with ele temp --- dpgen/generator/lib/vasp.py | 6 ++ dpgen/generator/run.py | 91 +++++++++++++++++----------- tests/generator/test_make_fp.py | 102 ++++++++++++++++++++++++++++---- 3 files changed, 154 insertions(+), 45 deletions(-) diff --git a/dpgen/generator/lib/vasp.py b/dpgen/generator/lib/vasp.py index ebd87fc75..b6846d19e 100644 --- a/dpgen/generator/lib/vasp.py +++ b/dpgen/generator/lib/vasp.py @@ -2,6 +2,7 @@ import os import numpy as np +from pymatgen.io.vasp import Incar def _make_vasp_incar_dict (ecut, ediff, npar, kpar, kspacing = 0.5, kgamma = True, @@ -113,3 +114,8 @@ def make_vasp_incar_user_dict(fp_params) : incar = write_incar_dict(incar_dict) return incar +def incar_upper(dincar): + standard_incar={} + for key,val in dincar.items(): + standard_incar[key.upper()]=val + return Incar(standard_incar) diff --git a/dpgen/generator/run.py b/dpgen/generator/run.py index ecb4469d5..3e3beacec 100644 --- a/dpgen/generator/run.py +++ b/dpgen/generator/run.py @@ -22,6 +22,7 @@ import dpdata import numpy as np import subprocess as sp +import scipy.constants as pc from collections import Counter from distutils.version import LooseVersion from dpgen import dlog @@ -36,6 +37,7 @@ from dpgen.generator.lib.lammps import make_lammps_input from dpgen.generator.lib.vasp import write_incar_dict from dpgen.generator.lib.vasp import make_vasp_incar_user_dict +from dpgen.generator.lib.vasp import incar_upper from dpgen.generator.lib.pwscf import make_pwscf_input #from dpgen.generator.lib.pwscf import cvt_1frame from dpgen.generator.lib.siesta import make_siesta_input @@ -818,7 +820,7 @@ def _make_fp_vasp_inner (modd_path, os.chdir(cwd) return fp_tasks -def make_fp_vasp_incar(jdata, filename): +def _make_vasp_incar(jdata, filename): if 'fp_incar' in jdata.keys() : fp_incar_path = jdata['fp_incar'] assert(os.path.exists(fp_incar_path)) @@ -834,13 +836,25 @@ def make_fp_vasp_incar(jdata, filename): fp.write(incar) return incar -def _link_fp_vasp_incar (iter_index, +def _make_vasp_incar_ele_temp(jdata, filename, temp_ele, nbands_esti = None): + with open(filename) as fp: + incar = fp.read() + incar = incar_upper(Incar.from_string(incar)) + incar['ISMEAR'] = -1 + incar['SIGMA'] = temp_ele * pc.Boltzmann / pc.electron_volt + incar.write_file('INCAR') + if nbands_esti is not None: + nbands = nbands_esti.predict('.') + with open(filename) as fp: + incar = Incar.from_string(fp.read()) + incar['NBANDS'] = nbands + incar.write_file('INCAR') + +def _make_fp_vasp_incar (iter_index, jdata, - incar = 'INCAR') : + nbands_esti = None) : iter_name = make_iter_name(iter_index) work_path = os.path.join(iter_name, fp_name) - incar_file = os.path.join(work_path, incar) - incar_file = os.path.abspath(incar_file) fp_tasks = glob.glob(os.path.join(work_path, 'task.*')) fp_tasks.sort() if len(fp_tasks) == 0 : @@ -848,30 +862,16 @@ def _link_fp_vasp_incar (iter_index, cwd = os.getcwd() for ii in fp_tasks: os.chdir(ii) - os.symlink(os.path.relpath(incar_file), incar) + _make_vasp_incar(jdata, 'INCAR') + if os.path.exists('job.json'): + with open('job.json') as fp: + job_data = json.load(fp) + if 'temp_ele' in job_data: + _make_vasp_incar_ele_temp(jdata, 'INCAR', job_data['temp_ele'], + nbands_esti = nbands_esti) os.chdir(cwd) -def _make_fp_vasp_kp (iter_index,jdata, incar): - dincar=Incar.from_string(incar) - standard_incar={} - for key,val in dincar.items(): - standard_incar[key.upper()]=val - try: - kspacing = standard_incar['KSPACING'] - except: - raise RuntimeError ("KSPACING must be given in INCAR") - try: - gamma = standard_incar['KGAMMA'] - if isinstance(gamma,bool): - pass - else: - if gamma[0].upper()=="T": - gamma=True - else: - gamma=False - except: - raise RuntimeError ("KGAMMA must be given in INCAR") - +def _make_fp_vasp_kp (iter_index,jdata): iter_name = make_iter_name(iter_index) work_path = os.path.join(iter_name, fp_name) @@ -882,12 +882,35 @@ def _make_fp_vasp_kp (iter_index,jdata, incar): cwd = os.getcwd() for ii in fp_tasks: os.chdir(ii) + # get kspacing and kgamma from incar + assert(os.path.exists('INCAR')) + with open('INCAR') as fp: + incar = fp.read() + standard_incar = incar_upper(Incar.from_string(incar)) + try: + kspacing = standard_incar['KSPACING'] + except: + raise RuntimeError ("KSPACING must be given in INCAR") + try: + gamma = standard_incar['KGAMMA'] + if isinstance(gamma,bool): + pass + else: + if gamma[0].upper()=="T": + gamma=True + else: + gamma=False + except: + raise RuntimeError ("KGAMMA must be given in INCAR") + # check poscar assert(os.path.exists('POSCAR')) + # make kpoints ret=make_kspacing_kpoints('POSCAR', kspacing, gamma) kp=Kpoints.from_string(ret) kp.write_file("KPOINTS") os.chdir(cwd) + def _link_fp_vasp_pp (iter_index, jdata) : fp_pp_path = jdata['fp_pp_path'] @@ -985,23 +1008,21 @@ def _make_fp_vasp_configs(iter_index, jdata) return fp_tasks - def make_fp_vasp (iter_index, jdata) : # make config fp_tasks = _make_fp_vasp_configs(iter_index, jdata) if len(fp_tasks) == 0 : return - # all tasks share the same incar - work_path = os.path.join(make_iter_name(iter_index), fp_name) - incar_file = os.path.abspath(os.path.join(work_path, 'INCAR')) - incar_str = make_fp_vasp_incar(jdata, incar_file) - # link incar to each task folder - _link_fp_vasp_incar(iter_index, jdata) + # abs path for fp_incar if it exists + if 'fp_incar' in jdata: + jdata['fp_incar'] = os.path.abspath(jdata['fp_incar']) + # create incar + _make_fp_vasp_incar(iter_index, jdata) # create potcar sys_link_fp_vasp_pp(iter_index, jdata) # create kpoints - _make_fp_vasp_kp(iter_index, jdata, incar_str) + _make_fp_vasp_kp(iter_index, jdata) def make_fp_pwscf(iter_index, diff --git a/tests/generator/test_make_fp.py b/tests/generator/test_make_fp.py index 2af722650..2cddf9ff1 100644 --- a/tests/generator/test_make_fp.py +++ b/tests/generator/test_make_fp.py @@ -25,6 +25,7 @@ from .comp_sys import test_coord from .comp_sys import test_cell from pymatgen.io.vasp import Kpoints,Incar +import scipy.constants as pc vasp_incar_ref = "PREC=A\n\ ENCUT=600\n\ @@ -46,6 +47,26 @@ KSPACING=0.16\n\ KGAMMA=F\n"; +vasp_incar_temp_ele_ref = "PREC=A\n\ +ENCUT=600\n\ +ISYM=0\n\ +ALGO=fast\n\ +EDIFF=1e-05\n\ +LREAL=A\n\ +NPAR=1\n\ +KPAR=1\n\ +NELMIN=4\n\ +ISIF=2\n\ +ISMEAR=-1\n\ +SIGMA=%.10f\n\ +IBRION=-1\n\ +NSW=0\n\ +LWAVE=F\n\ +LCHARG=F\n\ +PSTRESS=0\n\ +KSPACING=0.16\n\ +KGAMMA=F\n"; + pwscf_input_ref="&control\n\ calculation='scf',\n\ restart_mode='from_scratch',\n\ @@ -224,10 +245,12 @@ def _write_lammps_dump(sys, dump_file, f_idx = 0) : fp.write('%d %d %f %f %f\n' % (ii+1, atype[ii]+1, coord[ii][0], coord[ii][1], coord[ii][2])) -def _make_fake_md(idx, md_descript, atom_types, type_map) : +def _make_fake_md(idx, md_descript, atom_types, type_map, temp_ele = None) : """ md_descript: list of dimension [n_sys][n_MD][n_frame] + temp_ele: list of dimension + [n_sys][n_MD] """ natoms = len(atom_types) ntypes = len(type_map) @@ -257,6 +280,9 @@ def _make_fake_md(idx, md_descript, atom_types, type_map) : md_out[:,0] = np.arange(nframes) md_out[:,4] = mm np.savetxt(os.path.join(task_dir, 'model_devi.out'), md_out) + if temp_ele is not None: + with open(os.path.join(task_dir, 'job.json'), 'w') as fp: + json.dump({"temp_ele": temp_ele[sidx][midx]}, fp) def _check_poscars(testCase, idx, fp_task_max, type_map) : @@ -312,7 +338,7 @@ def _check_kpoints(testCase, idx) : def _check_incar_exists(testCase, idx) : fp_path = os.path.join('iter.%06d' % idx, '02.fp') - testCase.assertTrue(os.path.isfile(os.path.join(fp_path, 'INCAR'))) + # testCase.assertTrue(os.path.isfile(os.path.join(fp_path, 'INCAR'))) tasks = glob.glob(os.path.join(fp_path, 'task.*')) for ii in tasks : my_file_cmp(testCase, @@ -356,10 +382,32 @@ def _check_sel(testCase, idx, fp_task_max, flo, fhi): def _check_incar(testCase, idx): fp_path = os.path.join('iter.%06d' % idx, '02.fp') - with open(os.path.join(fp_path, 'INCAR')) as fp: - incar = fp.read() - testCase.assertEqual(incar.strip(), vasp_incar_ref.strip()) - + tasks = glob.glob(os.path.join(fp_path, 'task.*')) + cwd = os.getcwd() + for ii in tasks : + os.chdir(ii) + with open('INCAR') as fp: + incar = fp.read() + testCase.assertEqual(incar.strip(), vasp_incar_ref.strip()) + os.chdir(cwd) + +def _check_incar_temp_ele(testCase, idx, temp_ele): + fp_path = os.path.join('iter.%06d' % idx, '02.fp') + tasks = glob.glob(os.path.join(fp_path, 'task.*')) + cwd = os.getcwd() + for ii in tasks : + os.chdir(ii) + bname = os.path.basename(ii) + sidx = int(bname.split('.')[1]) + tidx = int(bname.split('.')[2]) + with open('INCAR') as fp: + incar = fp.read() + incar0 = Incar.from_string(incar) + # make_fake_md: the frames in a system shares the same temp_ele + incar1 = Incar.from_string(vasp_incar_temp_ele_ref%(temp_ele[sidx][0] * pc.Boltzmann / pc.electron_volt)) + for ii in incar0.keys(): + testCase.assertAlmostEqual(incar0[ii], incar1[ii], msg = 'key %s differ: ' % (ii), places = 5) + os.chdir(cwd) def _check_pwscf_input_head(testCase, idx) : fp_path = os.path.join('iter.%06d' % idx, '02.fp') @@ -525,7 +573,7 @@ def test_make_fp_vasp(self): make_fp(0, jdata, {}) _check_sel(self, 0, jdata['fp_task_max'], jdata['model_devi_f_trust_lo'], jdata['model_devi_f_trust_hi']) _check_poscars(self, 0, jdata['fp_task_max'], jdata['type_map']) - _check_incar_exists(self, 0) + # _check_incar_exists(self, 0) _check_incar(self, 0) _check_kpoints_exists(self, 0) _check_kpoints(self,0) @@ -555,7 +603,7 @@ def test_make_fp_vasp_old(self): make_fp(0, jdata, {}) _check_sel(self, 0, jdata['fp_task_max'], jdata['model_devi_f_trust_lo'], jdata['model_devi_f_trust_hi']) _check_poscars(self, 0, jdata['fp_task_max'], jdata['type_map']) - _check_incar_exists(self, 0) + # _check_incar_exists(self, 0) _check_incar(self, 0) _check_kpoints_exists(self, 0) _check_kpoints(self,0) @@ -585,7 +633,7 @@ def test_make_fp_vasp_less_sel(self): make_fp(0, jdata, {}) _check_sel(self, 0, jdata['fp_task_max'], jdata['model_devi_f_trust_lo'], jdata['model_devi_f_trust_hi']) _check_poscars(self, 0, jdata['fp_task_max'], jdata['type_map']) - _check_incar_exists(self, 0) + # _check_incar_exists(self, 0) _check_incar(self, 0) _check_kpoints_exists(self, 0) _check_kpoints(self,0) @@ -619,7 +667,7 @@ def test_make_fp_vasp_from_incar(self): make_fp(0, jdata, {}) _check_sel(self, 0, jdata['fp_task_max'], jdata['model_devi_f_trust_lo'], jdata['model_devi_f_trust_hi']) _check_poscars(self, 0, jdata['fp_task_max'], jdata['type_map']) - _check_incar_exists(self, 0) + # _check_incar_exists(self, 0) _check_incar(self, 0) _check_kpoints_exists(self, 0) _check_kpoints(self,0) @@ -627,6 +675,40 @@ def test_make_fp_vasp_from_incar(self): # _check_potcar(self, 0, jdata['fp_pp_path'], jdata['fp_pp_files']) shutil.rmtree('iter.000000') + def test_make_fp_vasp_temp_ele(self): + ## Verify if user chooses to diy VASP INCAR totally. + if os.path.isdir('iter.000000') : + shutil.rmtree('iter.000000') + with open (param_diy_file, 'r') as fp : + jdata = json.load (fp) + fp.close() + with open (machine_file, 'r') as fp: + mdata = json.load (fp) + fp.close() + md_descript = [] + temp_ele = [] + nsys = 2 + nmd = 3 + n_frame = 10 + for ii in range(nsys) : + tmp = [] + for jj in range(nmd) : + tmp.append(np.arange(0, 0.29, 0.29/10)) + md_descript.append(tmp) + temp_ele.append([np.random.random() * 10000] * nmd) + atom_types = [0, 1, 0, 1] + type_map = jdata['type_map'] + _make_fake_md(0, md_descript, atom_types, type_map, temp_ele = temp_ele) + make_fp(0, jdata, {}) + _check_sel(self, 0, jdata['fp_task_max'], jdata['model_devi_f_trust_lo'], jdata['model_devi_f_trust_hi']) + _check_poscars(self, 0, jdata['fp_task_max'], jdata['type_map']) + _check_incar_temp_ele(self, 0, temp_ele) + _check_kpoints_exists(self, 0) + _check_kpoints(self,0) + # checked elsewhere + # _check_potcar(self, 0, jdata['fp_pp_path'], jdata['fp_pp_files']) + shutil.rmtree('iter.000000') + class TestMakeFPGaussian(unittest.TestCase): def test_make_fp_gaussian(self): From 6f2999cf7901f69abff79f6d70905b48a2bafeca Mon Sep 17 00:00:00 2001 From: Han Wang Date: Thu, 10 Oct 2019 10:19:14 +0800 Subject: [PATCH 20/93] enable nbands estimate --- dpgen/generator/run.py | 18 +++++++++++++----- tests/generator/POTCAR.al | 0 tests/generator/POTCAR.mg | 0 tests/generator/param-mg-vasp-diy.json | 5 +++-- tests/generator/param-mg-vasp-old.json | 2 +- tests/generator/param-mg-vasp.json | 2 +- tests/generator/test_make_fp.py | 7 +++++-- tests/generator/{ => vasp}/INCAR.diy | 0 tests/generator/vasp/potcars/POTCAR.al | 4 ++++ tests/generator/vasp/potcars/POTCAR.mg | 4 ++++ 10 files changed, 31 insertions(+), 11 deletions(-) delete mode 100644 tests/generator/POTCAR.al delete mode 100644 tests/generator/POTCAR.mg rename tests/generator/{ => vasp}/INCAR.diy (100%) create mode 100644 tests/generator/vasp/potcars/POTCAR.al create mode 100644 tests/generator/vasp/potcars/POTCAR.mg diff --git a/dpgen/generator/run.py b/dpgen/generator/run.py index 3e3beacec..16d7a460f 100644 --- a/dpgen/generator/run.py +++ b/dpgen/generator/run.py @@ -43,6 +43,7 @@ from dpgen.generator.lib.siesta import make_siesta_input from dpgen.generator.lib.gaussian import make_gaussian_input, take_cluster from dpgen.generator.lib.cp2k import make_cp2k_input, make_cp2k_xyz +from dpgen.generator.lib.ele_temp import NBandsEsti from dpgen.remote.RemoteJob import SSHSession, JobStatus, SlurmJob, PBSJob, LSFJob, CloudMachineJob, awsMachineJob from dpgen.remote.group_jobs import ucloud_submit_jobs, aws_submit_jobs from dpgen.remote.group_jobs import group_slurm_jobs @@ -867,7 +868,8 @@ def _make_fp_vasp_incar (iter_index, with open('job.json') as fp: job_data = json.load(fp) if 'temp_ele' in job_data: - _make_vasp_incar_ele_temp(jdata, 'INCAR', job_data['temp_ele'], + _make_vasp_incar_ele_temp(jdata, 'INCAR', + job_data['temp_ele'], nbands_esti = nbands_esti) os.chdir(cwd) @@ -1017,11 +1019,17 @@ def make_fp_vasp (iter_index, # abs path for fp_incar if it exists if 'fp_incar' in jdata: jdata['fp_incar'] = os.path.abspath(jdata['fp_incar']) - # create incar - _make_fp_vasp_incar(iter_index, jdata) - # create potcar + # get nbands esti if it exists + if 'fp_nbands_esti_data' in jdata: + nbe = NBandsEsti(jdata['fp_nbands_esti_data']) + else: + nbe = None + # order is critical! + # 1, create potcar sys_link_fp_vasp_pp(iter_index, jdata) - # create kpoints + # 2, create incar + _make_fp_vasp_incar(iter_index, jdata, nbands_esti = nbe) + # 3, create kpoints _make_fp_vasp_kp(iter_index, jdata) diff --git a/tests/generator/POTCAR.al b/tests/generator/POTCAR.al deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/generator/POTCAR.mg b/tests/generator/POTCAR.mg deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/generator/param-mg-vasp-diy.json b/tests/generator/param-mg-vasp-diy.json index b40f255b0..b7fffc41b 100644 --- a/tests/generator/param-mg-vasp-diy.json +++ b/tests/generator/param-mg-vasp-diy.json @@ -84,8 +84,9 @@ "fp_task_max": 100, "fp_task_min": 10, "fp_pp_path": ".", - "fp_pp_files": ["POTCAR.mg", "POTCAR.al"], + "fp_pp_files": ["vasp/potcars/POTCAR.mg", "vasp/potcars/POTCAR.al"], "_comment": " user provided vasp script ", - "fp_incar" : "INCAR.diy", + "fp_incar" : "vasp/INCAR.diy", + "fp_nbands_esti_data": "vasp/nbands_esti.out", "_comment": " that's all " } diff --git a/tests/generator/param-mg-vasp-old.json b/tests/generator/param-mg-vasp-old.json index e79af4fb3..cd521bbc3 100644 --- a/tests/generator/param-mg-vasp-old.json +++ b/tests/generator/param-mg-vasp-old.json @@ -84,7 +84,7 @@ "fp_task_max": 100, "fp_task_min": 10, "fp_pp_path": ".", - "fp_pp_files": ["POTCAR.mg", "POTCAR.al"], + "fp_pp_files": ["vasp/potcars/POTCAR.mg", "vasp/potcars/POTCAR.al"], "fp_params": { "_comment": "given in unit depending on the fp method", "ecut": 600, diff --git a/tests/generator/param-mg-vasp.json b/tests/generator/param-mg-vasp.json index eba99eabe..908be9afb 100644 --- a/tests/generator/param-mg-vasp.json +++ b/tests/generator/param-mg-vasp.json @@ -84,7 +84,7 @@ "fp_task_max": 100, "fp_task_min": 10, "fp_pp_path": ".", - "fp_pp_files": ["POTCAR.mg", "POTCAR.al"], + "fp_pp_files": ["vasp/potcars/POTCAR.mg", "vasp/potcars/POTCAR.al"], "_comment": " user provided vasp script ", "user_fp_params": { "PREC": "A", diff --git a/tests/generator/test_make_fp.py b/tests/generator/test_make_fp.py index 2cddf9ff1..c22801fac 100644 --- a/tests/generator/test_make_fp.py +++ b/tests/generator/test_make_fp.py @@ -406,7 +406,10 @@ def _check_incar_temp_ele(testCase, idx, temp_ele): # make_fake_md: the frames in a system shares the same temp_ele incar1 = Incar.from_string(vasp_incar_temp_ele_ref%(temp_ele[sidx][0] * pc.Boltzmann / pc.electron_volt)) for ii in incar0.keys(): - testCase.assertAlmostEqual(incar0[ii], incar1[ii], msg = 'key %s differ: ' % (ii), places = 5) + # skip checking nbands... + if ii == 'NBANDS': + continue + testCase.assertAlmostEqual(incar0[ii], incar1[ii], msg = 'key %s differ' % (ii), places = 5) os.chdir(cwd) def _check_pwscf_input_head(testCase, idx) : @@ -695,7 +698,7 @@ def test_make_fp_vasp_temp_ele(self): for jj in range(nmd) : tmp.append(np.arange(0, 0.29, 0.29/10)) md_descript.append(tmp) - temp_ele.append([np.random.random() * 10000] * nmd) + temp_ele.append([np.random.random() * 100000] * nmd) atom_types = [0, 1, 0, 1] type_map = jdata['type_map'] _make_fake_md(0, md_descript, atom_types, type_map, temp_ele = temp_ele) diff --git a/tests/generator/INCAR.diy b/tests/generator/vasp/INCAR.diy similarity index 100% rename from tests/generator/INCAR.diy rename to tests/generator/vasp/INCAR.diy diff --git a/tests/generator/vasp/potcars/POTCAR.al b/tests/generator/vasp/potcars/POTCAR.al new file mode 100644 index 000000000..f3b7295da --- /dev/null +++ b/tests/generator/vasp/potcars/POTCAR.al @@ -0,0 +1,4 @@ + PAW_PBE Al 04Jan2001 + 3.00000000000000 + TITEL = PAW_PBE Al 04Jan2001 + End of Dataset diff --git a/tests/generator/vasp/potcars/POTCAR.mg b/tests/generator/vasp/potcars/POTCAR.mg new file mode 100644 index 000000000..4762c5028 --- /dev/null +++ b/tests/generator/vasp/potcars/POTCAR.mg @@ -0,0 +1,4 @@ + PAW_PBE Mg_sv 12Apr2007 + 10.0000000000000 + TITEL = PAW_PBE Mg_sv 12Apr2007 + End of Dataset From c869b8eaa0576fa9c9d3b1bc9bbb417af46c5db8 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Thu, 10 Oct 2019 11:26:07 +0800 Subject: [PATCH 21/93] save temp_ele as fparam if there is any. Stop dangerous exception passing! --- dpgen/generator/run.py | 35 +++++++++++-------- .../02.fp/task.000.000000/job.json | 1 + .../02.fp/task.000.000001/job.json | 1 + .../02.fp/task.001.000000/job.json | 1 + .../02.fp/task.001.000001/job.json | 1 + tests/generator/test_post_fp.py | 9 +++++ 6 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 tests/generator/out_data_post_fp_vasp/02.fp/task.000.000000/job.json create mode 100644 tests/generator/out_data_post_fp_vasp/02.fp/task.000.000001/job.json create mode 100644 tests/generator/out_data_post_fp_vasp/02.fp/task.001.000000/job.json create mode 100644 tests/generator/out_data_post_fp_vasp/02.fp/task.001.000001/job.json diff --git a/dpgen/generator/run.py b/dpgen/generator/run.py index 16d7a460f..6fcf32496 100644 --- a/dpgen/generator/run.py +++ b/dpgen/generator/run.py @@ -1329,8 +1329,9 @@ def post_fp_vasp (iter_index, for ss in system_index : sys_outcars = glob.glob(os.path.join(work_path, "task.%s.*/OUTCAR"%ss)) sys_outcars.sort() - flag=True - tcount+=len(sys_outcars) + tcount += len(sys_outcars) + all_sys = None + all_te = [] for oo in sys_outcars : try: _sys = dpdata.LabeledSystem(oo, type_map = jdata['type_map']) @@ -1341,23 +1342,29 @@ def post_fp_vasp (iter_index, except: _sys = dpdata.LabeledSystem() dlog.info('Failed fp path: %s'%oo.replace('OUTCAR','')) - if len(_sys) == 1: - if flag: - all_sys = _sys - flag = False - else: - all_sys.append(_sys) + if all_sys is None: + all_sys = _sys + else: + all_sys.append(_sys) + # save temp_ele, if any + with open(oo.replace('OUTCAR', 'job.json')) as fp: + job_data = json.load(fp) + if 'temp_ele' in job_data: + temp_ele = job_data['temp_ele'] + all_te.append(temp_ele) else: - icount+=1 - - try: - # limitation --> all_sys not defined + icount+=1 + all_te = np.array(all_te) + if all_sys is not None: sys_data_path = os.path.join(work_path, 'data.%s'%ss) all_sys.to_deepmd_raw(sys_data_path) all_sys.to_deepmd_npy(sys_data_path, set_size = len(sys_outcars)) - except: - pass + if all_te.size > 0: + assert(len(all_sys) == all_sys.get_nframes()) + all_te = np.reshape(all_te, [-1,1]) + np.savetxt(os.path.join(sys_data_path, 'fparam.raw'), all_te) + np.save(os.path.join(sys_data_path, 'set.000', 'fparam.npy'), all_te) dlog.info("failed frame number: %s "%icount) dlog.info("total frame number: %s "%tcount) diff --git a/tests/generator/out_data_post_fp_vasp/02.fp/task.000.000000/job.json b/tests/generator/out_data_post_fp_vasp/02.fp/task.000.000000/job.json new file mode 100644 index 000000000..f631c57bf --- /dev/null +++ b/tests/generator/out_data_post_fp_vasp/02.fp/task.000.000000/job.json @@ -0,0 +1 @@ +{ "temp_ele": 0 } diff --git a/tests/generator/out_data_post_fp_vasp/02.fp/task.000.000001/job.json b/tests/generator/out_data_post_fp_vasp/02.fp/task.000.000001/job.json new file mode 100644 index 000000000..a5bb359f6 --- /dev/null +++ b/tests/generator/out_data_post_fp_vasp/02.fp/task.000.000001/job.json @@ -0,0 +1 @@ +{ "temp_ele": 1 } diff --git a/tests/generator/out_data_post_fp_vasp/02.fp/task.001.000000/job.json b/tests/generator/out_data_post_fp_vasp/02.fp/task.001.000000/job.json new file mode 100644 index 000000000..64ee7787b --- /dev/null +++ b/tests/generator/out_data_post_fp_vasp/02.fp/task.001.000000/job.json @@ -0,0 +1 @@ +{ "temp_ele": 100000 } diff --git a/tests/generator/out_data_post_fp_vasp/02.fp/task.001.000001/job.json b/tests/generator/out_data_post_fp_vasp/02.fp/task.001.000001/job.json new file mode 100644 index 000000000..bdd3bba39 --- /dev/null +++ b/tests/generator/out_data_post_fp_vasp/02.fp/task.001.000001/job.json @@ -0,0 +1 @@ +{ "temp_ele": 110000 } diff --git a/tests/generator/test_post_fp.py b/tests/generator/test_post_fp.py index fe256e119..526c05951 100644 --- a/tests/generator/test_post_fp.py +++ b/tests/generator/test_post_fp.py @@ -98,6 +98,10 @@ def test_post_fp_vasp_0(self): self.assertAlmostEqual(ref_cell[ff][ii][jj], sys.data['cells'][ff][ii][jj]) + fparam = np.load('iter.000000/02.fp/data.000/set.000/fparam.npy') + self.assertEqual(fparam.shape[0], 2) + self.assertEqual(list(fparam), [0, 1]) + def test_post_fp_vasp_1(self): @@ -138,6 +142,11 @@ def test_post_fp_vasp_1(self): self.assertAlmostEqual(ref_cell[ff][ii][jj], sys.data['cells'][ff][ii][jj]) + fparam = np.load('iter.000000/02.fp/data.001/set.000/fparam.npy') + self.assertEqual(fparam.shape[0], 1) + self.assertEqual(list(fparam), [100000]) + + def test_post_fp_vasp_2(self): with open (param_file, 'r') as fp : jdata = json.load (fp) From de95823517786622793b76e86ef5a9afa5893898 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 14 Oct 2019 07:59:53 +0800 Subject: [PATCH 22/93] support for ele temp --- dpgen/generator/lib/lammps.py | 7 +++ dpgen/generator/run.py | 48 ++++++++++++++----- dpgen/tools/relabel.py | 16 ++----- .../02.fp/task.000.000000/job.json | 2 +- .../02.fp/task.000.000001/job.json | 2 +- .../02.fp/task.001.000000/job.json | 2 +- .../02.fp/task.001.000001/job.json | 2 +- tests/generator/test_make_fp.py | 26 +++++----- 8 files changed, 62 insertions(+), 43 deletions(-) diff --git a/dpgen/generator/lib/lammps.py b/dpgen/generator/lib/lammps.py index 30d78b78d..4921b3771 100644 --- a/dpgen/generator/lib/lammps.py +++ b/dpgen/generator/lib/lammps.py @@ -28,12 +28,17 @@ def make_lammps_input(ensemble, pres = None, tau_p = 0.5, pka_e = None, + ele_temp = None, max_seed = 1000000, deepmd_version = '0.1') : + if ele_temp is not None and LooseVersion(deepmd_version) < LooseVersion('1'): + raise RuntimeError('the electron temperature is only supported by deepmd-kit >= 1.0.0, please upgrade your deepmd-kit') ret = "variable NSTEPS equal %d\n" % nsteps ret+= "variable THERMO_FREQ equal %d\n" % trj_freq ret+= "variable DUMP_FREQ equal %d\n" % trj_freq ret+= "variable TEMP equal %f\n" % temp + if ele_temp is not None: + ret+= "variable ELE_TEMP equal %f\n" % ele_temp ret+= "variable PRES equal %f\n" % pres ret+= "variable TAU_T equal %f\n" % tau_t ret+= "variable TAU_P equal %f\n" % tau_p @@ -65,6 +70,8 @@ def make_lammps_input(ensemble, if jdata.get('use_relative', False): eps = jdata.get('eps', 0.) keywords += "relative %s " % jdata['epsilon'] + if ele_temp is not None: + keywords += "fparam ${ELE_TEMP}" ret+= "pair_style deepmd %s out_freq ${THERMO_FREQ} out_file model_devi.out %s\n" % (graph_list, keywords) ret+= "pair_coeff \n" ret+= "\n" diff --git a/dpgen/generator/run.py b/dpgen/generator/run.py index 6fcf32496..afd7ad352 100644 --- a/dpgen/generator/run.py +++ b/dpgen/generator/run.py @@ -185,6 +185,7 @@ def make_train (iter_index, init_data_sys_ = jdata['init_data_sys'] fp_task_min = jdata['fp_task_min'] model_devi_jobs = jdata['model_devi_jobs'] + use_ele_temp = jdata.get('use_ele_temp', False) if iter_index > 0 and _check_empty_iter(iter_index-1, fp_task_min) : log_task('prev data is empty, copy prev model') @@ -271,10 +272,15 @@ def make_train (iter_index, # 0.x jinput['systems'] = init_data_sys jinput['batch_size'] = init_batch_size + if use_ele_temp: + raise RuntimeError('the electron temperature is only supported by deepmd-kit >= 1.0.0, please upgrade your deepmd-kit') else: # 1.x jinput['training']['systems'] = init_data_sys jinput['training']['batch_size'] = init_batch_size + if use_ele_temp: + # fparam for electron temperature + jinput['model']['fitting_net']['numb_fparam'] = 1 for ii in range(numb_models) : task_path = os.path.join(work_path, train_task_fmt % ii) create_path(task_path) @@ -481,6 +487,7 @@ def parse_cur_job(cur_job) : def make_model_devi (iter_index, jdata, mdata) : + use_ele_temp = jdata.get('use_ele_temp', False) model_devi_dt = jdata['model_devi_dt'] model_devi_neidelay = None if 'model_devi_neidelay' in jdata : @@ -574,7 +581,18 @@ def make_model_devi (iter_index, conf_counter = 0 task_counter = 0 for cc in ss : - for tt in temps: + for tt_ in temps: + if use_ele_temp: + if type(tt_) == list: + tt = tt_[0] + te = tt_[1] + else: + assert(type(tt_) == float or type(tt_) == int) + tt = float(tt_) + te = tt + else : + tt = tt_ + te = None for pp in press: task_name = make_model_devi_task_name(sys_idx[sys_counter], task_counter) conf_name = make_model_devi_conf_name(sys_idx[sys_counter], conf_counter) + '.lmp' @@ -606,11 +624,14 @@ def make_model_devi (iter_index, pres = pp, tau_p = model_devi_taup, pka_e = pka_e, + ele_temp = te, deepmd_version = deepmd_version) job = {} job["ensemble"] = ensemble job["press"] = pp job["temps"] = tt + if te is not None: + job["ele_temp"] = te job["model_devi_dt"] = model_devi_dt with open('job.json', 'w') as _outfile: json.dump(job, _outfile, indent = 4) @@ -821,7 +842,7 @@ def _make_fp_vasp_inner (modd_path, os.chdir(cwd) return fp_tasks -def _make_vasp_incar(jdata, filename): +def make_vasp_incar(jdata, filename): if 'fp_incar' in jdata.keys() : fp_incar_path = jdata['fp_incar'] assert(os.path.exists(fp_incar_path)) @@ -837,12 +858,12 @@ def _make_vasp_incar(jdata, filename): fp.write(incar) return incar -def _make_vasp_incar_ele_temp(jdata, filename, temp_ele, nbands_esti = None): +def make_vasp_incar_ele_temp(jdata, filename, ele_temp, nbands_esti = None): with open(filename) as fp: incar = fp.read() incar = incar_upper(Incar.from_string(incar)) incar['ISMEAR'] = -1 - incar['SIGMA'] = temp_ele * pc.Boltzmann / pc.electron_volt + incar['SIGMA'] = ele_temp * pc.Boltzmann / pc.electron_volt incar.write_file('INCAR') if nbands_esti is not None: nbands = nbands_esti.predict('.') @@ -863,14 +884,14 @@ def _make_fp_vasp_incar (iter_index, cwd = os.getcwd() for ii in fp_tasks: os.chdir(ii) - _make_vasp_incar(jdata, 'INCAR') + make_vasp_incar(jdata, 'INCAR') if os.path.exists('job.json'): with open('job.json') as fp: job_data = json.load(fp) - if 'temp_ele' in job_data: - _make_vasp_incar_ele_temp(jdata, 'INCAR', - job_data['temp_ele'], - nbands_esti = nbands_esti) + if 'ele_temp' in job_data: + make_vasp_incar_ele_temp(jdata, 'INCAR', + job_data['ele_temp'], + nbands_esti = nbands_esti) os.chdir(cwd) def _make_fp_vasp_kp (iter_index,jdata): @@ -1347,12 +1368,12 @@ def post_fp_vasp (iter_index, all_sys = _sys else: all_sys.append(_sys) - # save temp_ele, if any + # save ele_temp, if any with open(oo.replace('OUTCAR', 'job.json')) as fp: job_data = json.load(fp) - if 'temp_ele' in job_data: - temp_ele = job_data['temp_ele'] - all_te.append(temp_ele) + if 'ele_temp' in job_data: + ele_temp = job_data['ele_temp'] + all_te.append(ele_temp) else: icount+=1 all_te = np.array(all_te) @@ -1362,6 +1383,7 @@ def post_fp_vasp (iter_index, all_sys.to_deepmd_npy(sys_data_path, set_size = len(sys_outcars)) if all_te.size > 0: assert(len(all_sys) == all_sys.get_nframes()) + assert(len(all_sys) == all_te.size) all_te = np.reshape(all_te, [-1,1]) np.savetxt(os.path.join(sys_data_path, 'fparam.raw'), all_te) np.save(os.path.join(sys_data_path, 'set.000', 'fparam.npy'), all_te) diff --git a/dpgen/tools/relabel.py b/dpgen/tools/relabel.py index 5aa1ea8df..3cc3627f6 100755 --- a/dpgen/tools/relabel.py +++ b/dpgen/tools/relabel.py @@ -6,8 +6,7 @@ sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')) from dpgen.generator.lib.pwscf import make_pwscf_input from dpgen.generator.lib.siesta import make_siesta_input -from dpgen.generator.lib.vasp import make_vasp_incar -from dpgen.generator.lib.vasp import system_from_poscar +from dpgen.generator.run import make_vasp_incar import dpdata def get_lmp_info(input_file) : @@ -76,7 +75,7 @@ def make_pwscf(tdir, fp_params, mass_map, fp_pp_path, fp_pp_files, user_input) : def make_siesta(tdir, fp_params, fp_pp_path, fp_pp_files) : cwd = os.getcwd() os.chdir(tdir) - sys_data = system_from_poscar('POSCAR') + sys_data = dpdata.System('POSCAR').data ret = make_siesta_input(sys_data, fp_pp_files, fp_params) open('input', 'w').write(ret) os.chdir(cwd) @@ -201,16 +200,7 @@ def create_tasks(target_folder, param_file, output, fp_json, verbose = True, num os.makedirs(output, exist_ok = True) if fp_style == 'vasp': copy_pp_files(output, fp_pp_path, fp_pp_files) - try : - fp_params = fp_jdata['fp_params'] - make_vasp(output, fp_params) - except: - fp_incar = fp_jdata['fp_incar'] - cwd_ = os.getcwd() - os.chdir(target_folder) - fp_incar = os.path.abspath(fp_incar) - os.chdir(cwd_) - make_vasp_incar(output, fp_incar) + make_vasp_incar(fp_params, output) if fp_style == 'pwscf' : copy_pp_files(output, fp_pp_path, fp_pp_files) if fp_style == 'siesta' : diff --git a/tests/generator/out_data_post_fp_vasp/02.fp/task.000.000000/job.json b/tests/generator/out_data_post_fp_vasp/02.fp/task.000.000000/job.json index f631c57bf..e2f74b65b 100644 --- a/tests/generator/out_data_post_fp_vasp/02.fp/task.000.000000/job.json +++ b/tests/generator/out_data_post_fp_vasp/02.fp/task.000.000000/job.json @@ -1 +1 @@ -{ "temp_ele": 0 } +{ "ele_temp": 0 } diff --git a/tests/generator/out_data_post_fp_vasp/02.fp/task.000.000001/job.json b/tests/generator/out_data_post_fp_vasp/02.fp/task.000.000001/job.json index a5bb359f6..ec49f8a06 100644 --- a/tests/generator/out_data_post_fp_vasp/02.fp/task.000.000001/job.json +++ b/tests/generator/out_data_post_fp_vasp/02.fp/task.000.000001/job.json @@ -1 +1 @@ -{ "temp_ele": 1 } +{ "ele_temp": 1 } diff --git a/tests/generator/out_data_post_fp_vasp/02.fp/task.001.000000/job.json b/tests/generator/out_data_post_fp_vasp/02.fp/task.001.000000/job.json index 64ee7787b..c4924f0bd 100644 --- a/tests/generator/out_data_post_fp_vasp/02.fp/task.001.000000/job.json +++ b/tests/generator/out_data_post_fp_vasp/02.fp/task.001.000000/job.json @@ -1 +1 @@ -{ "temp_ele": 100000 } +{ "ele_temp": 100000 } diff --git a/tests/generator/out_data_post_fp_vasp/02.fp/task.001.000001/job.json b/tests/generator/out_data_post_fp_vasp/02.fp/task.001.000001/job.json index bdd3bba39..a393fb733 100644 --- a/tests/generator/out_data_post_fp_vasp/02.fp/task.001.000001/job.json +++ b/tests/generator/out_data_post_fp_vasp/02.fp/task.001.000001/job.json @@ -1 +1 @@ -{ "temp_ele": 110000 } +{ "ele_temp": 110000 } diff --git a/tests/generator/test_make_fp.py b/tests/generator/test_make_fp.py index c22801fac..20fdc51dc 100644 --- a/tests/generator/test_make_fp.py +++ b/tests/generator/test_make_fp.py @@ -47,7 +47,7 @@ KSPACING=0.16\n\ KGAMMA=F\n"; -vasp_incar_temp_ele_ref = "PREC=A\n\ +vasp_incar_ele_temp_ref = "PREC=A\n\ ENCUT=600\n\ ISYM=0\n\ ALGO=fast\n\ @@ -245,11 +245,11 @@ def _write_lammps_dump(sys, dump_file, f_idx = 0) : fp.write('%d %d %f %f %f\n' % (ii+1, atype[ii]+1, coord[ii][0], coord[ii][1], coord[ii][2])) -def _make_fake_md(idx, md_descript, atom_types, type_map, temp_ele = None) : +def _make_fake_md(idx, md_descript, atom_types, type_map, ele_temp = None) : """ md_descript: list of dimension [n_sys][n_MD][n_frame] - temp_ele: list of dimension + ele_temp: list of dimension [n_sys][n_MD] """ natoms = len(atom_types) @@ -280,9 +280,9 @@ def _make_fake_md(idx, md_descript, atom_types, type_map, temp_ele = None) : md_out[:,0] = np.arange(nframes) md_out[:,4] = mm np.savetxt(os.path.join(task_dir, 'model_devi.out'), md_out) - if temp_ele is not None: + if ele_temp is not None: with open(os.path.join(task_dir, 'job.json'), 'w') as fp: - json.dump({"temp_ele": temp_ele[sidx][midx]}, fp) + json.dump({"ele_temp": ele_temp[sidx][midx]}, fp) def _check_poscars(testCase, idx, fp_task_max, type_map) : @@ -391,7 +391,7 @@ def _check_incar(testCase, idx): testCase.assertEqual(incar.strip(), vasp_incar_ref.strip()) os.chdir(cwd) -def _check_incar_temp_ele(testCase, idx, temp_ele): +def _check_incar_ele_temp(testCase, idx, ele_temp): fp_path = os.path.join('iter.%06d' % idx, '02.fp') tasks = glob.glob(os.path.join(fp_path, 'task.*')) cwd = os.getcwd() @@ -403,8 +403,8 @@ def _check_incar_temp_ele(testCase, idx, temp_ele): with open('INCAR') as fp: incar = fp.read() incar0 = Incar.from_string(incar) - # make_fake_md: the frames in a system shares the same temp_ele - incar1 = Incar.from_string(vasp_incar_temp_ele_ref%(temp_ele[sidx][0] * pc.Boltzmann / pc.electron_volt)) + # make_fake_md: the frames in a system shares the same ele_temp + incar1 = Incar.from_string(vasp_incar_ele_temp_ref%(ele_temp[sidx][0] * pc.Boltzmann / pc.electron_volt)) for ii in incar0.keys(): # skip checking nbands... if ii == 'NBANDS': @@ -678,7 +678,7 @@ def test_make_fp_vasp_from_incar(self): # _check_potcar(self, 0, jdata['fp_pp_path'], jdata['fp_pp_files']) shutil.rmtree('iter.000000') - def test_make_fp_vasp_temp_ele(self): + def test_make_fp_vasp_ele_temp(self): ## Verify if user chooses to diy VASP INCAR totally. if os.path.isdir('iter.000000') : shutil.rmtree('iter.000000') @@ -689,7 +689,7 @@ def test_make_fp_vasp_temp_ele(self): mdata = json.load (fp) fp.close() md_descript = [] - temp_ele = [] + ele_temp = [] nsys = 2 nmd = 3 n_frame = 10 @@ -698,14 +698,14 @@ def test_make_fp_vasp_temp_ele(self): for jj in range(nmd) : tmp.append(np.arange(0, 0.29, 0.29/10)) md_descript.append(tmp) - temp_ele.append([np.random.random() * 100000] * nmd) + ele_temp.append([np.random.random() * 100000] * nmd) atom_types = [0, 1, 0, 1] type_map = jdata['type_map'] - _make_fake_md(0, md_descript, atom_types, type_map, temp_ele = temp_ele) + _make_fake_md(0, md_descript, atom_types, type_map, ele_temp = ele_temp) make_fp(0, jdata, {}) _check_sel(self, 0, jdata['fp_task_max'], jdata['model_devi_f_trust_lo'], jdata['model_devi_f_trust_hi']) _check_poscars(self, 0, jdata['fp_task_max'], jdata['type_map']) - _check_incar_temp_ele(self, 0, temp_ele) + _check_incar_ele_temp(self, 0, ele_temp) _check_kpoints_exists(self, 0) _check_kpoints(self,0) # checked elsewhere From 905e872e3e41a2900ce483e2fd30b2056a2cc91d Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 14 Oct 2019 08:18:16 +0800 Subject: [PATCH 23/93] add missing files and links --- tests/generator/out_data_nbands_esti/md.010000K/POTCAR | 1 + tests/generator/out_data_nbands_esti/md.020000K/POTCAR | 1 + tests/generator/out_data_nbands_esti/mgal/POTCAR | 1 + tests/generator/vasp/nbands_esti.out | 2 ++ 4 files changed, 5 insertions(+) create mode 120000 tests/generator/out_data_nbands_esti/md.010000K/POTCAR create mode 120000 tests/generator/out_data_nbands_esti/md.020000K/POTCAR create mode 120000 tests/generator/out_data_nbands_esti/mgal/POTCAR create mode 100644 tests/generator/vasp/nbands_esti.out diff --git a/tests/generator/out_data_nbands_esti/md.010000K/POTCAR b/tests/generator/out_data_nbands_esti/md.010000K/POTCAR new file mode 120000 index 000000000..1ff10fc0a --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.010000K/POTCAR @@ -0,0 +1 @@ +../POTCAR \ No newline at end of file diff --git a/tests/generator/out_data_nbands_esti/md.020000K/POTCAR b/tests/generator/out_data_nbands_esti/md.020000K/POTCAR new file mode 120000 index 000000000..1ff10fc0a --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.020000K/POTCAR @@ -0,0 +1 @@ +../POTCAR \ No newline at end of file diff --git a/tests/generator/out_data_nbands_esti/mgal/POTCAR b/tests/generator/out_data_nbands_esti/mgal/POTCAR new file mode 120000 index 000000000..743ba1bb9 --- /dev/null +++ b/tests/generator/out_data_nbands_esti/mgal/POTCAR @@ -0,0 +1 @@ +../POTCAR.dbl \ No newline at end of file diff --git a/tests/generator/vasp/nbands_esti.out b/tests/generator/vasp/nbands_esti.out new file mode 100644 index 000000000..58babc4e0 --- /dev/null +++ b/tests/generator/vasp/nbands_esti.out @@ -0,0 +1,2 @@ +3.6534712640497446e-08 +8.651576676279664e-09 From 1ff8cb54423f2ff1678f3cedf06a86997dda29d3 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 14 Oct 2019 09:02:30 +0800 Subject: [PATCH 24/93] add missing file --- tests/generator/out_data_nbands_esti/md.040000K/POTCAR | 1 + 1 file changed, 1 insertion(+) create mode 120000 tests/generator/out_data_nbands_esti/md.040000K/POTCAR diff --git a/tests/generator/out_data_nbands_esti/md.040000K/POTCAR b/tests/generator/out_data_nbands_esti/md.040000K/POTCAR new file mode 120000 index 000000000..1ff10fc0a --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.040000K/POTCAR @@ -0,0 +1 @@ +../POTCAR \ No newline at end of file From c7e871ecb74b4739c2bfa3511024e2753133d5b8 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 14 Oct 2019 09:05:14 +0800 Subject: [PATCH 25/93] add missing file --- tests/generator/out_data_nbands_esti/md.080000K/POTCAR | 1 + tests/generator/out_data_nbands_esti/md.160000K/POTCAR | 1 + 2 files changed, 2 insertions(+) create mode 120000 tests/generator/out_data_nbands_esti/md.080000K/POTCAR create mode 120000 tests/generator/out_data_nbands_esti/md.160000K/POTCAR diff --git a/tests/generator/out_data_nbands_esti/md.080000K/POTCAR b/tests/generator/out_data_nbands_esti/md.080000K/POTCAR new file mode 120000 index 000000000..1ff10fc0a --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.080000K/POTCAR @@ -0,0 +1 @@ +../POTCAR \ No newline at end of file diff --git a/tests/generator/out_data_nbands_esti/md.160000K/POTCAR b/tests/generator/out_data_nbands_esti/md.160000K/POTCAR new file mode 120000 index 000000000..1ff10fc0a --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.160000K/POTCAR @@ -0,0 +1 @@ +../POTCAR \ No newline at end of file From 4e056e9526cf82b94da91f9c527269a38ccf0286 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 14 Oct 2019 09:09:45 +0800 Subject: [PATCH 26/93] add missing file --- tests/generator/out_data_nbands_esti/md.240000K/POTCAR | 1 + 1 file changed, 1 insertion(+) create mode 120000 tests/generator/out_data_nbands_esti/md.240000K/POTCAR diff --git a/tests/generator/out_data_nbands_esti/md.240000K/POTCAR b/tests/generator/out_data_nbands_esti/md.240000K/POTCAR new file mode 120000 index 000000000..1ff10fc0a --- /dev/null +++ b/tests/generator/out_data_nbands_esti/md.240000K/POTCAR @@ -0,0 +1 @@ +../POTCAR \ No newline at end of file From f8b4abffaf3ab0769c6e934bea689dbab55c6c44 Mon Sep 17 00:00:00 2001 From: Silvia-liu <1362341411@qq.com> Date: Mon, 14 Oct 2019 19:28:49 +0800 Subject: [PATCH 27/93] fix_bug --- dpgen/generator/run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpgen/generator/run.py b/dpgen/generator/run.py index afd7ad352..b4c940f9e 100644 --- a/dpgen/generator/run.py +++ b/dpgen/generator/run.py @@ -1307,7 +1307,7 @@ def run_fp (iter_index, elif fp_style == "siesta": forward_files = ['input'] + fp_pp_files backward_files = ['output'] - run_fp_inner(iter_index, jdata, mdata, ssh_sess, forward_files, backward_files, _siesta_check_fin, log_file='output') + run_fp_inner(iter_index, jdata, mdata, dispatcher, forward_files, backward_files, _siesta_check_fin, log_file='output') elif fp_style == "gaussian": forward_files = ['input'] backward_files = ['output'] From e4725a1e23367bee2a8682b1ae90447820a0772f Mon Sep 17 00:00:00 2001 From: AnguseZhang <529133328@qq.con> Date: Tue, 15 Oct 2019 01:02:42 +0800 Subject: [PATCH 28/93] make slurm & decide_machine compatible with deepmdkit1.0 --- dpgen/generator/run.py | 8 ++++++- dpgen/remote/decide_machine.py | 38 +++++++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/dpgen/generator/run.py b/dpgen/generator/run.py index afd7ad352..5cb41934a 100644 --- a/dpgen/generator/run.py +++ b/dpgen/generator/run.py @@ -1600,8 +1600,14 @@ def set_version(mdata): deepmd_version = '0.1' elif 'python_path' in mdata: deepmd_version = '1' + elif 'train' in mdata: + if 'deepmd_path' in mdata['train'][0]: + deepmd_version = '0.1' + elif 'python_path' in mdata['train'][0]: + deepmd_version = '1' + else: + deepmd_version = '0.1' else: - # default deepmd_version = '0.1' # set mdata['deepmd_version'] = deepmd_version diff --git a/dpgen/remote/decide_machine.py b/dpgen/remote/decide_machine.py index 465207db6..3a0e3ecf3 100644 --- a/dpgen/remote/decide_machine.py +++ b/dpgen/remote/decide_machine.py @@ -21,18 +21,28 @@ def decide_train_machine(mdata): if profile['purpose'] == 'train': mdata['train_machine'] = profile['machine'] mdata['train_resources'] = profile['resources'] - mdata['deepmd_path'] = profile['deepmd_path'] + if 'deepmd_path' in profile: + mdata['deepmd_path'] = profile['deepmd_path'] + elif 'python_path' in profile: + mdata['python_path'] = profile['python_path'] if "group_size" in profile: mdata["train_group_size"] = profile["group_size"] + if 'deepmd_version' in profile: + mdata["deepmd_version"] = profile['deepmd_version'] continue_flag = True except: pass if "hostname" not in mdata["train"][0]["machine"]: mdata["train_machine"] = mdata["train"][0]["machine"] mdata["train_resources"] = mdata["train"][0]["resources"] - mdata["deepmd_path"] = mdata["train"][0]["deepmd_path"] + if 'deepmd_path' in mdata["train"][0]: + mdata["deepmd_path"] = mdata["train"][0]["deepmd_path"] + elif 'python_path' in mdata["train"][0]: + mdata["python_path"] = mdata["train"][0]["python_path"] if "group_size" in mdata["train"][0]: mdata["train_group_size"] = mdata["train"][0]["group_size"] + if 'deepmd_version' in mdata["train"][0]: + mdata["deepmd_version"] = mdata["train"][0]["deepmd_version"] continue_flag = True pd_flag = False @@ -61,7 +71,15 @@ def decide_train_machine(mdata): if pd_count ==1: mdata['train_machine'] = temp_machine mdata['train_resources'] = temp_resources - mdata['deepmd_path'] = mdata['train'][machine_idx]['deepmd_path'] + if 'deepmd_path' in mdata['train'][machine_idx]: + mdata['deepmd_path'] = mdata['train'][machine_idx]['deepmd_path'] + elif 'python_path' in mdata['train'][machine_idx]: + mdata['python_path'] = mdata['train'][machine_idx]['python_path'] + if 'group_size' in mdata['train'][machine_idx]: + mdata['train_group_size'] = mdata['train'][machine_idx]['group_size'] + if 'deepmd_version' in mdata['train'][machine_idx]: + mdata['deepmd_version'] = mdata['train'][machine_idx]['deepmd_version'] + ## No need to wait pd_flag = True break @@ -73,9 +91,14 @@ def decide_train_machine(mdata): min_machine_idx = np.argsort(pd_count_list)[0] mdata['train_machine'] = mdata['train'][min_machine_idx]['machine'] mdata['train_resources'] = mdata['train'][min_machine_idx]['resources'] - mdata['deepmd_path'] = mdata['train'][min_machine_idx]['deepmd_path'] + if 'deepmd_path' in mdata['train'][min_machine_idx]: + mdata['deepmd_path'] = mdata['train'][min_machine_idx]['deepmd_path'] + elif 'python_path' in mdata['train'][min_machine_idx]: + mdata['python_path'] = mdata['train'][min_machine_idx]['python_path'] if "group_size" in mdata['train'][min_machine_idx]: mdata["train_group_size"] = mdata['train'][min_machine_idx]["group_size"] + if 'deepmd_version' in mdata['train'][min_machine_idx]: + mdata['deepmd_version'] = mdata['train'][min_machine_idx]["deepmd_version"] ## Record which machine is selected with open("record.machine","w") as _outfile: @@ -83,9 +106,14 @@ def decide_train_machine(mdata): profile['purpose'] = 'train' profile['machine'] = mdata['train_machine'] profile['resources'] = mdata['train_resources'] - profile['deepmd_path'] = mdata['deepmd_path'] + if 'deepmd_path' in mdata: + profile['deepmd_path'] = mdata['deepmd_path'] + elif 'python_path' in mdata: + profile['python_path'] = mdata['python_path'] if "train_group_size" in mdata: profile["group_size"] = mdata["train_group_size"] + if 'deepmd_version' in mdata: + profile['deepmd_version'] = mdata['deepmd_version'] json.dump(profile, _outfile, indent = 4) return mdata From 82acbde7b91cec357cc8c71c79e8504da53e9d12 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Mon, 14 Oct 2019 13:21:51 -0400 Subject: [PATCH 29/93] remove extra comma --- examples/run/dp_lammps_gaussian/dodecane/dodecane.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/run/dp_lammps_gaussian/dodecane/dodecane.json b/examples/run/dp_lammps_gaussian/dodecane/dodecane.json index 74f6678d3..12b15f7b7 100644 --- a/examples/run/dp_lammps_gaussian/dodecane/dodecane.json +++ b/examples/run/dp_lammps_gaussian/dodecane/dodecane.json @@ -58,7 +58,7 @@ "time_training": true, "profiling": false, "profiling_file": "timeline.json" - }, + } }, "use_clusters": true, "cluster_cutoff": 3.5, From 348724d49f2b5baf744b8b67560995152884cda4 Mon Sep 17 00:00:00 2001 From: AnguseZhang <529133328@qq.con> Date: Tue, 15 Oct 2019 11:03:04 +0800 Subject: [PATCH 30/93] make init_data compatible with dispatcher --- dpgen/data/gen.py | 189 +++++++-------------------------- dpgen/dispatcher/Dispatcher.py | 21 ++++ dpgen/generator/run.py | 25 +---- 3 files changed, 60 insertions(+), 175 deletions(-) diff --git a/dpgen/data/gen.py b/dpgen/data/gen.py index 37cc9090f..bd9368854 100644 --- a/dpgen/data/gen.py +++ b/dpgen/data/gen.py @@ -25,6 +25,7 @@ from dpgen.remote.decide_machine import decide_train_machine, decide_fp_machine, decide_model_devi_machine from dpgen.remote.RemoteJob import SSHSession, JobStatus, SlurmJob, PBSJob, CloudMachineJob from dpgen import ROOT_PATH +#from dpgen.dispatcher.Dispatcher import Dispatcher, make_dispatcher @@ -289,19 +290,7 @@ def place_element (jdata) : def make_vasp_relax (jdata, mdata) : out_dir = jdata['out_dir'] potcars = jdata['potcars'] - #encut = jdata['encut'] - #kspacing = jdata['kspacing_relax'] - #kgamma = jdata['kgamma'] - #ismear = 1 - #if 'ismear' in jdata : - # ismear = jdata['ismear'] - #sigma = 0.2 - #if 'sigma' in jdata : - # sigma = jdata['sigma'] cwd = os.getcwd() - - #vasp_dir = os.path.join(cwd, 'vasp.in') - work_dir = os.path.join(out_dir, global_dirname_02) assert (os.path.isdir(work_dir)) work_dir = os.path.abspath(work_dir) @@ -602,11 +591,11 @@ def _group_slurm_jobs(ssh_sess, job_fin[idx] = True time.sleep(10) -def run_vasp_relax(jdata, mdata, ssh_sess): +def run_vasp_relax(jdata, mdata, dispatcher): fp_command = mdata['fp_command'] fp_group_size = mdata['fp_group_size'] fp_resources = mdata['fp_resources'] - machine_type = mdata['fp_machine']['machine_type'] + #machine_type = mdata['fp_machine']['machine_type'] work_dir = os.path.join(jdata['out_dir'], global_dirname_02) forward_files = ["POSCAR", "INCAR", "POTCAR"] @@ -622,29 +611,28 @@ def run_vasp_relax(jdata, mdata, ssh_sess): if len(relax_tasks) == 0: return - relax_run_tasks = [] - for ii in relax_tasks : - if not _vasp_check_fin(ii): - relax_run_tasks.append(ii) + relax_run_tasks = relax_tasks + #for ii in relax_tasks : + # if not _vasp_check_fin(ii): + # relax_run_tasks.append(ii) run_tasks = [os.path.basename(ii) for ii in relax_run_tasks] #dlog.info(run_tasks) - assert (machine_type == "slurm" or machine_type =="Slurm"), "Currently only support for Slurm!" - _group_slurm_jobs(ssh_sess, - fp_resources, - fp_command, - work_dir, - run_tasks, - fp_group_size, - forward_common_files, - forward_files, - backward_files) + #assert (machine_type == "slurm" or machine_type =="Slurm"), "Currently only support for Slurm!" + dispatcher.run_jobs(fp_resources, + [fp_command], + work_dir, + run_tasks, + fp_group_size, + forward_common_files, + forward_files, + backward_files) def run_vasp_md(jdata, mdata, ssh_sess): fp_command = mdata['fp_command'] fp_group_size = mdata['fp_group_size'] fp_resources = mdata['fp_resources'] - machine_type = mdata['fp_machine']['machine_type'] + #machine_type = mdata['fp_machine']['machine_type'] work_dir = os.path.join(jdata['out_dir'], global_dirname_04) scale = jdata['scale'] pert_numb = jdata['pert_numb'] @@ -667,26 +655,24 @@ def run_vasp_md(jdata, mdata, ssh_sess): if len(md_tasks) == 0: return - md_run_tasks = [] - for ii in md_tasks : - if not _vasp_check_fin(ii): - md_run_tasks.append(ii) - + md_run_tasks = md_tasks + #for ii in md_tasks : + # if not _vasp_check_fin(ii): + # md_run_tasks.append(ii) run_tasks = [ii.replace(work_dir+"/", "") for ii in md_run_tasks] #dlog.info("md_work_dir", work_dir) #dlog.info("run_tasks",run_tasks) - assert (machine_type == "slurm" or machine_type =="Slurm"), "Currently only support for Slurm!" - _group_slurm_jobs(ssh_sess, - fp_resources, - fp_command, - work_dir, - run_tasks, - fp_group_size, - forward_common_files, - forward_files, - backward_files) + #assert (machine_type == "slurm" or machine_type =="Slurm"), "Currently only support for Slurm!" + dispatcher.run_jobs(fp_resources, + [fp_command], + work_dir, + run_tasks, + fp_group_size, + forward_common_files, + forward_files, + backward_files) @@ -711,8 +697,9 @@ def gen_init_bulk(args) : if args.MACHINE is not None: # Selecting a proper machine mdata = decide_fp_machine(mdata) - fp_machine = mdata['fp_machine'] - fp_ssh_sess = SSHSession(fp_machine) + disp = make_dispatcher(mdata["fp_machine"]) + #fp_machine = mdata['fp_machine'] + #fp_ssh_sess = SSHSession(fp_machine) # Decide work path out_dir = out_dir_name(jdata) jdata['out_dir'] = out_dir @@ -768,108 +755,7 @@ def gen_init_bulk(args) : place_element(jdata) if args.MACHINE is not None: make_vasp_relax(jdata, mdata) - run_vasp_relax(jdata, mdata, fp_ssh_sess) - else: - make_vasp_relax(jdata, {"fp_resources":{}}) - elif stage == 2 : - dlog.info("Current stage is 2, perturb and scale") - make_scale(jdata) - pert_scaled(jdata) - elif stage == 3 : - dlog.info("Current stage is 3, run a short md") - make_vasp_md(jdata) - if args.MACHINE is not None: - run_vasp_md(jdata, mdata, fp_ssh_sess) - elif stage == 4 : - dlog.info("Current stage is 4, collect data") - coll_vasp_md(jdata) - else : - raise RuntimeError("unknown stage %d" % stage) - -def _main() : - parser = argparse.ArgumentParser( - description="gen init confs") - parser.add_argument('PARAM', type=str, - help="parameter file, json/yaml format") - parser.add_argument("MACHINE", type=str, default=None,nargs="?", - help="The settings of the machine running the generator") - args = parser.parse_args() - - try: - import ruamel - from monty.serialization import loadfn,dumpfn - warnings.simplefilter('ignore', ruamel.yaml.error.MantissaNoDotYAML1_1Warning) - jdata=loadfn(args.PARAM) - if args.MACHINE is not None: - mdata=loadfn(args.MACHINE) - except: - with open (args.PARAM, 'r') as fp : - jdata = json.load (fp) - if args.MACHINE is not None: - with open (args.MACHINE, "r") as fp: - mdata = json.load(fp) - if args.MACHINE is not None: - # Selecting a proper machine - mdata = decide_fp_machine(mdata) - fp_machine = mdata['fp_machine'] - fp_ssh_sess = SSHSession(fp_machine) - # Decide work path - out_dir = out_dir_name(jdata) - jdata['out_dir'] = out_dir - dlog.info ("# working dir %s" % out_dir) - # Decide whether to use a given poscar - from_poscar = False - if 'from_poscar' in jdata : - from_poscar = jdata['from_poscar'] - # Verify md_nstep - md_nstep_jdata = jdata["md_nstep"] - try: - md_incar = jdata['md_incar'] - if os.path.isfile(md_incar): - with open(md_incar , "r") as fr: - md_incar_lines = fr.readlines() - nsw_flag = False - for incar_line in md_incar_lines: - line = incar_line.split() - if "NSW" in line: - nsw_flag = True - nsw_steps = int(incar_line.split()[-1]) - break - #dlog.info("nsw_steps is", nsw_steps) - #dlog.info("md_nstep_jdata is", md_nstep_jdata) - if nsw_flag: - if (nsw_steps != md_nstep_jdata): - dlog.info("WARNING: your set-up for MD steps in PARAM and md_incar are not consistent!") - dlog.info("MD steps in PARAM is %d"%(md_nstep_jdata)) - dlog.info("MD steps in md_incar is %d"(nsw_steps)) - dlog.info("DP-GEN will use settings in md_incar!") - jdata['md_nstep'] = nsw_steps - except: - pass - ## correct element name - temp_elements = [] - for ele in jdata['elements']: - temp_elements.append(ele[0].upper() + ele[1:]) - jdata['elements'] = temp_elements - dlog.info("Elements are %s"%(' '.join(jdata['elements']))) - - ## Iteration - stage_list = [int(i) for i in jdata['stages']] - for stage in stage_list: - if stage == 1 : - dlog.info("Current stage is 1, relax") - create_path(out_dir) - shutil.copy2(args.PARAM, os.path.join(out_dir, 'param.json')) - if from_poscar : - make_super_cell_poscar(jdata) - else : - make_unit_cell(jdata) - make_super_cell(jdata) - place_element(jdata) - - if args.MACHINE is not None: - make_vasp_relax(jdata, mdata) - run_vasp_relax(jdata, mdata, fp_ssh_sess) + run_vasp_relax(jdata, mdata, disp) else: make_vasp_relax(jdata, {"fp_resources":{}}) elif stage == 2 : @@ -880,12 +766,9 @@ def _main() : dlog.info("Current stage is 3, run a short md") make_vasp_md(jdata) if args.MACHINE is not None: - run_vasp_md(jdata, mdata, fp_ssh_sess) + run_vasp_md(jdata, mdata, disp) elif stage == 4 : dlog.info("Current stage is 4, collect data") coll_vasp_md(jdata) else : - raise RuntimeError("unknown stage %d" % stage) - -if __name__ == "__main__": - _main() + raise RuntimeError("unknown stage %d" % stage) \ No newline at end of file diff --git a/dpgen/dispatcher/Dispatcher.py b/dpgen/dispatcher/Dispatcher.py index 1774c08db..39a988543 100644 --- a/dpgen/dispatcher/Dispatcher.py +++ b/dpgen/dispatcher/Dispatcher.py @@ -205,3 +205,24 @@ def delete(self): os.remove(f_path_map) except: pass + +def make_dispatcher(mdata): + try: + hostname = mdata['hostname'] + context_type = 'ssh' + except: + context_type = 'local' + try: + batch_type = mdata['batch'] + except: + dlog.info('cannot find key "batch" in machine file, try to use deprecated key "machine_type"') + batch_type = mdata['machine_type'] + try: + lazy_local = mdata['lazy_local'] + except: + lazy_local = False + if lazy_local and context_type == 'local': + dlog.info('Dispatcher switches to the lazy local mode') + context_type = 'lazy-local' + disp = Dispatcher(mdata, context_type=context_type, batch_type=batch_type) + return disp diff --git a/dpgen/generator/run.py b/dpgen/generator/run.py index 5cb41934a..9228f8cf2 100644 --- a/dpgen/generator/run.py +++ b/dpgen/generator/run.py @@ -49,7 +49,7 @@ from dpgen.remote.group_jobs import group_slurm_jobs from dpgen.remote.group_jobs import group_local_jobs from dpgen.remote.decide_machine import decide_train_machine, decide_fp_machine, decide_model_devi_machine -from dpgen.dispatcher.Dispatcher import Dispatcher +from dpgen.dispatcher.Dispatcher import Dispatcher, make_dispatcher from dpgen.util import sepline from dpgen import ROOT_PATH from pymatgen.io.vasp import Incar,Kpoints,Potcar @@ -841,7 +841,7 @@ def _make_fp_vasp_inner (modd_path, dump_to_poscar('conf.dump', 'POSCAR', type_map) os.chdir(cwd) return fp_tasks - + def make_vasp_incar(jdata, filename): if 'fp_incar' in jdata.keys() : fp_incar_path = jdata['fp_incar'] @@ -1614,26 +1614,7 @@ def set_version(mdata): return mdata -def make_dispatcher(mdata): - try: - hostname = mdata['hostname'] - context_type = 'ssh' - except: - context_type = 'local' - try: - batch_type = mdata['batch'] - except: - dlog.info('cannot find key "batch" in machine file, try to use deprecated key "machine_type"') - batch_type = mdata['machine_type'] - try: - lazy_local = mdata['lazy_local'] - except: - lazy_local = False - if lazy_local and context_type == 'local': - dlog.info('Dispatcher switches to the lazy local mode') - context_type = 'lazy-local' - disp = Dispatcher(mdata, context_type=context_type, batch_type=batch_type) - return disp + def run_iter (param_file, machine_file) : From 599fefb4cab4a787956fbaf40de52c225811b34a Mon Sep 17 00:00:00 2001 From: AnguseZhang <529133328@qq.con> Date: Tue, 15 Oct 2019 11:05:06 +0800 Subject: [PATCH 31/93] make init_data compatible with dispatcher --- dpgen/data/gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpgen/data/gen.py b/dpgen/data/gen.py index bd9368854..5c0454300 100644 --- a/dpgen/data/gen.py +++ b/dpgen/data/gen.py @@ -25,7 +25,7 @@ from dpgen.remote.decide_machine import decide_train_machine, decide_fp_machine, decide_model_devi_machine from dpgen.remote.RemoteJob import SSHSession, JobStatus, SlurmJob, PBSJob, CloudMachineJob from dpgen import ROOT_PATH -#from dpgen.dispatcher.Dispatcher import Dispatcher, make_dispatcher +from dpgen.dispatcher.Dispatcher import Dispatcher, make_dispatcher From 7d2a22daf2f2b8a9526305af115d237b24203de9 Mon Sep 17 00:00:00 2001 From: AnguseZhang <529133328@qq.con> Date: Tue, 15 Oct 2019 11:23:36 +0800 Subject: [PATCH 32/93] Make init_bulk compatible with dispatcher --- dpgen/data/gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpgen/data/gen.py b/dpgen/data/gen.py index 5c0454300..0a8e4efab 100644 --- a/dpgen/data/gen.py +++ b/dpgen/data/gen.py @@ -628,7 +628,7 @@ def run_vasp_relax(jdata, mdata, dispatcher): forward_files, backward_files) -def run_vasp_md(jdata, mdata, ssh_sess): +def run_vasp_md(jdata, mdata, dispatcher): fp_command = mdata['fp_command'] fp_group_size = mdata['fp_group_size'] fp_resources = mdata['fp_resources'] From b4fa2496665cefe1ad9acee9140c1be87c43c474 Mon Sep 17 00:00:00 2001 From: AnguseZhang <529133328@qq.com> Date: Tue, 15 Oct 2019 11:40:15 +0800 Subject: [PATCH 33/93] Update Readme & Machine in init_bulk can be None --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index da2fe8427..bf7cf0acf 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,8 @@ Basically `init_bulk` can be devided into four parts , denoted as `stages` in `P All stages must be **in order**. One doesn't need to run all stages. For example, you may run stage 1 and 2, generating supercells as starting point of exploration in `dpgen run`. +If MACHINE is None, there should be only one stage in stages. Corresponding tasks will be generated, but user's intervention should be involved in, to manunally run the scripts. + Following is an example for `PARAM`, which generates data from a typical structure hcp. ```json { From d526ef492fe30f93e301205349dd2d752a3df046 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 15 Oct 2019 20:33:15 +0800 Subject: [PATCH 34/93] support atom param --- dpgen/generator/lib/lammps.py | 17 +++++++---- dpgen/generator/run.py | 53 +++++++++++++++++++++++++-------- tests/generator/test_post_fp.py | 12 ++++++-- 3 files changed, 62 insertions(+), 20 deletions(-) diff --git a/dpgen/generator/lib/lammps.py b/dpgen/generator/lib/lammps.py index 4921b3771..367817a89 100644 --- a/dpgen/generator/lib/lammps.py +++ b/dpgen/generator/lib/lammps.py @@ -28,17 +28,22 @@ def make_lammps_input(ensemble, pres = None, tau_p = 0.5, pka_e = None, - ele_temp = None, + ele_temp_f = None, + ele_temp_a = None, max_seed = 1000000, deepmd_version = '0.1') : - if ele_temp is not None and LooseVersion(deepmd_version) < LooseVersion('1'): + if (ele_temp_f is not None or ele_temp_a is not None) and LooseVersion(deepmd_version) < LooseVersion('1'): raise RuntimeError('the electron temperature is only supported by deepmd-kit >= 1.0.0, please upgrade your deepmd-kit') + if ele_temp_f is not None and ele_temp_a is not None: + raise RuntimeError('the frame style ele_temp and atom style ele_temp should not be set at the same time') ret = "variable NSTEPS equal %d\n" % nsteps ret+= "variable THERMO_FREQ equal %d\n" % trj_freq ret+= "variable DUMP_FREQ equal %d\n" % trj_freq ret+= "variable TEMP equal %f\n" % temp - if ele_temp is not None: - ret+= "variable ELE_TEMP equal %f\n" % ele_temp + if ele_temp_f is not None: + ret+= "variable ELE_TEMP equal %f\n" % ele_temp_f + if ele_temp_a is not None: + ret+= "variable ELE_TEMP equal %f\n" % ele_temp_a ret+= "variable PRES equal %f\n" % pres ret+= "variable TAU_T equal %f\n" % tau_t ret+= "variable TAU_P equal %f\n" % tau_p @@ -70,8 +75,10 @@ def make_lammps_input(ensemble, if jdata.get('use_relative', False): eps = jdata.get('eps', 0.) keywords += "relative %s " % jdata['epsilon'] - if ele_temp is not None: + if ele_temp_f is not None: keywords += "fparam ${ELE_TEMP}" + if ele_temp_a is not None: + keywords += "aparam ${ELE_TEMP}" ret+= "pair_style deepmd %s out_freq ${THERMO_FREQ} out_file model_devi.out %s\n" % (graph_list, keywords) ret+= "pair_coeff \n" ret+= "\n" diff --git a/dpgen/generator/run.py b/dpgen/generator/run.py index afd7ad352..81f96030b 100644 --- a/dpgen/generator/run.py +++ b/dpgen/generator/run.py @@ -185,7 +185,7 @@ def make_train (iter_index, init_data_sys_ = jdata['init_data_sys'] fp_task_min = jdata['fp_task_min'] model_devi_jobs = jdata['model_devi_jobs'] - use_ele_temp = jdata.get('use_ele_temp', False) + use_ele_temp = jdata.get('use_ele_temp', 0) if iter_index > 0 and _check_empty_iter(iter_index-1, fp_task_min) : log_task('prev data is empty, copy prev model') @@ -278,9 +278,15 @@ def make_train (iter_index, # 1.x jinput['training']['systems'] = init_data_sys jinput['training']['batch_size'] = init_batch_size - if use_ele_temp: - # fparam for electron temperature + # electron temperature + if use_ele_temp == 1: jinput['model']['fitting_net']['numb_fparam'] = 1 + jinput['model']['fitting_net'].pop('numb_aparam', None) + elif use_ele_temp == 2: + jinput['model']['fitting_net']['numb_aparam'] = 1 + jinput['model']['fitting_net'].pop('numb_fparam', None) + else: + raise RuntimeError('invalid setting for use_ele_temp') for ii in range(numb_models) : task_path = os.path.join(work_path, train_task_fmt % ii) create_path(task_path) @@ -487,7 +493,7 @@ def parse_cur_job(cur_job) : def make_model_devi (iter_index, jdata, mdata) : - use_ele_temp = jdata.get('use_ele_temp', False) + use_ele_temp = jdata.get('use_ele_temp', 0) model_devi_dt = jdata['model_devi_dt'] model_devi_neidelay = None if 'model_devi_neidelay' in jdata : @@ -585,14 +591,25 @@ def make_model_devi (iter_index, if use_ele_temp: if type(tt_) == list: tt = tt_[0] - te = tt_[1] + if use_ele_temp == 1: + te_f = tt_[1] + te_a = None + else: + te_f = None + te_a = tt_[1] else: assert(type(tt_) == float or type(tt_) == int) tt = float(tt_) - te = tt + if use_ele_temp == 1: + te_f = tt + te_a = None + else: + te_f = None + te_a = tt else : tt = tt_ - te = None + te_f = None + te_a = None for pp in press: task_name = make_model_devi_task_name(sys_idx[sys_counter], task_counter) conf_name = make_model_devi_conf_name(sys_idx[sys_counter], conf_counter) + '.lmp' @@ -624,14 +641,17 @@ def make_model_devi (iter_index, pres = pp, tau_p = model_devi_taup, pka_e = pka_e, - ele_temp = te, + ele_temp_f = te_f, + ele_temp_a = te_a, deepmd_version = deepmd_version) job = {} job["ensemble"] = ensemble job["press"] = pp job["temps"] = tt - if te is not None: - job["ele_temp"] = te + if te_f is not None: + job["ele_temp"] = te_f + if te_a is not None: + job["ele_temp"] = te_a job["model_devi_dt"] = model_devi_dt with open('job.json', 'w') as _outfile: json.dump(job, _outfile, indent = 4) @@ -1327,6 +1347,7 @@ def post_fp_vasp (iter_index, ratio_failed = rfailed if rfailed else jdata.get('ratio_failed',0.05) model_devi_jobs = jdata['model_devi_jobs'] assert (iter_index < len(model_devi_jobs)) + use_ele_temp = jdata.get('use_ele_temp', 0) iter_name = make_iter_name(iter_index) work_path = os.path.join(iter_name, fp_name) @@ -1372,6 +1393,7 @@ def post_fp_vasp (iter_index, with open(oo.replace('OUTCAR', 'job.json')) as fp: job_data = json.load(fp) if 'ele_temp' in job_data: + assert(use_ele_temp) ele_temp = job_data['ele_temp'] all_te.append(ele_temp) else: @@ -1385,8 +1407,15 @@ def post_fp_vasp (iter_index, assert(len(all_sys) == all_sys.get_nframes()) assert(len(all_sys) == all_te.size) all_te = np.reshape(all_te, [-1,1]) - np.savetxt(os.path.join(sys_data_path, 'fparam.raw'), all_te) - np.save(os.path.join(sys_data_path, 'set.000', 'fparam.npy'), all_te) + if use_ele_temp == 1: + np.savetxt(os.path.join(sys_data_path, 'fparam.raw'), all_te) + np.save(os.path.join(sys_data_path, 'set.000', 'fparam.npy'), all_te) + elif use_ele_temp == 2: + tile_te = np.tile(all_te, [1, all_sys.get_natoms()]) + np.savetxt(os.path.join(sys_data_path, 'aparam.raw'), tile_te) + np.save(os.path.join(sys_data_path, 'set.000', 'aparam.npy'), tile_te) + else: + raise RuntimeError('invalid setting of use_ele_temp ' + use_ele_temp) dlog.info("failed frame number: %s "%icount) dlog.info("total frame number: %s "%tcount) diff --git a/tests/generator/test_post_fp.py b/tests/generator/test_post_fp.py index 526c05951..652f627ab 100644 --- a/tests/generator/test_post_fp.py +++ b/tests/generator/test_post_fp.py @@ -63,6 +63,7 @@ def test_post_fp_vasp_0(self): with open (param_file, 'r') as fp : jdata = json.load (fp) + jdata['use_ele_temp'] = 2 post_fp_vasp(0, jdata, rfailed=0.3) sys = dpdata.LabeledSystem('iter.000000/02.fp/data.000/', fmt = 'deepmd/raw') @@ -98,15 +99,19 @@ def test_post_fp_vasp_0(self): self.assertAlmostEqual(ref_cell[ff][ii][jj], sys.data['cells'][ff][ii][jj]) - fparam = np.load('iter.000000/02.fp/data.000/set.000/fparam.npy') - self.assertEqual(fparam.shape[0], 2) - self.assertEqual(list(fparam), [0, 1]) + self.assertTrue(os.path.isfile('iter.000000/02.fp/data.000/set.000/aparam.npy')) + aparam = np.load('iter.000000/02.fp/data.000/set.000/aparam.npy') + natoms = sys.get_natoms() + self.assertEqual(natoms, 2) + self.assertEqual(list(list(aparam)[0]), [0,0]) + self.assertEqual(list(list(aparam)[1]), [1,1]) def test_post_fp_vasp_1(self): with open (param_file, 'r') as fp : jdata = json.load (fp) + jdata['use_ele_temp'] = 1 post_fp_vasp(0, jdata, rfailed=0.3) sys = dpdata.LabeledSystem('iter.000000/02.fp/data.001/', fmt = 'deepmd/raw') @@ -150,6 +155,7 @@ def test_post_fp_vasp_1(self): def test_post_fp_vasp_2(self): with open (param_file, 'r') as fp : jdata = json.load (fp) + jdata['use_ele_temp'] = 1 with self.assertRaises(RuntimeError): post_fp_vasp(0, jdata) From 9cb3b48fed2c3ec9baffd12f2a16771ec8fa2581 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 15 Oct 2019 20:34:48 +0800 Subject: [PATCH 35/93] example for atom param --- .../run/dp-lammps-vasp-et/param_elet.json | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 examples/run/dp-lammps-vasp-et/param_elet.json diff --git a/examples/run/dp-lammps-vasp-et/param_elet.json b/examples/run/dp-lammps-vasp-et/param_elet.json new file mode 100644 index 000000000..b0f08c7cd --- /dev/null +++ b/examples/run/dp-lammps-vasp-et/param_elet.json @@ -0,0 +1,104 @@ +{ + "type_map": ["Al", "Mg"], + "mass_map": [27, 24], + "use_ele_temp": 2, + + "init_data_prefix": "/home/wanghan/study/deep.md/data/almgop.20/init//", + + "init_data_sys": [ + "al.fcc.01x01x01/02.md/sys-0004/deepmd", + "mg.fcc.01x01x01/02.md/sys-0004/deepmd" + ], + "init_batch_size": [1,1], + "sys_configs": [ + ["/home/wanghan/study/deep.md/data/almgop.20/init/al.fcc.02x02x02/01.scale_pert/sys-0032/scale-1.000/00000[0-4]/POSCAR"], + ["/home/wanghan/study/deep.md/data/almgop.20/init/mg.fcc.02x02x02/01.scale_pert/sys-0032/scale-1.000/00000[0-4]/POSCAR"] + ], + "sys_batch_size": [1,1], + + "_comment": " 00.train ", + "numb_models": 4, + "default_training_param" : { + "_comment": " model parameters", + "model" : { + "descriptor": { + "type": "se_a", + "sel": [90, 90], + "rcut_smth": 1.80, + "rcut": 6.00, + "neuron": [10, 20, 40], + "resnet_dt": false, + "axis_neuron": 4, + "seed": 1 + }, + "fitting_net" : { + "neuron": [120, 120, 120], + "resnet_dt": true, + "numb_fparam": 10, + "seed": 1 + } + }, + + "loss" : { + "start_pref_e": 0.02, + "limit_pref_e": 1, + "start_pref_f": 1000, + "limit_pref_f": 1, + "start_pref_v": 0, + "limit_pref_v": 0 + }, + + "learning_rate" : { + "start_lr": 0.001, + "decay_steps": 5000, + "decay_rate": 0.95 + }, + + "_comment": " traing controls", + "training" : { + "systems": [], + "set_prefix": "set", + "stop_batch": 1000, + "batch_size": 1, + + "seed": 1, + + "_comment": " display and restart", + "_comment": " frequencies counted in batch", + "disp_file": "lcurve.out", + "disp_freq": 1000, + "numb_test": 1, + "save_freq": 1000, + "save_ckpt": "model.ckpt", + "load_ckpt": "model.ckpt", + "disp_training":true, + "time_training":true, + "profiling": false, + "profiling_file": "timeline.json" + }, + "_comment": "that's all" + }, + + "_comment": " 01.model_devi ", + "_comment": "model_devi_skip: the first x of the recorded frames", + "model_devi_dt": 0.002, + "model_devi_skip": 0, + "model_devi_f_trust_lo": 0.05, + "model_devi_f_trust_hi": 0.20, + "model_devi_e_trust_lo": 1e10, + "model_devi_e_trust_hi": 1e10, + "model_devi_clean_traj": false, + "model_devi_jobs": [ + { "_idx": 0, "ensemble": "npt", "nsteps": 50, "press": [1.0,2.0], "sys_idx": [0, 1], "temps": [50,100], "trj_freq": 10 } + ], + "_comment": " 02.fp ", + "fp_style": "vasp", + "shuffle_poscar": false, + "fp_task_max": 8, + "fp_task_min": 2, + "fp_pp_path": "/home/wanghan/study/deep.md/dpgen/almg/vasp", + "fp_pp_files": ["POTCAR.Al", "POTCAR.Mg"], + "fp_incar": "/home/wanghan/study/deep.md/dpgen/almg/vasp/INCAR", + "_comment": " that's all " +} + From 603ac8475e57f29897509dd05de57c4296c3b47c Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 15 Oct 2019 20:41:07 +0800 Subject: [PATCH 36/93] readme for electron temperature --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index da2fe8427..29b29a2ed 100644 --- a/README.md +++ b/README.md @@ -431,6 +431,7 @@ The bold notation of key (such aas **type_map**) means that it's a necessary key | *#Basics* | **type_map** | List of string | ["H", "C"] | Atom types | **mass_map** | List of float | [1, 12] | Standard atom weights. +| **use_ele_temp** | int | 0 | Currently only support fp_style vasp. 0(default): no electron temperature. 1: eletron temperature as frame parameter. 2: electron temperature as atom parameter. | *#Data* | init_data_prefix | String | "/sharedext4/.../data/" | Prefix of initial data directories | ***init_data_sys*** | List of string|["CH4.POSCAR.01x01x01/.../deepmd"] |Directories of initial data. You may use either absolute or relative path here. From 523f5d348da628c2bdca6d8622692397c0bdb506 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 15 Oct 2019 21:33:35 +0800 Subject: [PATCH 37/93] unittest for make_train for deepmd-kit > v1.0, test fparam and aparam --- tests/generator/context.py | 2 + tests/generator/machine-local-v1.json | 49 +++++++++++++ tests/generator/param-mg-vasp-v1.json | 101 ++++++++++++++++++++++++++ tests/generator/test_make_train.py | 76 ++++++++++++++++++- 4 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 tests/generator/machine-local-v1.json create mode 100644 tests/generator/param-mg-vasp-v1.json diff --git a/tests/generator/context.py b/tests/generator/context.py index 7a4302212..b12dd8ddf 100644 --- a/tests/generator/context.py +++ b/tests/generator/context.py @@ -6,6 +6,7 @@ from dpgen.generator.lib.ele_temp import NBandsEsti param_file = 'param-mg-vasp.json' +param_file_v1 = 'param-mg-vasp-v1.json' param_old_file = 'param-mg-vasp-old.json' param_pwscf_file = 'param-pyridine-pwscf.json' param_pwscf_old_file = 'param-pyridine-pwscf-old.json' @@ -13,6 +14,7 @@ param_siesta_file = 'param-pyridine-siesta.json' param_cp2k_file = 'param-pyridine-cp2k.json' machine_file = 'machine-local.json' +machine_file_v1 = 'machine-local-v1.json' param_diy_file = 'param-mg-vasp-diy.json' def my_file_cmp(test, f0, f1): diff --git a/tests/generator/machine-local-v1.json b/tests/generator/machine-local-v1.json new file mode 100644 index 000000000..7079678e8 --- /dev/null +++ b/tests/generator/machine-local-v1.json @@ -0,0 +1,49 @@ +{ + "train_machine": { + "machine_type": "shell", + "lazy_local": true + }, + "train_resources": { + "numb_node": 1, + "numb_gpu": 0, + "task_per_node": 4, + "exclude_list": [], + "source_list": ["/home/wanghan/study/deep.md/venvs/py3.6-tf1.8/bin/active"], + "envs" : { + }, + "_comment": "that's All" + }, + "python_path": "/home/wanghan/study/deep.md/venvs/py3.6-tf1.8/bin/python", + + "model_devi_machine": { + "machine_type": "shell", + "work_path": "/home/wanghan/study/deep.md/dpgen/almg/tmp" + }, + "model_devi_resources": { + "numb_node": 1, + "task_per_node": 4, + "with_mpi": true, + "module_list" : ["mpi"], + "exclude_list": [], + "source_list": [], + "_comment": "that's All" + }, + "lmp_command": "/home/wanghan/local/bin/lmp_mpi_1_1_0", + "model_devi_group_size": 10, + + "fp_machine": { + "machine_type": "shell", + "work_path": "/home/wanghan/study/deep.md/dpgen/almg/tmp" + }, + "fp_resources": { + "cvasp": false, + "task_per_node": 4, + "exclude_list": [], + "with_mpi": true, + "module_list" : ["mpi"], + "source_list": [], + "_comment": "that's All" + }, + "fp_command": "/home/wanghan/local/bin/vasp_std", + "fp_group_size": 5 +} diff --git a/tests/generator/param-mg-vasp-v1.json b/tests/generator/param-mg-vasp-v1.json new file mode 100644 index 000000000..a1f384a1d --- /dev/null +++ b/tests/generator/param-mg-vasp-v1.json @@ -0,0 +1,101 @@ +{ + "type_map": ["Al", "Mg"], + "mass_map": [27, 24], + "use_ele_temp": 2, + + "init_data_prefix": "/home/wanghan/study/deep.md/data/almgop.20/init//", + + "init_data_sys": [ + "al.fcc.01x01x01/02.md/sys-0004/deepmd", + "mg.fcc.01x01x01/02.md/sys-0004/deepmd" + ], + "init_batch_size": [1,1], + "sys_configs": [ + ["/home/wanghan/study/deep.md/data/almgop.20/init/al.fcc.02x02x02/01.scale_pert/sys-0032/scale-1.000/00000[0-4]/POSCAR"], + ["/home/wanghan/study/deep.md/data/almgop.20/init/mg.fcc.02x02x02/01.scale_pert/sys-0032/scale-1.000/00000[0-4]/POSCAR"] + ], + "sys_batch_size": [1,1], + + "_comment": " 00.train ", + "numb_models": 4, + "default_training_param" : { + "model" : { + "descriptor": { + "type": "se_a", + "sel": [90, 90], + "rcut_smth": 1.80, + "rcut": 6.00, + "neuron": [10, 20, 40], + "resnet_dt": false, + "axis_neuron": 4, + "seed": 1 + }, + "fitting_net" : { + "neuron": [120, 120, 120], + "resnet_dt": true, + "numb_fparam": 10, + "seed": 1 + } + }, + + "loss" : { + "start_pref_e": 0.02, + "limit_pref_e": 1, + "start_pref_f": 1000, + "limit_pref_f": 1, + "start_pref_v": 0, + "limit_pref_v": 0 + }, + + "learning_rate" : { + "start_lr": 0.001, + "decay_steps": 5000, + "decay_rate": 0.95 + }, + + "training" : { + "systems": [], + "set_prefix": "set", + "stop_batch": 1000, + "batch_size": 1, + + "seed": 1, + + "_comment": " display and restart", + "_comment": " frequencies counted in batch", + "disp_file": "lcurve.out", + "disp_freq": 1000, + "numb_test": 1, + "save_freq": 1000, + "save_ckpt": "model.ckpt", + "load_ckpt": "model.ckpt", + "disp_training":true, + "time_training":true, + "profiling": false, + "profiling_file": "timeline.json" + } + }, + + "_comment": " 01.model_devi ", + "_comment": "model_devi_skip: the first x of the recorded frames", + "model_devi_dt": 0.002, + "model_devi_skip": 0, + "model_devi_f_trust_lo": 0.05, + "model_devi_f_trust_hi": 0.20, + "model_devi_e_trust_lo": 1e10, + "model_devi_e_trust_hi": 1e10, + "model_devi_clean_traj": false, + "model_devi_jobs": [ + { "_idx": 0, "ensemble": "npt", "nsteps": 50, "press": [1.0,2.0], "sys_idx": [0, 1], "temps": [50,100], "trj_freq": 10 } + ], + "_comment": " 02.fp ", + "fp_style": "vasp", + "shuffle_poscar": false, + "fp_task_max": 8, + "fp_task_min": 2, + "fp_pp_path": "/home/wanghan/study/deep.md/dpgen/almg/vasp", + "fp_pp_files": ["POTCAR.Al", "POTCAR.Mg"], + "fp_incar": "/home/wanghan/study/deep.md/dpgen/almg/vasp/INCAR", + "_comment": " that's all " +} + diff --git a/tests/generator/test_make_train.py b/tests/generator/test_make_train.py index c402e3e00..a0ee21b0a 100644 --- a/tests/generator/test_make_train.py +++ b/tests/generator/test_make_train.py @@ -8,7 +8,9 @@ __package__ = 'generator' from .context import make_train from .context import param_file +from .context import param_file_v1 from .context import machine_file +from .context import machine_file_v1 from .context import setUpModule def _comp_sys_files (sys0, sys1) : @@ -48,7 +50,7 @@ def _check_numb_models(testCase, iter_idx, numb_models) : def _check_model_inputs(testCase, iter_idx, jdata) : - train_param = jdata['train_param'] + train_param = jdata.get('train_param', 'input.json') numb_models = jdata['numb_models'] default_training_param = jdata['default_training_param'] init_data_sys = [os.path.join('..', 'data.init', ii) for ii in jdata['init_data_sys']] @@ -79,6 +81,59 @@ def _check_model_inputs(testCase, iter_idx, jdata) : else : testCase.assertEqual(jdata0[ii], default_training_param[ii]) +def _check_model_input_dict(testCase, input_dict, init_data_sys, init_batch_size, default_training_param): + for ii in input_dict.keys() : + if ii == 'systems' : + for jj,kk in zip(input_dict[ii], init_data_sys): + testCase.assertEqual(jj, kk) + elif ii == 'batch_size' : + for jj, kk in zip(input_dict[ii], init_batch_size) : + testCase.assertEqual(jj, kk) + elif ii == 'seed': + # can be anything + pass + elif ii == 'numb_fparam': + testCase.assertEqual(input_dict[ii], 1) + elif ii == 'numb_aparam': + testCase.assertEqual(input_dict[ii], 1) + else : + testCase.assertEqual(input_dict[ii], default_training_param[ii]) + + +def _check_model_inputs_v1(testCase, iter_idx, jdata) : + train_param = jdata.get('train_param', 'input.json') + numb_models = jdata['numb_models'] + use_ele_temp = jdata.get('use_ele_temp', 0) + default_training_param = jdata['default_training_param'] + init_data_sys = [os.path.join('..', 'data.init', ii) for ii in jdata['init_data_sys']] + init_batch_size = jdata['init_batch_size'] + sys_batch_size = jdata['sys_batch_size'] + if iter_idx > 0 : + systems = glob.glob(os.path.join('iter.*', '02.fp', 'data.*')) + for ii in systems : + init_data_sys.append(os.path.join('..', 'data.iters', ii)) + sys_idx = int(os.path.basename(ii).split('.')[1]) + init_batch_size.append(sys_batch_size[sys_idx]) + for kk in range(numb_models) : + with open(os.path.join('iter.%06d' % iter_idx, + '00.train', + '%03d' % kk, + train_param)) as fp : + jdata0 = json.load(fp) + # keys except 'systems', 'batch_size', 'seed' should be identical + if use_ele_temp == 1: + testCase.assertTrue('numb_fparam' in jdata0['model']['fitting_net']) + testCase.assertFalse('numb_aparam' in jdata0['model']['fitting_net']) + if use_ele_temp == 2: + testCase.assertTrue('numb_aparam' in jdata0['model']['fitting_net']) + testCase.assertFalse('numb_fparam' in jdata0['model']['fitting_net']) + _check_model_input_dict(testCase, jdata0['model']['descriptor'], init_data_sys, init_batch_size, default_training_param['model']['descriptor']) + _check_model_input_dict(testCase, jdata0['model']['fitting_net'], init_data_sys, init_batch_size, default_training_param['model']['fitting_net']) + _check_model_input_dict(testCase, jdata0['loss'], init_data_sys, init_batch_size, default_training_param['loss']) + _check_model_input_dict(testCase, jdata0['learning_rate'], init_data_sys, init_batch_size, default_training_param['learning_rate']) + _check_model_input_dict(testCase, jdata0['training'], init_data_sys, init_batch_size, default_training_param['training']) + + def _make_fake_fp(iter_idx, sys_idx, nframes): for ii in range(nframes) : dirname = os.path.join('iter.%06d' % iter_idx, @@ -159,6 +214,25 @@ def test_1_skip(self): # remove testing dirs shutil.rmtree('iter.000001') shutil.rmtree('iter.000000') + + + def test_1_data_v1(self) : + with open (param_file_v1, 'r') as fp : + jdata = json.load (fp) + with open (machine_file_v1, 'r') as fp: + mdata = json.load (fp) + make_train(0, jdata, mdata) + # make fake fp results #data == fp_task_min + _make_fake_fp(0, 0, jdata['fp_task_min']) + # make iter1 train + make_train(1, jdata, mdata) + # check data is linked + self.assertTrue(os.path.isdir(os.path.join('iter.000001', '00.train', 'data.iters', 'iter.000000', '02.fp'))) + # check models inputs + _check_model_inputs_v1(self, 1, jdata) + # remove testing dirs + shutil.rmtree('iter.000001') + shutil.rmtree('iter.000000') if __name__ == '__main__': From cc872c196bdfc7bee04e3d0b01ecbacd72d6f687 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 15 Oct 2019 21:50:14 +0800 Subject: [PATCH 38/93] fix bug --- tests/generator/param-mg-vasp-v1.json | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/tests/generator/param-mg-vasp-v1.json b/tests/generator/param-mg-vasp-v1.json index a1f384a1d..7397eac67 100644 --- a/tests/generator/param-mg-vasp-v1.json +++ b/tests/generator/param-mg-vasp-v1.json @@ -3,16 +3,13 @@ "mass_map": [27, 24], "use_ele_temp": 2, - "init_data_prefix": "/home/wanghan/study/deep.md/data/almgop.20/init//", - - "init_data_sys": [ - "al.fcc.01x01x01/02.md/sys-0004/deepmd", - "mg.fcc.01x01x01/02.md/sys-0004/deepmd" - ], - "init_batch_size": [1,1], + "init_data_prefix": "data", + "init_data_sys": ["deepmd" + ], + "init_batch_size": [16], "sys_configs": [ - ["/home/wanghan/study/deep.md/data/almgop.20/init/al.fcc.02x02x02/01.scale_pert/sys-0032/scale-1.000/00000[0-4]/POSCAR"], - ["/home/wanghan/study/deep.md/data/almgop.20/init/mg.fcc.02x02x02/01.scale_pert/sys-0032/scale-1.000/00000[0-4]/POSCAR"] + ["data/mg.fcc.02x02x02/01.scale_pert/sys-0032/scale*/000010/POSCAR"], + ["data/mg.fcc.02x02x02/01.scale_pert/sys-0032/scale*/00000[8-9]/POSCAR"] ], "sys_batch_size": [1,1], From eee6fa2f5741a5f44f250d94051382738367fed9 Mon Sep 17 00:00:00 2001 From: felix5572 Date: Wed, 16 Oct 2019 09:27:40 +0000 Subject: [PATCH 39/93] AWS bug fix --- dpgen/dispatcher/AWS.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dpgen/dispatcher/AWS.py b/dpgen/dispatcher/AWS.py index c7d774e67..c339c18eb 100644 --- a/dpgen/dispatcher/AWS.py +++ b/dpgen/dispatcher/AWS.py @@ -6,9 +6,9 @@ from dpgen import dlog class AWS(Batch): - try : + try: import boto3 - batch = boto3.client('batch') + batch_client = boto3.client('batch') except ModuleNotFoundError: pass _query_max_results = 1000 @@ -44,7 +44,7 @@ def AWS_check_status(cls, job_id=""): if datetime.now().timestamp() > cls._query_next_allow_time: cls._query_next_allow_time=datetime.now().timestamp()+cls._query_time_interval for status in ['SUBMITTED', 'PENDING', 'RUNNABLE', 'STARTING', 'RUNNING','SUCCEEDED', 'FAILED']: - status_response = cls.batch.list_jobs(jobQueue=cls._jobQueue, jobStatus=status, maxResults=cls._query_max_results) + status_response = cls.batch_client.list_jobs(jobQueue=cls._jobQueue, jobStatus=status, maxResults=cls._query_max_results) status_list=status_response.get('jobSummaryList', []) for job_dict in status_list: query_dict.update({job_dict['jobId']: cls.map_aws_status_to_dpgen_status(job_dict['status'])}) @@ -64,7 +64,7 @@ def job_id(self): except AttributeError: if self.context.check_file_exists(self.job_id_name): self._job_id = self.context.read_file(self.job_id_name) - response_list = self.__class__.batch.describe_jobs(jobs=[self._job_id]).get('jobs') + response_list = self.__class__.batch_client.describe_jobs(jobs=[self._job_id]).get('jobs') try: response = response_list[0] jobQueue = response['jobQueue'] @@ -103,7 +103,7 @@ def sub_script(self, job_dirs, cmd, args, res, outlog, errlog): multi_command = "" for job_dir in job_dirs: for idx,t in enumerate(zip_longest(cmd, args, fillvalue='')): - c_str = f"((cd {self.context.remote_root}/{job_dir} && {t[0]} {t[1]} 2>>{errlog} |tee -a {outlog})&& touch tag_{idx}_finished);wait;" + c_str = f"((cd {self.context.remote_root}/{job_dir} && test -f touch tag_{idx}_finished || {t[0]} {t[1]} 2>>{errlog} && touch tag_{idx}_finished ) | tee -a {outlog});wait;" multi_command += c_str dlog.debug("10000, %s" % multi_command) return multi_command @@ -138,7 +138,7 @@ def do_submit(self, """ jobName = os.path.join(self.context.remote_root,job_dirs.pop())[1:].replace('/','-').replace('.','_') jobName += ("_" + str(self.context.job_uuid)) - response = self.__class__.batch.submit_job(jobName=jobName, + response = self.__class__.batch_client.submit_job(jobName=jobName, jobQueue=res['jobQueue'], jobDefinition=res['jobDefinition'], parameters={'task_command':script_str}, From d27540db27e1d901288fe6b0ca2ce9e8c472192a Mon Sep 17 00:00:00 2001 From: Yuan Fengbo Date: Fri, 18 Oct 2019 12:18:27 +0800 Subject: [PATCH 40/93] AWS bug fixed 2 --- dpgen/dispatcher/AWS.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpgen/dispatcher/AWS.py b/dpgen/dispatcher/AWS.py index c339c18eb..f6aedff06 100644 --- a/dpgen/dispatcher/AWS.py +++ b/dpgen/dispatcher/AWS.py @@ -103,7 +103,7 @@ def sub_script(self, job_dirs, cmd, args, res, outlog, errlog): multi_command = "" for job_dir in job_dirs: for idx,t in enumerate(zip_longest(cmd, args, fillvalue='')): - c_str = f"((cd {self.context.remote_root}/{job_dir} && test -f touch tag_{idx}_finished || {t[0]} {t[1]} 2>>{errlog} && touch tag_{idx}_finished ) | tee -a {outlog});wait;" + c_str = f"((cd {self.context.remote_root}/{job_dir} && test -f tag_{idx}_finished || {t[0]} {t[1]} 2>>{errlog} && touch tag_{idx}_finished ) | tee -a {outlog});wait;" multi_command += c_str dlog.debug("10000, %s" % multi_command) return multi_command From e98eca695978c090bb544756485d7fdf7e707971 Mon Sep 17 00:00:00 2001 From: Cloudac7 <812556867@qq.com> Date: Fri, 18 Oct 2019 15:31:10 +0800 Subject: [PATCH 41/93] add an example machine.json file for lsf --- examples/machine/machine-lsf.json | 91 +++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 examples/machine/machine-lsf.json diff --git a/examples/machine/machine-lsf.json b/examples/machine/machine-lsf.json new file mode 100644 index 000000000..3d71a4654 --- /dev/null +++ b/examples/machine/machine-lsf.json @@ -0,0 +1,91 @@ +{ + "train": [ + { + "machine": { + "machine_type": "lsf", + "hostname": "localhost", + "port": 22, + "username": "ypliu", + "work_path": "/data/home/ypliu/test/deepmd-tutorial/cp2k_dpgen/dpmd" + }, + "resources": { + "node_cpu": 4, + "numb_node": 1, + "task_per_node": 4, + "partition": "gpu", + "exclude_list": [], + "mem_limit": 11, + "source_list": [ + "/data/home/ypliu/test/deepmd-tutorial/cp2k_dpgen/source_env.sh", + "/data/home/ypliu/test/deepmd-tutorial/cp2k_dpgen/test_gpu_sub.sh" + ], + "module_list": [ + "vasp/5.4.4", + "cuda" + ], + "time_limit": "23:0:0" + }, + "deepmd_path": "/data/home/ypliu/deepmd/deepmd_root" + } + ], + "model_devi": [ + { + "machine": { + "machine_type": "lsf", + "hostname": "localhost", + "port": 22, + "username": "ypliu", + "work_path": "/data/home/ypliu/test/deepmd-tutorial/cp2k_dpgen/lammps" + }, + "resources": { + "node_cpu": 4, + "numb_node": 1, + "task_per_node": 4, + "partition": "gpu", + "exclude_list": [], + "mem_limit": 11, + "source_list": [ + "/data/home/ypliu/test/deepmd-tutorial/cp2k_dpgen/source_env.sh", + "/data/home/ypliu/test/deepmd-tutorial/cp2k_dpgen/test_gpu_sub.sh" + ], + "module_list": [ + "vasp/5.4.4", + "cuda", + "gcc/4.9.4" + ], + "time_limit": "23:0:0" + }, + "command": "/data/home/ypliu/lammps/lammps-7Aug19/src/lmp_mpi", + "group_size": 10 + } + ], + "fp": [ + { + "machine": { + "machine_type": "lsf", + "hostname": "localhost", + "port": 22, + "username": "ypliu", + "work_path": "/data/home/ypliu/test/deepmd-tutorial/cp2k_dpgen/cp2k" + }, + "resources": { + "cvasp": false, + "task_per_node": 28, + "node_cpu": 28, + "exclude_list": [], + "mem_limit": 128, + "with_mpi": true, + "source_list": [], + "module_list": [ + "intel/17.0.1", + "mpi/intel/2017.1.132" + ], + "time_limit": "96:0:0", + "partition": "q2680v4m128", + "_comment": "that's Bel" + }, + "command": "/share/apps/cp2k-5.0/Linux-x86-64-intel-host/cp2k.popt -i input.inp", + "group_size": 5 + } + ] +} \ No newline at end of file From f2586a55798f131077dd8e5b7be9eb86920c8e0e Mon Sep 17 00:00:00 2001 From: Cloudac7 <812556867@qq.com> Date: Fri, 18 Oct 2019 15:36:54 +0800 Subject: [PATCH 42/93] comment for GPU part --- examples/machine/machine-lsf.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/machine/machine-lsf.json b/examples/machine/machine-lsf.json index 3d71a4654..f10ed82fb 100644 --- a/examples/machine/machine-lsf.json +++ b/examples/machine/machine-lsf.json @@ -9,6 +9,7 @@ "work_path": "/data/home/ypliu/test/deepmd-tutorial/cp2k_dpgen/dpmd" }, "resources": { + "_comment": "this part should be modified if GPU resources could be called directly by LSF", "node_cpu": 4, "numb_node": 1, "task_per_node": 4, @@ -38,6 +39,7 @@ "work_path": "/data/home/ypliu/test/deepmd-tutorial/cp2k_dpgen/lammps" }, "resources": { + "_comment": "this part should be modified if GPU resources could be called directly by LSF", "node_cpu": 4, "numb_node": 1, "task_per_node": 4, From f4d2a61065437e5fc5abb5acf3f6dfd802b4987d Mon Sep 17 00:00:00 2001 From: Yuan Fengbo Date: Sat, 19 Oct 2019 15:28:00 +0800 Subject: [PATCH 43/93] auto scan file and write param.json --- dpgen/tools/auto_gen_param.py | 275 ++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 dpgen/tools/auto_gen_param.py diff --git a/dpgen/tools/auto_gen_param.py b/dpgen/tools/auto_gen_param.py new file mode 100644 index 000000000..d2ae065c6 --- /dev/null +++ b/dpgen/tools/auto_gen_param.py @@ -0,0 +1,275 @@ +#%% +import os +import argparse +import json +from collections import defaultdict +from itertools import tee + +class System(object): + current_num_of_system = 0 + current_num_of_sub_systems = 0 + + @property + def index_system(self): + return self._index_system + + @index_system.setter + def index_system(self,value): + self._index_system = value + + @classmethod + def register_system(cls): + cls.current_num_of_system+=1 + return cls.current_num_of_system-1 + + @classmethod + def register_sub_system(cls): + cls.current_num_of_sub_systems+=1 + return cls.current_num_of_sub_systems-1 + + def __init__(self, system_prefix=""): + # print(files_list) + # if sum(map_relations)>len(files_list): + # raise RuntimeError( + # "files_list not enough;sum(map_relations):%s>len(files_list):%s, %s" + # % (sum(map_relations),len(files_list),files_list,)) + self.index_system = self.register_system() + self.sub_system_list = [] + self.system_prefix = system_prefix + self.current_idx2 = 0 + + def add_sub_system(self,idx2, files_list): + idx1 = self.register_sub_system() + idx2 = self.current_idx2 + self.sub_system_list.append((idx1, self.index_system, idx2, files_list)) + self.current_idx2 += 1 + + def get_sub_system(self): + return self.sub_system_list + + +class Iteration(object): + current_num_of_itearation = 0 + current_num_of_sub_itearation = 0 + + @property + def index_iteration(self): + return self._index_iteration # pylint: disable=no-member + + @index_iteration.setter + def index_iteration(self, value): + self._index_sub_iteration = value + + @classmethod + def register_iteration(cls): + cls.current_num_of_itearation+=1 + return cls.current_num_of_itearation-1 + + @classmethod + def register_sub_iteartion(cls): + cls.current_num_of_sub_itearation +=1 + return cls.current_num_of_sub_itearation-1 + + def __init__(self, + temps, + nsteps_list=[500, 500, 1000, 1000, 3000, 3000, 6000, 6000], + sub_iteration_num=8, + ensemble='npt', + press=[1.0, 10.0, 100.0, 1000.0, 5000.0, 10000.0, 20000.0, 50000.0], + trj_freq=10): + if len(nsteps_list) != sub_iteration_num: + raise RuntimeError(f'{nsteps_list}, {sub_iteration_num}; length does not match') + self.temps = temps + self.index_iteration = self.register_iteration() + self.nsteps_list=nsteps_list + self.sub_iteration_num=sub_iteration_num + self.ensemble=ensemble + self.press = press + self.trj_freq = trj_freq + + def gen_sub_iter(self, system_list): + sub_iter_list = [] + for idx2 in range(self.sub_iteration_num): + iter_dict = {} + iter_dict['_idx'] = self.register_sub_iteartion() + iter_dict['ensemble'] = self.ensemble + iter_dict['nsteps'] = self.nsteps_list[idx2] + iter_dict['press'] = self.press + iter_dict['sys_idx'] = [ii[0] for ii in system_list if ii[2]==idx2] + iter_dict['temps'] = self.temps + iter_dict['trj_freq'] = self.trj_freq + sub_iter_list.append(iter_dict) + return sub_iter_list + +def default_map_generator(map_list=[1,1,2,2,4,4,4,4], data_list=None): + num = 0 + # if len(data_list) < sum(map_list): + # raise RuntimeError(f'{data_list} < {map_list};not enough structure to expore, data_list_too_short!') + if (data_list is None) and ( all(el%10==0 for el in map_list) ): + for ii in map_list: + yield [f"{jj:0<5}?" for jj in range(num, num+ii//10)] + num+=(ii//10) + elif data_list: + for ii in map_list: + yield [data_list[jj] for jj in range(num, num+ii)] + num += ii + raise RuntimeError(f"{map_list} length is not enough") + # while True: + # yield [data_list[jj] for jj in range(num, num+ii)] + # num += ii + +def get_system_list(system_dict, + map_list=[1,1,2,2,4,4,4,4], + meta_iter_num=4, + sub_iteration_num=8, + map_iterator=None, + file_name="POSCAR"): + """ + :type map_iterator: Iterable use to generate sys_configs + :Exmaple [['000000', '000001',], ['00000[2-9]',], ['00001?', '000020',],] + """ + if sub_iteration_num != len(map_list): + raise RuntimeError(f"{sub_iteration_num},{map_list};sub_iteration_num does not match the length of map_list") + + system_list = [] + for system_prefix,data_list in system_dict.items(): + if map_iterator is None: + new_map_iterator = default_map_generator(map_list=map_list, data_list=data_list) + else: + origin_one, new_map_iterator = tee(map_iterator) # pylint: disable=unused-variable + # tee means copy;new_map_generator will become a copy of map_iterator + system = System(system_prefix) + for idx2 in range(sub_iteration_num): + files_list = [os.path.join(system_prefix, jj) for jj in next(new_map_iterator)] + system.add_sub_system(idx2=idx2, files_list=files_list) + system_list.extend(system.get_sub_system()) + return system_list + +def scan_files(scan_dir="./" ,file_name="POSCAR", min_allow_files_num=20): + # will return + # files_list=[] + system_dict = defaultdict(list) + for ii in os.walk(scan_dir): + if file_name in ii[2]: + system_prefix = os.path.dirname(ii[0]) + system_suffix = os.path.basename(ii[0]) + system_dict[system_prefix].append(os.path.join(system_suffix, file_name)) + for k,v in list(system_dict.items()): + if len(v) < min_allow_files_num: + del system_dict[k] + return system_dict + +# def gen_ + +def default_temps_generator(melt_point, temps_intervel=0.1, num_temps=5): + temps = [50, ] + last_temp = 0 + for ii in range(num_temps-1): # pylint: disable=unused-variable + last_temp = last_temp + temps_intervel*melt_point + temps.append(last_temp) + yield temps + while True: + temps = [] + for ii in range(num_temps): + last_temp = last_temp + temps_intervel*melt_point + temps.append(last_temp) + yield temps + +def get_model_devi_jobs(melt_point, + system_list, + nsteps_list=[500, 500, 1000, 1000, 3000, 3000, 6000, 6000], + press=[1.0, 10.0, 100.0, 1000.0, 5000.0, 10000.0, 20000.0, 50000.0], + meta_iter_num=4, + sub_iteration_num=8, + temps_iterator=None, + ensemble="npt", + trj_freq=10, + temps_intervel=0.1, + num_temps=5): + + if temps_iterator is None: + temps_iterator = default_temps_generator(melt_point=melt_point, + temps_intervel=temps_intervel, num_temps=num_temps) + + if len(nsteps_list) != sub_iteration_num: + raise RuntimeError(f"{nsteps_list}, {sub_iteration_num};length do not match!") + model_devi_jobs =[] + for ii in range(meta_iter_num): # pylint: disable=unused-variable + temps = next(temps_iterator) + meta_iter = Iteration(temps=temps, + nsteps_list=nsteps_list, + sub_iteration_num=sub_iteration_num, + ensemble=ensemble, + press=press, + trj_freq=trj_freq) + model_devi_jobs.extend(meta_iter.gen_sub_iter(system_list)) + return model_devi_jobs + +def get_sys_configs(system_list): + sys_configs=[[] for ii in system_list] + for t in system_list: + sys_configs[t[0]]=t[3] + return sys_configs + +def get_init_data_sys(scan_dir='./', init_file_name='type.raw'): + + init_data_sys = [] + for t in os.walk(scan_dir): + if init_file_name in t[2]: + init_data_sys.append(t[0]) + else: + pass + return init_data_sys + + +def get_basic_param_json(melt_point, + out_param_filename='param.json', + scan_dir="./", + file_name='POSCAR', + init_file_name='type.raw', + min_allow_files_num=20, + map_list=[1,1,2,2,4,4,4,4], + meta_iter_num=4, + sub_iteration_num=8, + map_iterator=None, + nsteps_list=[500, 500, 1000, 1000, 3000, 3000, 6000, 6000], + press=[1.0, 10.0, 100.0, 1000.0, 5000.0, 10000.0, 20000.0, 50000.0], + temps_iterator=None, + ensemble="npt", + trj_freq=10, + temps_intervel=0.1, + num_temps=5,): + + init_data_sys = get_init_data_sys(scan_dir=scan_dir, init_file_name=init_file_name) + print(f"length of init_data_sys: {len(init_data_sys)}") + system_dict = scan_files(scan_dir, file_name, min_allow_files_num) + print(f"num of different systems: {len(system_dict)}") + system_list =get_system_list(system_dict, + map_list=map_list, + meta_iter_num=meta_iter_num, + sub_iteration_num=sub_iteration_num, + map_iterator=map_iterator, + file_name=file_name) + + sys_configs = get_sys_configs(system_list) + print(f"length of sys_configs: {len(sys_configs)}") + model_devi_jobs = get_model_devi_jobs(melt_point=melt_point, + system_list=system_list, + nsteps_list=nsteps_list, + press=press, + meta_iter_num=meta_iter_num, + sub_iteration_num=sub_iteration_num, + temps_iterator=temps_iterator, + ensemble=ensemble, + trj_freq=trj_freq, + temps_intervel=temps_intervel, + num_temps=num_temps) + param_dict={ + 'init_data_sys': init_data_sys, + 'sys_configs':sys_configs, + 'model_devi_jobs':model_devi_jobs + } + with open(out_param_filename, 'w') as p: + json.dump(param_dict, p, indent=4) + +#%% From f5fd1bf3f100ffac179e92d688fcc5926885a9ee Mon Sep 17 00:00:00 2001 From: felix5572 Date: Sat, 19 Oct 2019 07:35:05 +0000 Subject: [PATCH 44/93] modify AWS logic --- dpgen/dispatcher/AWS.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dpgen/dispatcher/AWS.py b/dpgen/dispatcher/AWS.py index f6aedff06..c6a9838da 100644 --- a/dpgen/dispatcher/AWS.py +++ b/dpgen/dispatcher/AWS.py @@ -47,13 +47,13 @@ def AWS_check_status(cls, job_id=""): status_response = cls.batch_client.list_jobs(jobQueue=cls._jobQueue, jobStatus=status, maxResults=cls._query_max_results) status_list=status_response.get('jobSummaryList', []) for job_dict in status_list: - query_dict.update({job_dict['jobId']: cls.map_aws_status_to_dpgen_status(job_dict['status'])}) - for job in cls._job_id_map_status: - cls._job_id_map_status[job]=query_dict.get(job, JobStatus.unknown) - dlog.debug('20000: _query: %s, _map: %s' %(query_dict, cls._job_id_map_status)) + cls._job_id_map_status.update({job_dict['jobId']: cls.map_aws_status_to_dpgen_status(job_dict['status'])}) + # for job in cls._job_id_map_status: + # cls._job_id_map_status[job]=query_dict.get(job, JobStatus.unknown) + dlog.debug('20000:_map: %s' %(cls._job_id_map_status)) dlog.debug('62000:job_id:%s, _query: %s, _map: %s' %(job_id, query_dict, cls._job_id_map_status)) if job_id: - return cls._job_id_map_status.get(job_id, query_dict.get(job_id,JobStatus.unknown)) + return cls._job_id_map_status.get(job_id, JobStatus.unknown) return cls._job_id_map_status From 5dd77a5afebb261d88ffd49d709a3ee21e456181 Mon Sep 17 00:00:00 2001 From: haidi Date: Sun, 20 Oct 2019 16:11:06 +0800 Subject: [PATCH 45/93] update gen.py and surf.py --- README.md | 39 +++++--- dpgen/data/gen.py | 91 ++++--------------- dpgen/data/{ => jsons}/param.json | 0 dpgen/data/surf.py | 142 +++++------------------------- 4 files changed, 69 insertions(+), 203 deletions(-) rename dpgen/data/{ => jsons}/param.json (100%) mode change 100755 => 100644 dpgen/data/surf.py diff --git a/README.md b/README.md index 117fa3c0e..3ebd81725 100644 --- a/README.md +++ b/README.md @@ -75,12 +75,23 @@ and if everything works, it gives ``` DeepModeling ------------ +Version: 0.5.1.dev53+gddbeee7.d20191020 +Date: Oct-07-2019 +Path: /home/me/miniconda3/envs/py363/lib/python3.6/site-packages/dpgen-0.5.1.dev53+gddbeee7.d20191020-py3.6.egg/dpgen -Version: 0.2.0 -Path: /home/wanghan/.local/lib/python3.6/site-packages/dpgen-0.1.0-py3.6.egg/dpgen -Date: Aug 13, 2019 - -usage: dpgen [-h] {init_surf,init_bulk,run,test,db} ... +Dependency +------------ + numpy 1.17.2 /home/me/miniconda3/envs/py363/lib/python3.6/site-packages/numpy + dpdata 0.1.10 /home/me/miniconda3/envs/py363/lib/python3.6/site-packages/dpdata-0.1.10-py3.6.egg/dpdata + pymatgen 2019.7.2 /home/me/miniconda3/envs/py363/lib/python3.6/site-packages/pymatgen + monty 2.0.4 /home/me/miniconda3/envs/py363/lib/python3.6/site-packages/monty + ase 3.17.0 /home/me/miniconda3/envs/py363/lib/python3.6/site-packages/ase-3.17.0-py3.6.egg/ase + paramiko 2.6.0 /home/me/miniconda3/envs/py363/lib/python3.6/site-packages/paramiko + custodian 2019.2.10 /home/me/miniconda3/envs/py363/lib/python3.6/site-packages/custodian + +Description +------------ +usage: dpgen [-h] {init_surf,init_bulk,run,run/report,test,db} ... dpgen is a convenient script that uses DeepGenerator to prepare initial data, drive DeepMDkit and analyze results. This script works based on several sub- @@ -88,16 +99,18 @@ commands with their own options. To see the options for the sub-commands, type "dpgen sub-command -h". positional arguments: - {init_surf,init_bulk,run,test,db} + {init_surf,init_bulk,run,run/report,test,db} init_surf Generating initial data for surface systems. init_bulk Generating initial data for bulk systems. - run Main process of Deep Generator. + run Main process of Deep Potential Generator. + run/report Report the systems and the thermodynamic conditions of + the labeled frames. test Auto-test for Deep Potential. - db Collecting data from DP-GEN. - + db Collecting data from Deep Generator. optional arguments: -h, --help show this help message and exit + ``` @@ -108,8 +121,10 @@ optional arguments: You may prepare initial data for bulk systems with VASP by: ```bash -dpgen init_bulk PARAM MACHINE +dpgen init_bulk PARAM [MACHINE] ``` +The MACHINE configure file is optional. If this parameter exists, then the optimization +tasks or MD tasks will be submitted automatically according to MACHINE.json. Basically `init_bulk` can be devided into four parts , denoted as `stages` in `PARAM`: 1. Relax in folder `00.place_ele` @@ -178,8 +193,10 @@ The bold notation of key (such as **Elements**) means that it's a necessary key. You may prepare initial data for surface systems with VASP by: ```bash -dpgen init_surf PARAM MACHINE +dpgen init_surf PARAM [MACHINE] ``` +The MACHINE configure file is optional. If this parameter exists, then the optimization +tasks or MD tasks will be submitted automatically according to MACHINE.json. Basically `init_surf` can be devided into two parts , denoted as `stages` in `PARAM`: 1. Build specific surface in folder `00.place_ele` diff --git a/dpgen/data/gen.py b/dpgen/data/gen.py index 0a8e4efab..c8e98ff54 100644 --- a/dpgen/data/gen.py +++ b/dpgen/data/gen.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import os +import re import sys import argparse import glob @@ -13,8 +14,6 @@ import dpdata import numpy as np from dpgen import dlog -import os,json,shutil,re,glob,argparse,dpdata -import numpy as np import subprocess as sp import dpgen.data.tools.hcp as hcp import dpgen.data.tools.fcc as fcc @@ -22,8 +21,7 @@ import dpgen.data.tools.diamond as diamond import dpgen.data.tools.sc as sc from pymatgen import Structure -from dpgen.remote.decide_machine import decide_train_machine, decide_fp_machine, decide_model_devi_machine -from dpgen.remote.RemoteJob import SSHSession, JobStatus, SlurmJob, PBSJob, CloudMachineJob +from dpgen.remote.decide_machine import decide_fp_machine from dpgen import ROOT_PATH from dpgen.dispatcher.Dispatcher import Dispatcher, make_dispatcher @@ -314,15 +312,6 @@ def make_vasp_relax (jdata, mdata) : outfile.write(infile.read()) os.chdir(work_dir) - #replace('INCAR', 'ENCUT=.*', 'ENCUT=%f' % encut) - #replace('INCAR', 'ISIF=.*', 'ISIF=3') - #replace('INCAR', 'KSPACING=.*from dpgen.remote.decide_machine import decide_train_machine, decide_fp_machine, decide_model_devi_machine', 'KSPACING=%f' % kspacing) - #if kgamma : - # replace('INCAR', 'KGAMMA=.*', 'KGAMMA=T') - #else : - # replace('INCAR', 'KGAMMA=.*', 'KGAMMA=F') - #replace('INCAR', 'ISMEAR=.*', 'ISMEAR=%d' % ismear) - #replace('INCAR', 'SIGMA=.*', 'SIGMA=%f' % sigma) sys_list = glob.glob('sys-*') for ss in sys_list: @@ -426,8 +415,6 @@ def make_vasp_md(jdata) : md_nstep = jdata['md_nstep'] cwd = os.getcwd() - #vasp_dir = os.path.join(cwd, 'vasp.in') - #vasp_dir = os.path.join(cwd, vasp_dir) path_ps = os.path.join(out_dir, global_dirname_03) path_ps = os.path.abspath(path_ps) assert(os.path.isdir(path_ps)) @@ -446,18 +433,6 @@ def make_vasp_md(jdata) : with open(fname) as infile: outfile.write(infile.read()) os.chdir(path_md) - #replace('INCAR', 'ENCUT=.*', 'ENCUT=%f' % encut) - #replace('INCAR', 'ISIF=.*', 'ISIF=2') - #replace('INCAR', 'KSPACING=.*', 'KSPACING=%f' % kspacing) - #if kgamma : - # replace('INCAR', 'KGAMMA=.*', 'KGAMMA=T') - #else : - # replace('INCAR', 'KGAMMA=.*', 'KGAMMA=F') - #replace('INCAR', 'NSW=.*', 'NSW=%d' % md_nstep) - #replace('INCAR', 'TEBEG=.*', 'TEBEG=%d' % md_temp) - #replace('INCAR', 'TEEND=.*', 'TEEND=%d' % md_temp) - #replace('INCAR', 'ISMEAR=.*', 'ISMEAR=%d' % ismear) - #replace('INCAR', 'SIGMA=.*', 'SIGMA=%f' % sigma) os.chdir(cwd) for ii in sys_ps : @@ -556,40 +531,6 @@ def _vasp_check_fin (ii) : else : return False return True -def _group_slurm_jobs(ssh_sess, - resources, - command, - work_path, - tasks, - group_size, - forward_common_files, - forward_task_files, - backward_task_files, - remote_job = SlurmJob) : - task_chunks = [ - [j for j in tasks[i:i + group_size]] \ - for i in range(0, len(tasks), group_size) - ] - job_list = [] - for chunk in task_chunks : - rjob = remote_job(ssh_sess, work_path) - rjob.upload('.', forward_common_files) - rjob.upload(chunk, forward_task_files) - rjob.submit(chunk, command, resources = resources) - job_list.append(rjob) - - job_fin = [False for ii in job_list] - while not all(job_fin) : - for idx,rjob in enumerate(job_list) : - if not job_fin[idx] : - status = rjob.check_status() - if status == JobStatus.terminated : - raise RuntimeError("find unsuccessfully terminated job in %s" % rjob.get_job_root()) - elif status == JobStatus.finished : - rjob.download(task_chunks[idx], backward_task_files) - rjob.clean() - job_fin[idx] = True - time.sleep(10) def run_vasp_relax(jdata, mdata, dispatcher): fp_command = mdata['fp_command'] @@ -612,13 +553,12 @@ def run_vasp_relax(jdata, mdata, dispatcher): return relax_run_tasks = relax_tasks - #for ii in relax_tasks : - # if not _vasp_check_fin(ii): - # relax_run_tasks.append(ii) + for ii in relax_tasks : + if not _vasp_check_fin(ii): + relax_run_tasks.append(ii) run_tasks = [os.path.basename(ii) for ii in relax_run_tasks] #dlog.info(run_tasks) - #assert (machine_type == "slurm" or machine_type =="Slurm"), "Currently only support for Slurm!" dispatcher.run_jobs(fp_resources, [fp_command], work_dir, @@ -664,7 +604,6 @@ def run_vasp_md(jdata, mdata, dispatcher): #dlog.info("md_work_dir", work_dir) #dlog.info("run_tasks",run_tasks) - #assert (machine_type == "slurm" or machine_type =="Slurm"), "Currently only support for Slurm!" dispatcher.run_jobs(fp_resources, [fp_command], work_dir, @@ -674,11 +613,6 @@ def run_vasp_md(jdata, mdata, dispatcher): forward_files, backward_files) - - - - - def gen_init_bulk(args) : try: import ruamel @@ -698,8 +632,7 @@ def gen_init_bulk(args) : # Selecting a proper machine mdata = decide_fp_machine(mdata) disp = make_dispatcher(mdata["fp_machine"]) - #fp_machine = mdata['fp_machine'] - #fp_ssh_sess = SSHSession(fp_machine) + # Decide work path out_dir = out_dir_name(jdata) jdata['out_dir'] = out_dir @@ -771,4 +704,14 @@ def gen_init_bulk(args) : dlog.info("Current stage is 4, collect data") coll_vasp_md(jdata) else : - raise RuntimeError("unknown stage %d" % stage) \ No newline at end of file + raise RuntimeError("unknown stage %d" % stage) + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Generating initial data for bulk systems.") + parser.add_argument('PARAM', type=str, + help="parameter file, json/yaml format") + parser.add_argument('MACHINE', type=str,default=None,nargs="?", + help="machine file, json/yaml format") + args = parser.parse_args() + gen_init_bulk(args) diff --git a/dpgen/data/param.json b/dpgen/data/jsons/param.json similarity index 100% rename from dpgen/data/param.json rename to dpgen/data/jsons/param.json diff --git a/dpgen/data/surf.py b/dpgen/data/surf.py old mode 100755 new mode 100644 index 81753df5e..f28f6e3ba --- a/dpgen/data/surf.py +++ b/dpgen/data/surf.py @@ -11,16 +11,15 @@ from dpgen import dlog import time from dpgen import ROOT_PATH -from dpgen.remote.decide_machine import decide_train_machine, decide_fp_machine, decide_model_devi_machine -from dpgen.remote.RemoteJob import SSHSession, JobStatus, SlurmJob, PBSJob, CloudMachineJob +from dpgen.remote.decide_machine import decide_fp_machine from pymatgen.core.surface import SlabGenerator,generate_all_slabs, Structure from pymatgen.io.vasp import Poscar +from dpgen.dispatcher.Dispatcher import Dispatcher, make_dispatcher #-----ASE------- from pymatgen.io.ase import AseAtomsAdaptor from ase.io import read from ase.build import general_surface - def create_path (path) : path += '/' if os.path.isdir(path) : @@ -292,11 +291,7 @@ def place_element (jdata) : def make_vasp_relax (jdata) : out_dir = jdata['out_dir'] potcars = jdata['potcars'] - #encut = jdata['encut'] - #kspacing = jdata['kspacing_relax'] - #kgamma = jdata['kgamma'] cwd = os.getcwd() - #vasp_dir = os.path.join(cwd, 'vasp.in') work_dir = os.path.join(out_dir, global_dirname_02) assert (os.path.isdir(work_dir)) @@ -314,13 +309,6 @@ def make_vasp_relax (jdata) : outfile.write(infile.read()) os.chdir(work_dir) - #replace('INCAR', 'ENCUT=.*', 'ENCUT=%f' % encut) - #replace('INCAR', 'ISIF=.*', 'ISIF=3') - #replace('INCAR', 'KSPACING=.*', 'KSPACING=%f' % kspacing) - #if kgamma : - # replace('INCAR', 'KGAMMA=.*', 'KGAMMA=T') - #else : - # replace('INCAR', 'KGAMMA=.*', 'KGAMMA=F') sys_list = glob.glob(os.path.join('surf-*', 'sys-*')) for ss in sys_list: @@ -485,41 +473,8 @@ def _vasp_check_fin (ii) : else : return False return True -def _group_slurm_jobs(ssh_sess, - resources, - command, - work_path, - tasks, - group_size, - forward_common_files, - forward_task_files, - backward_task_files, - remote_job = SlurmJob) : - task_chunks = [ - [j for j in tasks[i:i + group_size]] \ - for i in range(0, len(tasks), group_size) - ] - job_list = [] - for chunk in task_chunks : - rjob = remote_job(ssh_sess, work_path) - rjob.upload('.', forward_common_files) - rjob.upload(chunk, forward_task_files) - rjob.submit(chunk, command, resources = resources) - job_list.append(rjob) - - job_fin = [False for ii in job_list] - while not all(job_fin) : - for idx,rjob in enumerate(job_list) : - if not job_fin[idx] : - status = rjob.check_status() - if status == JobStatus.terminated : - raise RuntimeError("find unsuccessfully terminated job in %s" % rjob.get_job_root()) - elif status == JobStatus.finished : - rjob.download(task_chunks[idx], backward_task_files) - rjob.clean() - job_fin[idx] = True - time.sleep(10) -def run_vasp_relax(jdata, mdata, ssh_sess): + +def run_vasp_relax(jdata, mdata, dispatcher): fp_command = mdata['fp_command'] fp_group_size = mdata['fp_group_size'] fp_resources = mdata['fp_resources'] @@ -546,16 +501,15 @@ def run_vasp_relax(jdata, mdata, ssh_sess): run_tasks = [ii.replace(work_dir+"/", "") for ii in relax_run_tasks] #dlog.info(run_tasks) - assert (machine_type == "slurm" or machine_type =="Slurm"), "Currently only support for Slurm!" - _group_slurm_jobs(ssh_sess, - fp_resources, - fp_command, - work_dir, - run_tasks, - fp_group_size, - forward_common_files, - forward_files, - backward_files) + dispatcher.run_jobs(fp_resources, + [fp_command], + work_dir, + run_tasks, + fp_group_size, + forward_common_files, + forward_files, + backward_files) + def gen_init_surf(args): try: import ruamel @@ -578,8 +532,8 @@ def gen_init_surf(args): if args.MACHINE is not None: # Decide a proper machine mdata = decide_fp_machine(mdata) - fp_machine = mdata['fp_machine'] - fp_ssh_sess = SSHSession(fp_machine) + disp = make_dispatcher(mdata["fp_machine"]) + #stage = args.STAGE stage_list = [int(i) for i in jdata['stages']] for stage in stage_list: @@ -589,67 +543,19 @@ def gen_init_surf(args): place_element(jdata) make_vasp_relax(jdata) if args.MACHINE is not None: - run_vasp_relax(jdata, mdata, fp_ssh_sess) - # elif stage == 0 : - # # create_path(out_dir) - # # make_super_cell(jdata) - # # place_element(jdata) - # # make_vasp_relax(jdata) - # # make_scale(jdata) - # # pert_scaled(jdata) - # # poscar_elong('POSCAR', 'POSCAR.out', 3) - # pert_scaled(jdata) + run_vasp_relax(jdata, mdata, disp) elif stage == 2 : make_scale(jdata) pert_scaled(jdata) else : raise RuntimeError("unknown stage %d" % stage) -def _main() : - parser = argparse.ArgumentParser( - description="gen init confs") - parser.add_argument('PARAM', type=str, - help="parameter file, json format") - parser.add_argument('STAGE', type=int, - help="the stage of init, can be 1 or 2 " - "1: Setup vasp jobs for relaxation. " - "2: Collect vasp relaxed confs (if relax is not skiped). Perturb system. " - ) - args = parser.parse_args() - try: - import ruamel - from monty.serialization import loadfn,dumpfn - warnings.simplefilter('ignore', ruamel.yaml.error.MantissaNoDotYAML1_1Warning) - jdata=loadfn(args.PARAM) - except: - with open (args.PARAM, 'r') as fp : - jdata = json.load (fp) - - out_dir = out_dir_name(jdata) - jdata['out_dir'] = out_dir - dlog.info ("# working dir %s" % out_dir) - - stage = args.STAGE - - if stage == 1 : - create_path(out_dir) - make_super_cell_pymatgen(jdata) - place_element(jdata) - make_vasp_relax(jdata) - # elif stage == 0 : - # # create_path(out_dir) - # # make_super_cell(jdata) - # # place_element(jdata) - # # make_vasp_relax(jdata) - # # make_scale(jdata) - # # pert_scaled(jdata) - # # poscar_elong('POSCAR', 'POSCAR.out', 3) - # pert_scaled(jdata) - elif stage == 2 : - make_scale(jdata) - pert_scaled(jdata) - else : - raise RuntimeError("unknow stage %d" % stage) - if __name__ == "__main__": - _main() + parser = argparse.ArgumentParser( + description="Generating initial data for surface systems.") + parser.add_argument('PARAM', type=str, + help="parameter file, json/yaml format") + parser.add_argument('MACHINE', type=str,default=None,nargs="?", + help="machine file, json/yaml format") + args = parser.parse_args() + gen_init_surf(args) From cdcc390a8e30aff30c35cee52dd089f2d165b049 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 22 Oct 2019 18:11:15 +0800 Subject: [PATCH 46/93] fix bug: should pass the case of use_ele_temp --- dpgen/generator/run.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/dpgen/generator/run.py b/dpgen/generator/run.py index 0eb23698e..32961f870 100644 --- a/dpgen/generator/run.py +++ b/dpgen/generator/run.py @@ -279,14 +279,16 @@ def make_train (iter_index, jinput['training']['systems'] = init_data_sys jinput['training']['batch_size'] = init_batch_size # electron temperature - if use_ele_temp == 1: + if use_ele_temp == 0: + pass + elif use_ele_temp == 1: jinput['model']['fitting_net']['numb_fparam'] = 1 jinput['model']['fitting_net'].pop('numb_aparam', None) elif use_ele_temp == 2: jinput['model']['fitting_net']['numb_aparam'] = 1 jinput['model']['fitting_net'].pop('numb_fparam', None) else: - raise RuntimeError('invalid setting for use_ele_temp') + raise RuntimeError('invalid setting for use_ele_temp ' + use_ele_temp) for ii in range(numb_models) : task_path = os.path.join(work_path, train_task_fmt % ii) create_path(task_path) @@ -1407,7 +1409,9 @@ def post_fp_vasp (iter_index, assert(len(all_sys) == all_sys.get_nframes()) assert(len(all_sys) == all_te.size) all_te = np.reshape(all_te, [-1,1]) - if use_ele_temp == 1: + if use_ele_temp == 0: + raise RuntimeError('should not get ele temp at setting: use_ele_temp == 0') + elif use_ele_temp == 1: np.savetxt(os.path.join(sys_data_path, 'fparam.raw'), all_te) np.save(os.path.join(sys_data_path, 'set.000', 'fparam.npy'), all_te) elif use_ele_temp == 2: From bb765a100210331c40c681165425e32ea1f66134 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Tue, 22 Oct 2019 18:45:00 +0800 Subject: [PATCH 47/93] fix bug. unittest for no ele temp, deepmd-kit > 1.0.0 --- dpgen/generator/run.py | 4 +- tests/generator/context.py | 1 + tests/generator/param-mg-vasp-v1-et.json | 98 ++++++++++++++++++++++++ tests/generator/param-mg-vasp-v1.json | 3 +- tests/generator/test_make_train.py | 20 +++++ 5 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 tests/generator/param-mg-vasp-v1-et.json diff --git a/dpgen/generator/run.py b/dpgen/generator/run.py index 32961f870..cf92dbdb4 100644 --- a/dpgen/generator/run.py +++ b/dpgen/generator/run.py @@ -288,7 +288,7 @@ def make_train (iter_index, jinput['model']['fitting_net']['numb_aparam'] = 1 jinput['model']['fitting_net'].pop('numb_fparam', None) else: - raise RuntimeError('invalid setting for use_ele_temp ' + use_ele_temp) + raise RuntimeError('invalid setting for use_ele_temp ' + str(use_ele_temp)) for ii in range(numb_models) : task_path = os.path.join(work_path, train_task_fmt % ii) create_path(task_path) @@ -1419,7 +1419,7 @@ def post_fp_vasp (iter_index, np.savetxt(os.path.join(sys_data_path, 'aparam.raw'), tile_te) np.save(os.path.join(sys_data_path, 'set.000', 'aparam.npy'), tile_te) else: - raise RuntimeError('invalid setting of use_ele_temp ' + use_ele_temp) + raise RuntimeError('invalid setting of use_ele_temp ' + str(use_ele_temp)) dlog.info("failed frame number: %s "%icount) dlog.info("total frame number: %s "%tcount) diff --git a/tests/generator/context.py b/tests/generator/context.py index b12dd8ddf..75baecb0d 100644 --- a/tests/generator/context.py +++ b/tests/generator/context.py @@ -7,6 +7,7 @@ param_file = 'param-mg-vasp.json' param_file_v1 = 'param-mg-vasp-v1.json' +param_file_v1_et = 'param-mg-vasp-v1-et.json' param_old_file = 'param-mg-vasp-old.json' param_pwscf_file = 'param-pyridine-pwscf.json' param_pwscf_old_file = 'param-pyridine-pwscf-old.json' diff --git a/tests/generator/param-mg-vasp-v1-et.json b/tests/generator/param-mg-vasp-v1-et.json new file mode 100644 index 000000000..7397eac67 --- /dev/null +++ b/tests/generator/param-mg-vasp-v1-et.json @@ -0,0 +1,98 @@ +{ + "type_map": ["Al", "Mg"], + "mass_map": [27, 24], + "use_ele_temp": 2, + + "init_data_prefix": "data", + "init_data_sys": ["deepmd" + ], + "init_batch_size": [16], + "sys_configs": [ + ["data/mg.fcc.02x02x02/01.scale_pert/sys-0032/scale*/000010/POSCAR"], + ["data/mg.fcc.02x02x02/01.scale_pert/sys-0032/scale*/00000[8-9]/POSCAR"] + ], + "sys_batch_size": [1,1], + + "_comment": " 00.train ", + "numb_models": 4, + "default_training_param" : { + "model" : { + "descriptor": { + "type": "se_a", + "sel": [90, 90], + "rcut_smth": 1.80, + "rcut": 6.00, + "neuron": [10, 20, 40], + "resnet_dt": false, + "axis_neuron": 4, + "seed": 1 + }, + "fitting_net" : { + "neuron": [120, 120, 120], + "resnet_dt": true, + "numb_fparam": 10, + "seed": 1 + } + }, + + "loss" : { + "start_pref_e": 0.02, + "limit_pref_e": 1, + "start_pref_f": 1000, + "limit_pref_f": 1, + "start_pref_v": 0, + "limit_pref_v": 0 + }, + + "learning_rate" : { + "start_lr": 0.001, + "decay_steps": 5000, + "decay_rate": 0.95 + }, + + "training" : { + "systems": [], + "set_prefix": "set", + "stop_batch": 1000, + "batch_size": 1, + + "seed": 1, + + "_comment": " display and restart", + "_comment": " frequencies counted in batch", + "disp_file": "lcurve.out", + "disp_freq": 1000, + "numb_test": 1, + "save_freq": 1000, + "save_ckpt": "model.ckpt", + "load_ckpt": "model.ckpt", + "disp_training":true, + "time_training":true, + "profiling": false, + "profiling_file": "timeline.json" + } + }, + + "_comment": " 01.model_devi ", + "_comment": "model_devi_skip: the first x of the recorded frames", + "model_devi_dt": 0.002, + "model_devi_skip": 0, + "model_devi_f_trust_lo": 0.05, + "model_devi_f_trust_hi": 0.20, + "model_devi_e_trust_lo": 1e10, + "model_devi_e_trust_hi": 1e10, + "model_devi_clean_traj": false, + "model_devi_jobs": [ + { "_idx": 0, "ensemble": "npt", "nsteps": 50, "press": [1.0,2.0], "sys_idx": [0, 1], "temps": [50,100], "trj_freq": 10 } + ], + "_comment": " 02.fp ", + "fp_style": "vasp", + "shuffle_poscar": false, + "fp_task_max": 8, + "fp_task_min": 2, + "fp_pp_path": "/home/wanghan/study/deep.md/dpgen/almg/vasp", + "fp_pp_files": ["POTCAR.Al", "POTCAR.Mg"], + "fp_incar": "/home/wanghan/study/deep.md/dpgen/almg/vasp/INCAR", + "_comment": " that's all " +} + diff --git a/tests/generator/param-mg-vasp-v1.json b/tests/generator/param-mg-vasp-v1.json index 7397eac67..59c953e9e 100644 --- a/tests/generator/param-mg-vasp-v1.json +++ b/tests/generator/param-mg-vasp-v1.json @@ -1,7 +1,7 @@ { "type_map": ["Al", "Mg"], "mass_map": [27, 24], - "use_ele_temp": 2, + "use_ele_temp": 0, "init_data_prefix": "data", "init_data_sys": ["deepmd" @@ -30,7 +30,6 @@ "fitting_net" : { "neuron": [120, 120, 120], "resnet_dt": true, - "numb_fparam": 10, "seed": 1 } }, diff --git a/tests/generator/test_make_train.py b/tests/generator/test_make_train.py index a0ee21b0a..c64487f55 100644 --- a/tests/generator/test_make_train.py +++ b/tests/generator/test_make_train.py @@ -9,6 +9,7 @@ from .context import make_train from .context import param_file from .context import param_file_v1 +from .context import param_file_v1_et from .context import machine_file from .context import machine_file_v1 from .context import setUpModule @@ -219,6 +220,25 @@ def test_1_skip(self): def test_1_data_v1(self) : with open (param_file_v1, 'r') as fp : jdata = json.load (fp) + jdata.pop('use_ele_temp', None) + with open (machine_file_v1, 'r') as fp: + mdata = json.load (fp) + make_train(0, jdata, mdata) + # make fake fp results #data == fp_task_min + _make_fake_fp(0, 0, jdata['fp_task_min']) + # make iter1 train + make_train(1, jdata, mdata) + # check data is linked + self.assertTrue(os.path.isdir(os.path.join('iter.000001', '00.train', 'data.iters', 'iter.000000', '02.fp'))) + # check models inputs + _check_model_inputs_v1(self, 1, jdata) + # remove testing dirs + shutil.rmtree('iter.000001') + shutil.rmtree('iter.000000') + + def test_1_data_v1_eletron_temp(self) : + with open (param_file_v1_et, 'r') as fp : + jdata = json.load (fp) with open (machine_file_v1, 'r') as fp: mdata = json.load (fp) make_train(0, jdata, mdata) From c02b77d9819218b88f861f0447df225d8753914d Mon Sep 17 00:00:00 2001 From: felix5572 Date: Tue, 22 Oct 2019 11:58:06 +0000 Subject: [PATCH 48/93] aws modify --- .gitignore | 1 + dpgen/dispatcher/AWS.py | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index a2dff0063..60febdeb4 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ dpgen.egg-info *.swp .eggs .coverage +dbconfig.json diff --git a/dpgen/dispatcher/AWS.py b/dpgen/dispatcher/AWS.py index c6a9838da..67409482f 100644 --- a/dpgen/dispatcher/AWS.py +++ b/dpgen/dispatcher/AWS.py @@ -5,12 +5,13 @@ from dpgen.dispatcher.JobStatus import JobStatus from dpgen import dlog +try: + import boto3 +except ModuleNotFoundError: + pass + class AWS(Batch): - try: - import boto3 - batch_client = boto3.client('batch') - except ModuleNotFoundError: - pass + batch_client = boto3.client('batch') _query_max_results = 1000 _query_time_interval = 30 _job_id_map_status = {} @@ -42,6 +43,7 @@ def AWS_check_status(cls, job_id=""): """ query_dict ={} if datetime.now().timestamp() > cls._query_next_allow_time: + cls.batch_client = boto3.client('batch') cls._query_next_allow_time=datetime.now().timestamp()+cls._query_time_interval for status in ['SUBMITTED', 'PENDING', 'RUNNABLE', 'STARTING', 'RUNNING','SUCCEEDED', 'FAILED']: status_response = cls.batch_client.list_jobs(jobQueue=cls._jobQueue, jobStatus=status, maxResults=cls._query_max_results) From 75ed0327c92da8cd50e8044b04823702dd6c2c1d Mon Sep 17 00:00:00 2001 From: felix5572 Date: Thu, 24 Oct 2019 04:35:47 +0000 Subject: [PATCH 49/93] bug fix --- dpgen/dispatcher/AWS.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpgen/dispatcher/AWS.py b/dpgen/dispatcher/AWS.py index 67409482f..6cf0b8497 100644 --- a/dpgen/dispatcher/AWS.py +++ b/dpgen/dispatcher/AWS.py @@ -105,7 +105,7 @@ def sub_script(self, job_dirs, cmd, args, res, outlog, errlog): multi_command = "" for job_dir in job_dirs: for idx,t in enumerate(zip_longest(cmd, args, fillvalue='')): - c_str = f"((cd {self.context.remote_root}/{job_dir} && test -f tag_{idx}_finished || {t[0]} {t[1]} 2>>{errlog} && touch tag_{idx}_finished ) | tee -a {outlog});wait;" + c_str = f"((cd {self.context.remote_root}/{job_dir} && (test -f tag_{idx}_finished || {t[0]} {t[1]} 2>>{errlog} && touch tag_{idx}_finished ) | tee -a {outlog}));wait;" multi_command += c_str dlog.debug("10000, %s" % multi_command) return multi_command From 91ec70f6a1021dec6d927b7210dced58f864182e Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 14:08:31 +0800 Subject: [PATCH 50/93] Update cmpt_02_elastic.py --- dpgen/auto_test/cmpt_02_elastic.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/dpgen/auto_test/cmpt_02_elastic.py b/dpgen/auto_test/cmpt_02_elastic.py index cc60582c8..976a23483 100755 --- a/dpgen/auto_test/cmpt_02_elastic.py +++ b/dpgen/auto_test/cmpt_02_elastic.py @@ -43,16 +43,14 @@ def print_et (et): print("# Poission Ratio uV = %.2f " % (uV)) def cmpt_vasp(jdata, conf_dir) : - fp_params = jdata['vasp_params'] - kspacing = fp_params['kspacing'] - kgamma = fp_params['kgamma'] - conf_path = os.path.abspath(conf_dir) conf_poscar = os.path.join(conf_path, 'POSCAR') task_path = re.sub('confs', global_task_name, conf_path) if 'relax_incar' in jdata.keys(): vasp_str='vasp-relax_incar' else: + fp_params = jdata['vasp_params'] + kspacing = fp_params['kspacing'] vasp_str='vasp-k%.2f' % kspacing task_path = os.path.join(task_path, vasp_str) @@ -76,10 +74,6 @@ def cmpt_vasp(jdata, conf_dir) : result_et(et,conf_dir,task_path) def cmpt_deepmd_lammps(jdata, conf_dir, task_name) : - deepmd_model_dir = jdata['deepmd_model_dir'] - deepmd_type_map = jdata['deepmd_type_map'] - ntypes = len(deepmd_type_map) - conf_path = os.path.abspath(conf_dir) conf_poscar = os.path.join(conf_path, 'POSCAR') task_path = re.sub('confs', global_task_name, conf_path) From bc71a4c2ec67c0e76a90f8a9a8fec78eeba33926 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 14:10:12 +0800 Subject: [PATCH 51/93] Update run.py --- dpgen/auto_test/run.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dpgen/auto_test/run.py b/dpgen/auto_test/run.py index 589a57568..3dd1ac8f5 100644 --- a/dpgen/auto_test/run.py +++ b/dpgen/auto_test/run.py @@ -112,7 +112,6 @@ def _run(machine, raise RuntimeError("unknow machine type") def make_work_path(jdata,task,reprod_opt,static,user): - kspacing = jdata['vasp_params']['kspacing'] task_type=jdata['task_type'] conf_dir=jdata['conf_dir'] conf_path = os.path.abspath(conf_dir) @@ -127,11 +126,13 @@ def make_work_path(jdata,task,reprod_opt,static,user): if 'scf_incar' in jdata.keys(): task_type=task_type+'-static-scf_incar' else: + kspacing = jdata['vasp_params']['kspacing'] task_type=task_type+'-static-k%.2f' % (kspacing) else: if 'relax_incar' in jdata.keys(): task_type=task_type+'-relax_incar' else: + kspacing = jdata['vasp_params']['kspacing'] task_type=task_type+'-k%.2f' % (kspacing) elif task_type in lammps_task_type: if static: From fa76e701ec0ca6b3dd47be1a9ec4ab0fec606d86 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 14:11:13 +0800 Subject: [PATCH 52/93] Update cmpt_00_equi.py --- dpgen/auto_test/cmpt_00_equi.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dpgen/auto_test/cmpt_00_equi.py b/dpgen/auto_test/cmpt_00_equi.py index cc03c2ae3..a716eb0c6 100755 --- a/dpgen/auto_test/cmpt_00_equi.py +++ b/dpgen/auto_test/cmpt_00_equi.py @@ -47,7 +47,7 @@ def comput_lmp_nev(conf_dir, task_name, write_stable = False) : return None, None, None def comput_vasp_nev(jdata, conf_dir, write_stable = False) : - kspacing = jdata['vasp_params']['kspacing'] + conf_path = re.sub('confs', global_equi_name, conf_dir) conf_path = os.path.abspath(conf_path) poscar = os.path.join(conf_path, 'POSCAR') @@ -59,6 +59,7 @@ def comput_vasp_nev(jdata, conf_dir, write_stable = False) : if 'relax_incar' in jdata.keys(): vasp_str='vasp-relax_incar' else: + kspacing = jdata['vasp_params']['kspacing'] vasp_str='vasp-k%.2f' % kspacing ener_shift = comput_e_shift(poscar, vasp_str) From 8548fee7f0713b32283c3978b386f2fed4635cbe Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 14:12:47 +0800 Subject: [PATCH 53/93] Update cmpt_03_vacancy.py --- dpgen/auto_test/cmpt_03_vacancy.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/dpgen/auto_test/cmpt_03_vacancy.py b/dpgen/auto_test/cmpt_03_vacancy.py index e6fc93520..0c3c201e5 100755 --- a/dpgen/auto_test/cmpt_03_vacancy.py +++ b/dpgen/auto_test/cmpt_03_vacancy.py @@ -26,8 +26,6 @@ def comput_e_shift(poscar, task_name) : return ener_shift def cmpt_vasp(jdata, conf_dir, supercell) : - fp_params = jdata['vasp_params'] - kspacing = fp_params['kspacing'] if 'relax_incar' in jdata.keys(): vasp_str='vasp-relax_incar' From f15dddeaab8628c77f00d09870fe88429f7296c0 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 14:13:22 +0800 Subject: [PATCH 54/93] Update cmpt_04_interstitial.py --- dpgen/auto_test/cmpt_04_interstitial.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/dpgen/auto_test/cmpt_04_interstitial.py b/dpgen/auto_test/cmpt_04_interstitial.py index b6a39c4af..878dca15e 100755 --- a/dpgen/auto_test/cmpt_04_interstitial.py +++ b/dpgen/auto_test/cmpt_04_interstitial.py @@ -17,8 +17,6 @@ def cmpt_vasp(jdata, conf_dir, supercell, insert_ele) : _cmpt_vasp(jdata, conf_dir, supercell, ii) def _cmpt_vasp(jdata, conf_dir, supercell, insert_ele) : - fp_params = jdata['vasp_params'] - kspacing = fp_params['kspacing'] if 'relax_incar' in jdata.keys(): vasp_str='vasp-relax_incar' From 159c750da210884ec0ae7c72d29851f2b1234344 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 14:14:19 +0800 Subject: [PATCH 55/93] Update cmpt_04_interstitial.py --- dpgen/auto_test/cmpt_04_interstitial.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dpgen/auto_test/cmpt_04_interstitial.py b/dpgen/auto_test/cmpt_04_interstitial.py index 878dca15e..c87ef741e 100755 --- a/dpgen/auto_test/cmpt_04_interstitial.py +++ b/dpgen/auto_test/cmpt_04_interstitial.py @@ -54,12 +54,10 @@ def cmpt_deepmd_reprod_traj(jdata, conf_dir, supercell, insert_ele, task_name) : _cmpt_deepmd_reprod_traj(jdata, conf_dir, supercell, ii, task_name) def _cmpt_deepmd_reprod_traj(jdata, conf_dir, supercell, insert_ele, task_name) : - fp_params = jdata['vasp_params'] - kspacing = fp_params['kspacing'] - if 'relax_incar' in jdata.keys(): vasp_str='vasp-relax_incar' else: + kspacing = jdata['vasp_params']['kspacing'] vasp_str='vasp-k%.2f' % kspacing conf_path = os.path.abspath(conf_dir) From cb1c056668ec91e256a4c3686759f84938837a91 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 14:15:57 +0800 Subject: [PATCH 56/93] Update cmpt_05_surf.py --- dpgen/auto_test/cmpt_05_surf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dpgen/auto_test/cmpt_05_surf.py b/dpgen/auto_test/cmpt_05_surf.py index 1c1f9cb23..7f2790505 100755 --- a/dpgen/auto_test/cmpt_05_surf.py +++ b/dpgen/auto_test/cmpt_05_surf.py @@ -13,12 +13,11 @@ global_task_name = '05.surf' def cmpt_vasp(jdata, conf_dir, static = False) : - fp_params = jdata['vasp_params'] - kspacing = fp_params['kspacing'] if 'relax_incar' in jdata.keys(): vasp_str='vasp-relax_incar' - else: + else: + kspacing = jdata['vasp_params']['kspacing'] vasp_str='vasp-k%.2f' % (kspacing) equi_path = re.sub('confs', global_equi_name, conf_dir) @@ -30,6 +29,7 @@ def cmpt_vasp(jdata, conf_dir, static = False) : if 'scf_incar' in jdata.keys(): vasp_static_str='vasp-static-scf_incar' else: + kspacing = jdata['vasp_params']['kspacing'] vasp_static_str='vasp-static-k%.2f' % (kspacing) task_path = os.path.join(task_path, vasp_static_str) else : From 6b9be0739ae921efbcec68cb0b82d48ec6270fe8 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 14:18:50 +0800 Subject: [PATCH 57/93] Update gen_05_surf.py --- dpgen/auto_test/gen_05_surf.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/dpgen/auto_test/gen_05_surf.py b/dpgen/auto_test/gen_05_surf.py index ac275eb2f..776a0205f 100755 --- a/dpgen/auto_test/gen_05_surf.py +++ b/dpgen/auto_test/gen_05_surf.py @@ -11,20 +11,11 @@ global_task_name = '05.surf' def make_vasp(jdata, conf_dir, max_miller = 2, relax_box = False, static = False) : - fp_params = jdata['vasp_params'] - ecut = fp_params['ecut'] - ediff = fp_params['ediff'] - npar = fp_params['npar'] - kpar = fp_params['kpar'] - kspacing = fp_params['kspacing'] - kgamma = fp_params['kgamma'] - min_slab_size = jdata['min_slab_size'] - min_vacuum_size = jdata['min_vacuum_size'] - pert_xz = jdata['pert_xz'] if 'relax_incar' in jdata.keys(): vasp_str='vasp-relax_incar' else: + kspacing = jdata['vasp_params']['kspacing'] vasp_str='vasp-k%.2f' % (kspacing) # get conf poscar @@ -66,6 +57,16 @@ def make_vasp(jdata, conf_dir, max_miller = 2, relax_box = False, static = False scf_incar_path = os.path.abspath(scf_incar_path) fc = open(scf_incar_path).read() else : + fp_params = jdata['vasp_params'] + ecut = fp_params['ecut'] + ediff = fp_params['ediff'] + npar = fp_params['npar'] + kpar = fp_params['kpar'] + kspacing = fp_params['kspacing'] + kgamma = fp_params['kgamma'] + min_slab_size = jdata['min_slab_size'] + min_vacuum_size = jdata['min_vacuum_size'] + pert_xz = jdata['pert_xz'] fc = vasp.make_vasp_static_incar(ecut, ediff, npar=npar,kpar=kpar, kspacing = kspacing, kgamma = kgamma) else : if 'relax_incar' in jdata.keys(): @@ -74,6 +75,16 @@ def make_vasp(jdata, conf_dir, max_miller = 2, relax_box = False, static = False relax_incar_path = os.path.abspath(relax_incar_path) fc = open(relax_incar_path).read() else : + fp_params = jdata['vasp_params'] + ecut = fp_params['ecut'] + ediff = fp_params['ediff'] + npar = fp_params['npar'] + kpar = fp_params['kpar'] + kspacing = fp_params['kspacing'] + kgamma = fp_params['kgamma'] + min_slab_size = jdata['min_slab_size'] + min_vacuum_size = jdata['min_vacuum_size'] + pert_xz = jdata['pert_xz'] fc = vasp.make_vasp_relax_incar(ecut, ediff, True, relax_box, False, npar=npar,kpar=kpar, kspacing = kspacing, kgamma = kgamma) with open(os.path.join(task_path, 'INCAR'), 'w') as fp : fp.write(fc) From e36fff4853e8a3f94e621593bf3f1afe995ddba8 Mon Sep 17 00:00:00 2001 From: felix5572 Date: Thu, 24 Oct 2019 12:24:32 +0000 Subject: [PATCH 58/93] auto_gen_param --- dpgen/dispatcher/AWS.py | 3 ++- dpgen/tools/auto_gen_param.py | 21 ++++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) mode change 100644 => 100755 dpgen/tools/auto_gen_param.py diff --git a/dpgen/dispatcher/AWS.py b/dpgen/dispatcher/AWS.py index 6cf0b8497..eab67657e 100644 --- a/dpgen/dispatcher/AWS.py +++ b/dpgen/dispatcher/AWS.py @@ -105,8 +105,9 @@ def sub_script(self, job_dirs, cmd, args, res, outlog, errlog): multi_command = "" for job_dir in job_dirs: for idx,t in enumerate(zip_longest(cmd, args, fillvalue='')): - c_str = f"((cd {self.context.remote_root}/{job_dir} && (test -f tag_{idx}_finished || {t[0]} {t[1]} 2>>{errlog} && touch tag_{idx}_finished ) | tee -a {outlog}));wait;" + c_str = f"cd {self.context.remote_root}/{job_dir} && ( test -f tag_{idx}_finished || ( ({t[0]} {t[1]} && touch tag_{idx}_finished 2>>{errlog} || exit 52 ) | tee -a {outlog}) ) || exit 51;" multi_command += c_str + multi_command +="exit 0;" dlog.debug("10000, %s" % multi_command) return multi_command diff --git a/dpgen/tools/auto_gen_param.py b/dpgen/tools/auto_gen_param.py old mode 100644 new mode 100755 index d2ae065c6..75faa7337 --- a/dpgen/tools/auto_gen_param.py +++ b/dpgen/tools/auto_gen_param.py @@ -101,7 +101,7 @@ def gen_sub_iter(self, system_list): sub_iter_list.append(iter_dict) return sub_iter_list -def default_map_generator(map_list=[1,1,2,2,4,4,4,4], data_list=None): +def default_map_generator(map_list=[1,1,2,2,2,4,4,4], data_list=None): num = 0 # if len(data_list) < sum(map_list): # raise RuntimeError(f'{data_list} < {map_list};not enough structure to expore, data_list_too_short!') @@ -119,7 +119,7 @@ def default_map_generator(map_list=[1,1,2,2,4,4,4,4], data_list=None): # num += ii def get_system_list(system_dict, - map_list=[1,1,2,2,4,4,4,4], + map_list=[1,1,2,2,2,4,4,4], meta_iter_num=4, sub_iteration_num=8, map_iterator=None, @@ -134,6 +134,7 @@ def get_system_list(system_dict, system_list = [] for system_prefix,data_list in system_dict.items(): if map_iterator is None: + print('12', data_list) new_map_iterator = default_map_generator(map_list=map_list, data_list=data_list) else: origin_one, new_map_iterator = tee(map_iterator) # pylint: disable=unused-variable @@ -227,8 +228,8 @@ def get_basic_param_json(melt_point, scan_dir="./", file_name='POSCAR', init_file_name='type.raw', - min_allow_files_num=20, - map_list=[1,1,2,2,4,4,4,4], + min_allow_files_num=16, + map_list=[1,1,2,2,2,4,4,4], meta_iter_num=4, sub_iteration_num=8, map_iterator=None, @@ -241,7 +242,7 @@ def get_basic_param_json(melt_point, num_temps=5,): init_data_sys = get_init_data_sys(scan_dir=scan_dir, init_file_name=init_file_name) - print(f"length of init_data_sys: {len(init_data_sys)}") + print(f"length of init_data_sys: {len(init_data_sys)} {init_data_sys}") system_dict = scan_files(scan_dir, file_name, min_allow_files_num) print(f"num of different systems: {len(system_dict)}") system_list =get_system_list(system_dict, @@ -272,4 +273,14 @@ def get_basic_param_json(melt_point, with open(out_param_filename, 'w') as p: json.dump(param_dict, p, indent=4) +def _main(): + parser = argparse.ArgumentParser(description='Collect data from inputs and generate basic param.json') + parser.add_argument("melt_point", type=float, help="melt_point") + # parser.addparser.add_argument("JOB_DIR", type=str, help="the directory of the DP-GEN job") + args = parser.parse_args() + get_basic_param_json(melt_point=args.melt_point) + +if __name__=='__main__': + _main() + #%% From 0962e362c9d4446c6b96aac67cd8c77e35547496 Mon Sep 17 00:00:00 2001 From: felix5572 Date: Thu, 24 Oct 2019 12:54:20 +0000 Subject: [PATCH 59/93] add auto gen basic paramjson & AWS bug fix --- dpgen/dispatcher/AWS.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dpgen/dispatcher/AWS.py b/dpgen/dispatcher/AWS.py index eab67657e..7554b470d 100644 --- a/dpgen/dispatcher/AWS.py +++ b/dpgen/dispatcher/AWS.py @@ -93,13 +93,6 @@ def check_status(self): return self.__class__.AWS_check_status(job_id=self.job_id) def sub_script(self, job_dirs, cmd, args, res, outlog, errlog): - """ - return a command_Str like(indeed withoud tailing \n): - ((cd /home/ec2-user/Ag_init/run_gen/iter.000000/00.train/001 && /usr/bin/dp_train input.json 2>>train.log |tee -a train.log)&& touch tag_0_finished);wait; - ((cd /home/ec2-user/Ag_init/run_gen/iter.000000/00.train/001 && /usr/bin/dp_frz 2>>train.log |tee -a train.log)&& touch tag_1_finished);wait; - ((cd /home/ec2-user/Ag_init/run_gen/iter.000000/00.train/003 && /usr/bin/dp_train input.json 2>>train.log |tee -a train.log)&& touch tag_0_finished);wait; - ((cd /home/ec2-user/Ag_init/run_gen/iter.000000/00.train/003 && /usr/bin/dp_frz 2>>train.log |tee -a train.log)&& touch tag_1_finished);wait; - """ if args is None: args=[] multi_command = "" From a94f567af5ed0b13528d782669e8337be572b54b Mon Sep 17 00:00:00 2001 From: BaozCWJ Date: Thu, 24 Oct 2019 23:15:01 +0800 Subject: [PATCH 60/93] add insert_data --- dpgen/auto_test/.DS_Store | Bin 0 -> 10244 bytes dpgen/auto_test/cmpt_01_eos.py | 18 +++-- dpgen/auto_test/cmpt_02_elastic.py | 25 ++++-- dpgen/auto_test/cmpt_05_surf.py | 20 ++--- dpgen/auto_test/lib/insert_data.py | 9 +++ dpgen/auto_test/lib/util.py | 8 ++ dpgen/auto_test/lib/vasp.py | 35 +++++---- dpgen/auto_test/run.py | 122 ++++++++++++++--------------- 8 files changed, 136 insertions(+), 101 deletions(-) create mode 100644 dpgen/auto_test/.DS_Store create mode 100644 dpgen/auto_test/lib/insert_data.py diff --git a/dpgen/auto_test/.DS_Store b/dpgen/auto_test/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..9630a94f683f16f29ffc072f7b106ec27f5e43bc GIT binary patch literal 10244 zcmeHMTWl0n82&N;IHfZZ9b2_Oal5?xFx6_gc7tessqq!O>DmL!rsfB`NH(Qhq`-q1U& z2oVSo2oVSo2oVSo_&*>(Yc@;LTp`0eL?A>UL|_^L_I`-b#bn%*Q$q4r2W9*SK(dUg zd7?6%1GrAilW|W@3CUH-rZ_#Ir;6SY1BE)Z$5?lgaZgSODbxXlI-oZ)dM6a*qmy2Y zcL$6M8Rj7ZAp$odz|QV-`I+4SD{y`v?=$UG(zKJ*gFRH8bk+aO6O{nwLkdRdoX<}D zjr1D=9Zo`qY_QXRzV>T*+VcY1Ok1+$Q~5;f0S5YJY!<`9}`I95oTN8?3b zG^zr=w2}5G41-Pnu&Y=^{1$?!t|to#`lYxJS(;M;8$2?88`S|X+R27S2sng*O)V;q zPZ58RMaXYUA`P1uHo{|~ffM8-vS|4G&x7OSrA1@jl8qdDziy>Z_oiHAxT6%n{radg zVj|F!P}IWAcu3Dfz(Tdp``ct8Lp@;2kK!#j$RZHXReXNTfPpLu0sShU{*3s?qjAa? zjYU2Sx5Yjl6~Cp5X-kZS7CnVU-%aS(DY-5GTC zQ!XnVbnLX-!#fTdq|54tlm$$G_o!>wma|_^J0xZK^@>Hc%U9ml*!sYOy;myd%~z@x z$nrtL!*Y#dhMwLxW@zs40o6(AmS$MT2eO7^Bu%~FQb+VEY?b9J)isMNBhkp+xu$#- zNvV?tGfCrQ#&E~^7)zH$!UR_|FXIZ}wM(JfoI_5LShy;>m{ zde_25OY7>_G_T*#H66*k*!fAsnIovdDU+iF4_<(WEZULi61lb*m-i9l^ivX}jWS#G zjzyPC#1w^7B@$f`T_q8nl@i`6uZ~hrRZ>bt=XG+EMD$cWumo1?v#k9 zO1Ws=B*$g;h$$fMS44YdNx@?5E6TlB;R0NS58xBx+}Cgoet@6hPXsJSh4U?nORyGK z;wrosS7QUVVjD5913R%7H{({^M(j&qKkml?JV5MAarO=4Nlc@Q8DilSK1LiogHL!Y zd=8(-SMYou=lXJN6A~|8=Ug_CwoKbPPBo07<+R(&6yB}zwbs9aNPM5k_TOyhOMA}X zio@4dfBy=4CT+5Rg4VH7(nuBF(eV}aC*O)HoDTC4fe?W^4S`ZIp&0xAzq$DT|99H7 z!}){=gb4T$z_Q*%Z#Pxsw#mLWUS!|eV{{#*izU`?N=U9k8UGwll7Eh;8}>P#pBAXj nJ120xIMp-#DIuvu>0kddpy2n(zzID(|I@dC@ce)0p8x*=h=>iv literal 0 HcmV?d00001 diff --git a/dpgen/auto_test/cmpt_01_eos.py b/dpgen/auto_test/cmpt_01_eos.py index 93177148f..0000710c5 100755 --- a/dpgen/auto_test/cmpt_01_eos.py +++ b/dpgen/auto_test/cmpt_01_eos.py @@ -1,12 +1,13 @@ #!/usr/bin/env python3 import os, glob, argparse, json, re +import dpgen.auto_test.lib.util as util import dpgen.auto_test.lib.lammps as lammps import dpgen.auto_test.lib.vasp as vasp global_task_name = '01.eos' -def comput_lmp_eos(conf_dir, task_name) : +def comput_lmp_eos(jdata,conf_dir, task_name) : conf_path = re.sub('confs', global_task_name, conf_dir) conf_path = os.path.abspath(conf_path) conf_path = os.path.join(conf_path, task_name) @@ -20,6 +21,9 @@ def comput_lmp_eos(conf_dir, task_name) : natoms, epa, vpa = lammps.get_nev(log_lammps) print(vpa, epa) fp.write('%7.3f %8.4f \n' % (vpa,epa)) + if 'upload_username' in jdata.keys() and task_name =='deepmd': + upload_username=jdata['upload_username'] + util.insert_data('eos','deepmd',upload_username,'result') def comput_vasp_eos(jdata, conf_dir) : conf_path = re.sub('confs', global_task_name, conf_dir) @@ -41,12 +45,15 @@ def comput_vasp_eos(jdata, conf_dir) : natoms, epa, vpa = vasp.get_nev(outcar) print(vpa, epa) fp.write('%7.3f %8.4f \n' % (vpa,epa)) + if 'upload_username' in jdata.keys(): + upload_username=jdata['upload_username'] + util.insert_data('eos','vasp',upload_username,'result') def _main(): parser = argparse.ArgumentParser( description="cmpt 01.eos") parser.add_argument('TASK', type=str, - choices = ['vasp', 'deepmd', 'meam'], + choices = ['vasp', 'deepmd', 'meam'], help='the task of generation, vasp or lammps') parser.add_argument('PARAM', type=str, help='json parameter file') @@ -58,14 +65,13 @@ def _main(): jdata = json.load (fp) if args.TASK == 'vasp': - comput_vasp_eos(jdata, args.CONF) + comput_vasp_eos(jdata, args.CONF) elif args.TASK == 'deepmd' : - comput_lmp_eos(args.CONF, args.TASK) + comput_lmp_eos(jdata,args.CONF, args.TASK) elif args.TASK == 'meam' : - comput_lmp_eos(args.CONF, args.TASK) + comput_lmp_eos(jdata,args.CONF, args.TASK) else : raise RuntimeError("unknow task ", args.TASK) if __name__ == '__main__' : _main() - diff --git a/dpgen/auto_test/cmpt_02_elastic.py b/dpgen/auto_test/cmpt_02_elastic.py index 976a23483..7eb9e376f 100755 --- a/dpgen/auto_test/cmpt_02_elastic.py +++ b/dpgen/auto_test/cmpt_02_elastic.py @@ -5,6 +5,7 @@ import numpy as np import dpgen.auto_test.lib.vasp as vasp import dpgen.auto_test.lib.lammps as lammps +import dpgen.auto_test.lib.util as util from pymatgen.analysis.elasticity.elastic import ElasticTensor from pymatgen.analysis.elasticity.strain import Strain from pymatgen.analysis.elasticity.stress import Stress @@ -28,7 +29,8 @@ def result_et(et,conf_dir,task_path): fp.write("# Youngs Modulus EV = %.2f GPa\n" % (EV)) fp.write("# Poission Ratio uV = %.2f \n" % (uV)) -def print_et (et): + +def print_et (et): for ii in range(6) : for jj in range(6) : sys.stdout.write ("%7.2f " % (et.voigt[ii][jj] / 1e4)) @@ -51,7 +53,7 @@ def cmpt_vasp(jdata, conf_dir) : else: fp_params = jdata['vasp_params'] kspacing = fp_params['kspacing'] - vasp_str='vasp-k%.2f' % kspacing + vasp_str='vasp-k%.2f' % kspacing task_path = os.path.join(task_path, vasp_str) equi_stress = Stress(np.loadtxt(os.path.join(task_path, 'equi.stress.out'))) @@ -69,9 +71,13 @@ def cmpt_vasp(jdata, conf_dir) : et = ElasticTensor.from_independent_strains(lst_strain, lst_stress, eq_stress = equi_stress, vasp = False) # et = ElasticTensor.from_independent_strains(lst_strain, lst_stress, eq_stress = None) # bar to GPa - # et = -et / 1e4 + # et = -et / 1e4 print_et(et) result_et(et,conf_dir,task_path) + if 'upload_username' in jdata.keys(): + upload_username=jdata['upload_username'] + util.insert_data('elastic','vasp',upload_username,'result') + def cmpt_deepmd_lammps(jdata, conf_dir, task_name) : conf_path = os.path.abspath(conf_dir) @@ -93,9 +99,14 @@ def cmpt_deepmd_lammps(jdata, conf_dir, task_name) : et = ElasticTensor.from_independent_strains(lst_strain, lst_stress, eq_stress = equi_stress, vasp = False) # et = ElasticTensor.from_independent_strains(lst_strain, lst_stress, eq_stress = None) # bar to GPa - # et = -et / 1e4 + # et = -et / 1e4 print_et(et) result_et(et,conf_dir,task_path) + if 'upload_username' in jdata.keys() and task_name=='deepmd': + upload_username=jdata['upload_username'] + util.insert_data('elastic','deepmd',upload_username,'result') + + def _main() : parser = argparse.ArgumentParser( @@ -113,15 +124,13 @@ def _main() : print('# generate %s task with conf %s' % (args.TASK, args.CONF)) if args.TASK == 'vasp': - cmpt_vasp(jdata, args.CONF) + cmpt_vasp(jdata, args.CONF) elif args.TASK == 'deepmd' : cmpt_deepmd_lammps(jdata, args.CONF, args.TASK) elif args.TASK == 'meam' : cmpt_deepmd_lammps(jdata, args.CONF, args.TASK) else : raise RuntimeError("unknow task ", args.TASK) - + if __name__ == '__main__' : _main() - - diff --git a/dpgen/auto_test/cmpt_05_surf.py b/dpgen/auto_test/cmpt_05_surf.py index 7f2790505..5e58cfac7 100755 --- a/dpgen/auto_test/cmpt_05_surf.py +++ b/dpgen/auto_test/cmpt_05_surf.py @@ -3,11 +3,9 @@ import os, re, argparse, filecmp, json, glob, sys import subprocess as sp import numpy as np +import dpgen.auto_test.lib.util as util import dpgen.auto_test.lib.vasp as vasp import dpgen.auto_test.lib.lammps as lammps -from pymatgen.analysis.elasticity.elastic import ElasticTensor -from pymatgen.analysis.elasticity.strain import Strain -from pymatgen.analysis.elasticity.stress import Stress global_equi_name = '00.equi' global_task_name = '05.surf' @@ -44,7 +42,7 @@ def cmpt_vasp(jdata, conf_dir, static = False) : if len(struct_path_list) == 0: print("# cannot find results for conf %s" % (conf_dir)) sys.stdout.write ("Miller_Indices: \tSurf_E(J/m^2) EpA(eV) equi_EpA(eV)\n") - + with open(os.path.join(task_path,'result'),'w') as fp: fp.write('conf_dir:%s\n'% (conf_dir)) fp.write("Miller_Indices: \tSurf_E(J/m^2) EpA(eV) equi_EpA(eV)\n") @@ -61,6 +59,9 @@ def cmpt_vasp(jdata, conf_dir, static = False) : evac = (epa * natoms - equi_epa * natoms) / AA * Cf sys.stdout.write ("%s:\t %7.3f %8.3f %8.3f\n" % (structure_dir, evac, epa, equi_epa)) fp.write("%s:\t %7.3f %8.3f %8.3f\n" % (structure_dir, evac, epa, equi_epa)) + if 'upload_username' in jdata.keys(): + upload_username=jdata['upload_username'] + util.insert_data('surf','vasp',upload_username,'result') def cmpt_deepmd_lammps(jdata, conf_dir, task_name, static = False) : equi_path = re.sub('confs', global_equi_name, conf_dir) @@ -91,6 +92,9 @@ def cmpt_deepmd_lammps(jdata, conf_dir, task_name, static = False) : evac = (epa * natoms - equi_epa * natoms) / AA * Cf sys.stdout.write ("%s: \t%7.3f %8.3f %8.3f\n" % (structure_dir, evac, epa, equi_epa)) fp.write("%s:\t %7.3f %8.3f %8.3f\n" % (structure_dir, evac, epa, equi_epa)) + if 'upload_username' in jdata.keys() and task_name=='deepmd': + upload_username=jdata['upload_username'] + util.insert_data('surf','deepmd',upload_username,'result') def _main() : parser = argparse.ArgumentParser( @@ -108,9 +112,9 @@ def _main() : print('# generate %s task with conf %s' % (args.TASK, args.CONF)) if args.TASK == 'vasp': - cmpt_vasp(jdata, args.CONF) + cmpt_vasp(jdata, args.CONF) elif args.TASK == 'vasp-static': - cmpt_vasp(jdata, args.CONF, static = True) + cmpt_vasp(jdata, args.CONF, static = True) elif args.TASK == 'deepmd' : cmpt_deepmd_lammps(jdata, args.CONF, args.TASK) elif args.TASK == 'deepmd-static' : @@ -121,8 +125,6 @@ def _main() : cmpt_deepmd_lammps(jdata, args.CONF, args.TASK, static = True) else : raise RuntimeError("unknow task ", args.TASK) - + if __name__ == '__main__' : _main() - - diff --git a/dpgen/auto_test/lib/insert_data.py b/dpgen/auto_test/lib/insert_data.py new file mode 100644 index 000000000..e8598a3c3 --- /dev/null +++ b/dpgen/auto_test/lib/insert_data.py @@ -0,0 +1,9 @@ +#coding=utf-8 +# ls 0{1,2,5}*/*/*/vasp-k0.10/result|python insert_data.py +import sys +import requests +for line in sys.stdin: + expr_type, element, structure, data_type, result = line.strip().split('/') + expr_type = expr_type.split('.')[-1] + data_type = data_type.split('-')[0].strip() + res = requests.post('http://115.27.161.2:5000/insert_test_data?username=chenweijie&expr_type=%s&data_type=%s' % (data_type, expr_type), data=open(line.strip()).read()) diff --git a/dpgen/auto_test/lib/util.py b/dpgen/auto_test/lib/util.py index 9daf226dd..159d2248a 100644 --- a/dpgen/auto_test/lib/util.py +++ b/dpgen/auto_test/lib/util.py @@ -1,4 +1,5 @@ import numpy as np +import requests def voigt_to_stress(inpt) : ret = np.zeros((3,3)) @@ -12,3 +13,10 @@ def voigt_to_stress(inpt) : ret[1][0] = ret[0][1] ret[2][1] = ret[1][2] return ret + +def insert_data(task,task_type,username,file_name): + assert task in ['eos','elastic','surf'] + assert task_type in ['vasp','deepmd'] + url='http://115.27.161.2:5000/insert_test_data?username=%s&expr_type=%s&data_type=%s' % (username,task_type,task) + res = requests.post(url, data=open(file_name).read()) + print('Successful upload!') diff --git a/dpgen/auto_test/lib/vasp.py b/dpgen/auto_test/lib/vasp.py index b54cd47f2..5022e4b74 100644 --- a/dpgen/auto_test/lib/vasp.py +++ b/dpgen/auto_test/lib/vasp.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/python3 import warnings import numpy as np @@ -43,7 +43,7 @@ def regulate_poscar(poscar_in, poscar_out) : for ii in posis : ele_name = ii.split()[-1] if ele_name == ele : - ele_lines.append(ii) + ele_lines.append(ii) all_lines += ele_lines all_lines.append('') ret = lines[0:5] @@ -70,7 +70,7 @@ def sort_poscar(poscar_in, poscar_out, new_names) : for ii in posis : ele_name = ii.split()[-1] if ele_name == ele : - ele_lines.append(ii) + ele_lines.append(ii) all_lines += ele_lines all_lines.append('') ret = lines[0:5] @@ -79,7 +79,7 @@ def sort_poscar(poscar_in, poscar_out, new_names) : ret.append("Direct") ret += all_lines with open(poscar_out, 'w') as fp: - fp.write("\n".join(ret)) + fp.write("\n".join(ret)) def perturb_xz (poscar_in, poscar_out, pert = 0.01) : with open(poscar_in, 'r') as fp: @@ -119,7 +119,7 @@ def get_energies (fname) : if not check_finished(fname): warnings.warn("incomplete outcar: "+fname) with open(fname, 'r') as fp: - lines = fp.read().split('\n') + lines = fp.read().split('\n') try : ener = _get_energies(lines) return ener @@ -130,7 +130,7 @@ def get_boxes (fname) : if not check_finished(fname): warnings.warn("incomplete outcar: "+fname) with open(fname, 'r') as fp: - lines = fp.read().split('\n') + lines = fp.read().split('\n') try : ener = _get_boxes(lines) return ener @@ -141,7 +141,7 @@ def get_nev(fname) : if not check_finished(fname): warnings.warn("incomplete outcar: "+fname) with open(fname, 'r') as fp: - lines = fp.read().split('\n') + lines = fp.read().split('\n') try: natoms = _get_natoms(lines) vol = _get_volumes(lines)[-1] @@ -155,7 +155,7 @@ def get_stress(fname) : if not check_finished(fname): warnings.warn("incomplete outcar: "+fname) with open(fname, 'r') as fp: - lines = fp.read().split('\n') + lines = fp.read().split('\n') try: stress = _get_stress(lines)[-1] return stress @@ -163,7 +163,7 @@ def get_stress(fname) : return None def check_finished(fname) : - with open(fname, 'r') as fp: + with open(fname, 'r') as fp: return 'Elapsed time (sec):' in fp.read() def _get_natoms(lines) : @@ -217,9 +217,9 @@ def _get_stress(lines) : items.append(util.voigt_to_stress(sv)) if len(items) == 0: raise OutcarItemError("cannot find item 'in kB'") - return items + return items -def _compute_isif (relax_ions, +def _compute_isif (relax_ions, relax_shape, relax_volume) : if (relax_ions) and (not relax_shape) and (not relax_volume) : @@ -321,8 +321,8 @@ def make_vasp_relax_incar (ecut, ediff, return ret def make_vasp_phonon_incar (ecut, ediff, - npar, kpar, - kspacing = 0.5, kgamma = True, + npar, kpar, + kspacing = 0.5, kgamma = True, ismear = 1, sigma = 0.2) : isif = 2 ret = '' @@ -399,7 +399,7 @@ def _poscar_scale_cartesian (str_in, scale) : cv = [float(ii) for ii in cl] cv = np.array(cv) * scale lines[ii] = "%.16e %.16e %.16e\n" % (cv[0], cv[1], cv[2]) - return lines + return lines def poscar_natoms(poscar_in) : with open(poscar_in, 'r') as fin : @@ -409,9 +409,9 @@ def poscar_natoms(poscar_in) : def poscar_scale (poscar_in, poscar_out, scale) : with open(poscar_in, 'r') as fin : lines = list(fin) - if 'D' == lines[7][0] or 'd' == lines[7][0] : + if 'D' == lines[7][0] or 'd' == lines[7][0] : lines = _poscar_scale_direct(lines, scale) - elif 'C' == lines[7][0] or 'c' == lines[7][0] : + elif 'C' == lines[7][0] or 'c' == lines[7][0] : lines = _poscar_scale_cartesian(lines, scale) else : raise RuntimeError("Unknow poscar coord style at line 7: %s" % lines[7]) @@ -451,7 +451,8 @@ def _make_vasp_kp_mp(kpoints): def make_vasp_kpoints (kpoints, kgamma = False) : if kgamma : - ret = _make_vasp_kp_gamma(kpoints) + ret = _make_vasp_kp_gamma(kpoints) else : ret = _make_vasp_kp_mp(kpoints) return ret + diff --git a/dpgen/auto_test/run.py b/dpgen/auto_test/run.py index 3dd1ac8f5..b730fec68 100644 --- a/dpgen/auto_test/run.py +++ b/dpgen/auto_test/run.py @@ -74,7 +74,7 @@ def _run(machine, common_files, forward_files, backward_files) - elif machine_type == 'slurm' : + elif machine_type == 'slurm' : print("The second situation!") group_slurm_jobs(ssh_sess, resources, @@ -86,7 +86,7 @@ def _run(machine, forward_files, backward_files, forward_task_deference =False) - elif machine_type == 'pbs' : + elif machine_type == 'pbs' : group_slurm_jobs(ssh_sess, resources, command, @@ -98,7 +98,7 @@ def _run(machine, backward_files, remote_job = PBSJob, forward_task_deference =False) - elif machine_type == 'local' : + elif machine_type == 'local' : group_local_jobs(ssh_sess, resources, command, @@ -131,7 +131,7 @@ def make_work_path(jdata,task,reprod_opt,static,user): else: if 'relax_incar' in jdata.keys(): task_type=task_type+'-relax_incar' - else: + else: kspacing = jdata['vasp_params']['kspacing'] task_type=task_type+'-k%.2f' % (kspacing) elif task_type in lammps_task_type: @@ -159,13 +159,13 @@ def gen_equi(task_type,jdata,mdata): else : raise RuntimeError ("unknow task %s, something wrong" % task_type) os.chdir(cwd) - + def run_equi(task_type,jdata,mdata,ssh_sess): #rmprint("This module has been run !") work_path=make_work_path(jdata,'00.equi',False,False,False) all_task = glob.glob(os.path.join(work_path,'.')) - + #vasp if task_type=="vasp": mdata=decide_fp_machine(mdata) @@ -198,7 +198,7 @@ def run_equi(task_type,jdata,mdata,ssh_sess): resources = mdata['model_devi_resources'] machine=mdata['model_devi_machine'] machine_type = mdata['model_devi_machine']['machine_type'] - + command = lmp_exec + " -i lammps.in" command = cmd_append_log(command, "model_devi.log") @@ -216,7 +216,7 @@ def run_equi(task_type,jdata,mdata,ssh_sess): run_tasks_.append(ii) else : run_tasks_.append(ii) - + forward_files = ['conf.lmp', 'lammps.in'] backward_files = ['dump.relax','log.lammps', 'model_devi.log'] @@ -230,13 +230,13 @@ def run_equi(task_type,jdata,mdata,ssh_sess): else: models = [os.path.join(model_dir,ii) for ii in model_name] common_files = model_name - + if len(model_name)>1 and task_type == 'deepmd': backward_files = backward_files + ['model_devi.out'] else: raise RuntimeError ("unknow task %s, something wrong" % task_type) - + run_tasks = [os.path.basename(ii) for ii in run_tasks_] _run(machine, machine_type, @@ -271,13 +271,13 @@ def gen_eos(task_type,jdata,mdata): cwd=os.getcwd() #vasp if task_type == "vasp": - gen_01_eos.make_vasp(jdata, conf_dir) - #lammps + gen_01_eos.make_vasp(jdata, conf_dir) + #lammps elif task_type in lammps_task_type: if fix_shape : gen_01_eos.make_lammps_fixv(jdata, conf_dir,task_type) else : - gen_01_eos.make_lammps(jdata, conf_dir,task_type) + gen_01_eos.make_lammps(jdata, conf_dir,task_type) else : raise RuntimeError("unknow task ", task_type) os.chdir(cwd) @@ -288,7 +288,7 @@ def run_eos(task_type,jdata,mdata,ssh_sess): all_task = glob.glob(os.path.join(work_path, "vol-*")) all_task.sort() - + #vasp if task_type=="vasp": mdata=decide_fp_machine(mdata) @@ -351,7 +351,7 @@ def run_eos(task_type,jdata,mdata,ssh_sess): forward_files = ['conf.lmp', 'lammps.in']+model_name backward_files = ['log.lammps', 'model_devi.log'] common_files=['lammps.in']+model_name - + if len(model_name)>1 and task_type == 'deepmd': backward_files = backward_files + ['model_devi.out'] @@ -375,10 +375,10 @@ def cmpt_eos(task_type,jdata,mdata): conf_dir=jdata['conf_dir'] #vasp if task_type == "vasp": - cmpt_01_eos.comput_vasp_eos(jdata, conf_dir) - #lammps + cmpt_01_eos.comput_vasp_eos(jdata, conf_dir) + #lammps elif task_type in lammps_task_type: - cmpt_01_eos.comput_lmp_eos(conf_dir, task_type) + cmpt_01_eos.comput_lmp_eos(jdata, conf_dir, task_type) else : raise RuntimeError("unknow task ", task_type) @@ -398,10 +398,10 @@ def gen_elastic(task_type,jdata,mdata): def run_elastic(task_type,jdata,mdata,ssh_sess): work_path=make_work_path(jdata,'02.elastic',False,False,False) print(work_path) - + all_task = glob.glob(os.path.join(work_path, "dfm-*")) all_task.sort() - + #vasp if task_type == "vasp": mdata=decide_fp_machine(mdata) @@ -464,13 +464,13 @@ def run_elastic(task_type,jdata,mdata,ssh_sess): forward_files = ['conf.lmp', 'lammps.in','strain.out']+model_name backward_files = ['log.lammps', 'model_devi.log'] common_files=['lammps.in']+model_name - + if len(model_name)>1 and task_type == 'deepmd': backward_files = backward_files + ['model_devi.out'] else: raise RuntimeError ("unknow task %s, something wrong" % task_type) - + run_tasks = [os.path.basename(ii) for ii in run_tasks_] _run(machine, machine_type, @@ -483,16 +483,16 @@ def run_elastic(task_type,jdata,mdata,ssh_sess): common_files, forward_files, backward_files) - + def cmpt_elastic(task_type,jdata,mdata): conf_dir=jdata['conf_dir'] if task_type == "vasp": - cmpt_02_elastic.cmpt_vasp(jdata, conf_dir) + cmpt_02_elastic.cmpt_vasp(jdata, conf_dir) elif task_type in lammps_task_type: cmpt_02_elastic.cmpt_deepmd_lammps(jdata, conf_dir, task_type) else : raise RuntimeError ("unknow task %s, something wrong" % task_type) - + def gen_vacancy(task_type,jdata,mdata): conf_dir=jdata['conf_dir'] supercell=jdata['supercell'] @@ -511,7 +511,7 @@ def run_vacancy(task_type,jdata,mdata,ssh_sess): work_path=make_work_path(jdata,'03.vacancy',False,False,False) all_task = glob.glob(os.path.join(work_path,'struct-*')) - + #vasp if task_type == "vasp": mdata=decide_fp_machine(mdata) @@ -531,7 +531,7 @@ def run_vacancy(task_type,jdata,mdata,ssh_sess): run_tasks_.append(ii) else : run_tasks_.append(ii) - + forward_files = ['INCAR', 'POSCAR','POTCAR'] backward_files = ['OUTCAR','OSZICAR'] common_files=['INCAR','POTCAR'] @@ -561,7 +561,7 @@ def run_vacancy(task_type,jdata,mdata,ssh_sess): run_tasks_.append(ii) else : run_tasks_.append(ii) - + fp_params = jdata['lammps_params'] model_dir = fp_params['model_dir'] model_dir = os.path.abspath(model_dir) @@ -581,7 +581,7 @@ def run_vacancy(task_type,jdata,mdata,ssh_sess): else: raise RuntimeError ("unknow task %s, something wrong" % task_type) - + run_tasks = [os.path.basename(ii) for ii in run_tasks_] _run(machine, machine_type, @@ -600,7 +600,7 @@ def cmpt_vacancy(task_type,jdata,mdata): supercell=jdata['supercell'] #vasp if task_type == "vasp": - cmpt_03_vacancy.cmpt_vasp(jdata, conf_dir, supercell) + cmpt_03_vacancy.cmpt_vasp(jdata, conf_dir, supercell) #lammps elif task_type in lammps_task_type: cmpt_03_vacancy.cmpt_deepmd_lammps(jdata, conf_dir, supercell, task_type) @@ -631,7 +631,7 @@ def run_interstitial(task_type,jdata,mdata,ssh_sess): reprod_opt=jdata['reprod-opt'] work_path=make_work_path(jdata,'04.interstitial',reprod_opt,False,False) all_task = glob.glob(os.path.join(work_path,'struct-*')) - + #vasp if task_type == "vasp": mdata=decide_fp_machine(mdata) @@ -651,7 +651,7 @@ def run_interstitial(task_type,jdata,mdata,ssh_sess): run_tasks_.append(ii) else : run_tasks_.append(ii) - + forward_files = ['INCAR', 'POSCAR','POTCAR'] backward_files = ['OUTCAR','XDATCAR','OSZICAR'] common_files=['INCAR'] @@ -666,7 +666,7 @@ def run_interstitial(task_type,jdata,mdata,ssh_sess): machine_type = mdata['model_devi_machine']['machine_type'] command = lmp_exec + " -i lammps.in" command = cmd_append_log(command, "model_devi.log") - + if reprod_opt: all_frame=[] for ii in all_task: @@ -701,7 +701,7 @@ def run_interstitial(task_type,jdata,mdata,ssh_sess): forward_files = ['conf.lmp', 'lammps.in']+model_name backward_files = ['log.lammps', 'model_devi.log'] common_files=['lammps.in']+model_name - + if len(model_name)>1 and task_type == 'deepmd': backward_files = backward_files + ['model_devi.out'] @@ -717,7 +717,7 @@ def run_interstitial(task_type,jdata,mdata,ssh_sess): _run(machine, machine_type, ssh_sess, - resources, + resources, command, ii, run_tasks, @@ -778,9 +778,9 @@ def gen_surf(task_type,jdata,mdata): def run_surf(task_type,jdata,mdata,ssh_sess): static=jdata['static-opt'] work_path=make_work_path(jdata,'05.surf',False,static,False) - + all_task = glob.glob(os.path.join(work_path,'struct-*')) - + #vasp if task_type == "vasp": mdata=decide_fp_machine(mdata) @@ -800,7 +800,7 @@ def run_surf(task_type,jdata,mdata,ssh_sess): run_tasks_.append(ii) else : run_tasks_.append(ii) - + forward_files = ['INCAR', 'POSCAR','POTCAR'] backward_files = ['OUTCAR','OSZICAR'] @@ -844,13 +844,13 @@ def run_surf(task_type,jdata,mdata,ssh_sess): forward_files = ['conf.lmp', 'lammps.in']+model_name backward_files = ['log.lammps','model_devi.log'] common_files=['lammps.in']+model_name - + if len(model_name)>1 and task_type == 'deepmd': backward_files = backward_files + ['model_devi.out'] else: raise RuntimeError ("unknow task %s, something wrong" % task_type) - + run_tasks = [os.path.basename(ii) for ii in run_tasks_] _run(machine, machine_type, @@ -870,8 +870,8 @@ def cmpt_surf(task_type,jdata,mdata): cwd=os.getcwd() #vasp if task_type == "vasp": - cmpt_05_surf.cmpt_vasp(jdata, conf_dir, static = static_opt) - #lammps + cmpt_05_surf.cmpt_vasp(jdata, conf_dir, static = static_opt) + #lammps elif task_type in lammps_task_type : if static_opt: task_name =task_type+'-static' @@ -898,9 +898,9 @@ def gen_phonon(task_type,jdata,mdata): def run_phonon(task_type,jdata,mdata,ssh_sess): user= ('user_incar' in jdata.keys()) work_path=make_work_path(jdata,'06.phonon',False,False,user) - + all_task = glob.glob(os.path.join(work_path,'.')) - + #vasp if task_type == "vasp": mdata=decide_fp_machine(mdata) @@ -920,7 +920,7 @@ def run_phonon(task_type,jdata,mdata,ssh_sess): run_tasks_.append(ii) else : run_tasks_.append(ii) - + run_tasks = [os.path.basename(ii) for ii in run_tasks_] forward_files = ['INCAR', 'POTCAR','KPOINTS'] backward_files = ['OUTCAR','OSZICAR','vasprun.xml'] @@ -948,13 +948,13 @@ def cmpt_phonon(task_type,jdata,mdata): cwd=os.getcwd() #vasp if task_type == "vasp": - cmpt_06_phonon.cmpt_vasp(jdata, conf_dir) - #lammps + cmpt_06_phonon.cmpt_vasp(jdata, conf_dir) + #lammps elif task_type in lammps_task_type : cmpt_06_phonon.cmpt_lammps(jdata,conf_dir, task_type) else : raise RuntimeError("unknow task ", task_type) - os.chdir(cwd) + os.chdir(cwd) def run_task (json_file, machine_file) : with open (json_file, 'r') as fp : @@ -965,21 +965,21 @@ def run_task (json_file, machine_file) : record = "record.auto_test" model_devi_mdata = decide_model_devi_machine(mdata) - model_devi_machine = model_devi_mdata['model_devi_machine'] + model_devi_machine = model_devi_mdata['model_devi_machine'] if ('machine_type' in model_devi_machine) and \ (model_devi_machine['machine_type'] == 'ucloud'): model_devi_ssh_sess = None else : model_devi_ssh_sess = SSHSession(model_devi_machine) - + fp_mdata=decide_fp_machine(mdata) - fp_machine = fp_mdata['fp_machine'] + fp_machine = fp_mdata['fp_machine'] if ('machine_type' in fp_machine) and \ (fp_machine['machine_type'] == 'ucloud'): fp_ssh_sess = None else : fp_ssh_sess = SSHSession(fp_machine) - + confs = jdata['conf_dir'] ele_list=[key for key in jdata['potcar_map'].keys()] key_id = jdata['key_id'] @@ -1002,42 +1002,42 @@ def run_task (json_file, machine_file) : gen_confs.gen_alloy(ele_list,key_id) #default task log_iter ("gen_equi", ii, "equi") - gen_equi (ii, jdata, mdata) + gen_equi (ii, jdata, mdata) log_iter ("run_equi", ii, "equi") run_equi (ii, jdata, mdata,model_devi_ssh_sess) log_iter ("cmpt_equi", ii,"equi") cmpt_equi (ii, jdata, mdata) if jj == "eos" or jj=="all": log_iter ("gen_eos", ii, "eos") - gen_eos (ii, jdata, mdata) + gen_eos (ii, jdata, mdata) log_iter ("run_eos", ii, "eos") run_eos (ii, jdata, mdata,model_devi_ssh_sess) log_iter ("cmpt_eos", ii, "eos") cmpt_eos (ii, jdata, mdata) if jj=="elastic" or jj=="all": log_iter ("gen_elastic", ii, "elastic") - gen_elastic (ii, jdata, mdata) + gen_elastic (ii, jdata, mdata) log_iter ("run_elastic", ii, "elastic") run_elastic (ii, jdata, mdata,model_devi_ssh_sess) log_iter ("cmpt_elastic", ii, "elastic") cmpt_elastic (ii, jdata, mdata) if jj=="vacancy" or jj=="all": log_iter ("gen_vacancy", ii, "vacancy") - gen_vacancy (ii, jdata, mdata) + gen_vacancy (ii, jdata, mdata) log_iter ("run_vacancy", ii, "vacancy") run_vacancy (ii, jdata, mdata,model_devi_ssh_sess) log_iter ("cmpt_vacancy", ii, "vacancy") cmpt_vacancy (ii, jdata, mdata) if jj=="interstitial" or jj=="all": log_iter ("gen_interstitial", ii, "interstitial") - gen_interstitial (ii, jdata, mdata) + gen_interstitial (ii, jdata, mdata) log_iter ("run_interstitial", ii, "interstitial") run_interstitial (ii, jdata, mdata,model_devi_ssh_sess) log_iter ("cmpt_interstitial", ii, "interstitial") cmpt_interstitial (ii, jdata, mdata) if jj=="surf" or jj=="all": log_iter ("gen_surf", ii, "surf") - gen_surf (ii, jdata, mdata) + gen_surf (ii, jdata, mdata) log_iter ("run_surf", ii, "surf") run_surf (ii, jdata, mdata,model_devi_ssh_sess) log_iter ("cmpt_surf", ii, "surf") @@ -1045,7 +1045,7 @@ def run_task (json_file, machine_file) : ''' if jj=="phonon": log_iter ("gen_phonon", ii, "phonon") - gen_phonon (ii, jdata, mdata) + gen_phonon (ii, jdata, mdata) log_iter ("run_phonon", ii, "phonon") run_phonon (ii, jdata, mdata,model_devi_ssh_sess) log_iter ("cmpt_phonon", ii, "phonon") @@ -1061,9 +1061,9 @@ def gen_test(args): def _main () : parser = argparse.ArgumentParser() - parser.add_argument("PARAM", type=str, + parser.add_argument("PARAM", type=str, help="The parameters of the generator") - parser.add_argument("MACHINE", type=str, + parser.add_argument("MACHINE", type=str, help="The settings of the machine running the generator") args = parser.parse_args() From c8a4e3ff7461c34ed57cafd0cadf3320f0db0219 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 23:16:07 +0800 Subject: [PATCH 61/93] Delete .DS_Store --- dpgen/auto_test/.DS_Store | Bin 10244 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 dpgen/auto_test/.DS_Store diff --git a/dpgen/auto_test/.DS_Store b/dpgen/auto_test/.DS_Store deleted file mode 100644 index 9630a94f683f16f29ffc072f7b106ec27f5e43bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeHMTWl0n82&N;IHfZZ9b2_Oal5?xFx6_gc7tessqq!O>DmL!rsfB`NH(Qhq`-q1U& z2oVSo2oVSo2oVSo_&*>(Yc@;LTp`0eL?A>UL|_^L_I`-b#bn%*Q$q4r2W9*SK(dUg zd7?6%1GrAilW|W@3CUH-rZ_#Ir;6SY1BE)Z$5?lgaZgSODbxXlI-oZ)dM6a*qmy2Y zcL$6M8Rj7ZAp$odz|QV-`I+4SD{y`v?=$UG(zKJ*gFRH8bk+aO6O{nwLkdRdoX<}D zjr1D=9Zo`qY_QXRzV>T*+VcY1Ok1+$Q~5;f0S5YJY!<`9}`I95oTN8?3b zG^zr=w2}5G41-Pnu&Y=^{1$?!t|to#`lYxJS(;M;8$2?88`S|X+R27S2sng*O)V;q zPZ58RMaXYUA`P1uHo{|~ffM8-vS|4G&x7OSrA1@jl8qdDziy>Z_oiHAxT6%n{radg zVj|F!P}IWAcu3Dfz(Tdp``ct8Lp@;2kK!#j$RZHXReXNTfPpLu0sShU{*3s?qjAa? zjYU2Sx5Yjl6~Cp5X-kZS7CnVU-%aS(DY-5GTC zQ!XnVbnLX-!#fTdq|54tlm$$G_o!>wma|_^J0xZK^@>Hc%U9ml*!sYOy;myd%~z@x z$nrtL!*Y#dhMwLxW@zs40o6(AmS$MT2eO7^Bu%~FQb+VEY?b9J)isMNBhkp+xu$#- zNvV?tGfCrQ#&E~^7)zH$!UR_|FXIZ}wM(JfoI_5LShy;>m{ zde_25OY7>_G_T*#H66*k*!fAsnIovdDU+iF4_<(WEZULi61lb*m-i9l^ivX}jWS#G zjzyPC#1w^7B@$f`T_q8nl@i`6uZ~hrRZ>bt=XG+EMD$cWumo1?v#k9 zO1Ws=B*$g;h$$fMS44YdNx@?5E6TlB;R0NS58xBx+}Cgoet@6hPXsJSh4U?nORyGK z;wrosS7QUVVjD5913R%7H{({^M(j&qKkml?JV5MAarO=4Nlc@Q8DilSK1LiogHL!Y zd=8(-SMYou=lXJN6A~|8=Ug_CwoKbPPBo07<+R(&6yB}zwbs9aNPM5k_TOyhOMA}X zio@4dfBy=4CT+5Rg4VH7(nuBF(eV}aC*O)HoDTC4fe?W^4S`ZIp&0xAzq$DT|99H7 z!}){=gb4T$z_Q*%Z#Pxsw#mLWUS!|eV{{#*izU`?N=U9k8UGwll7Eh;8}>P#pBAXj nJ120xIMp-#DIuvu>0kddpy2n(zzID(|I@dC@ce)0p8x*=h=>iv From ed6b52b439cd250d9525311b1dd5dd41c8972477 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 23:16:22 +0800 Subject: [PATCH 62/93] Delete gen_08_dislocation.py --- dpgen/auto_test/gen_08_dislocation.py | 246 -------------------------- 1 file changed, 246 deletions(-) delete mode 100644 dpgen/auto_test/gen_08_dislocation.py diff --git a/dpgen/auto_test/gen_08_dislocation.py b/dpgen/auto_test/gen_08_dislocation.py deleted file mode 100644 index d28fcdd30..000000000 --- a/dpgen/auto_test/gen_08_dislocation.py +++ /dev/null @@ -1,246 +0,0 @@ -import os, re, argparse, filecmp, json, glob, math -import subprocess as sp -import numpy as np -import dpgen.auto_test.lib.vasp as vasp -import dpgen.auto_test.lib.lammps as lammps -from pymatgen.core.structure import Structure - - -global_equi_name = '00.equi' -global_task_name = '08.dislocation' - -task_dict={0:'edge',1:'screw'} - -def make_vasp(jdata, conf_dir, supercell = [1,1,1]) : - fp_params = jdata['vasp_params'] - ecut = fp_params['ecut'] - ediff = fp_params['ediff'] - npar = fp_params['npar'] - kpar = fp_params['kpar'] - kspacing = fp_params['kspacing'] - kgamma = fp_params['kgamma'] - - conf_path = os.path.abspath(conf_dir) - conf_poscar = os.path.join(conf_path, 'POSCAR') - # get equi poscar - equi_path = re.sub('confs', global_equi_name, conf_path) - equi_path = os.path.join(equi_path, 'vasp-k%.2f' % kspacing) - equi_contcar = os.path.join(equi_path, 'CONTCAR') - task_path = re.sub('confs', global_task_name, conf_path) - task_path = os.path.join(task_path, 'vasp-k%.2f' % kspacing) - os.makedirs(task_path, exist_ok=True) - cwd = os.getcwd() - os.chdir(task_path) - if os.path.isfile('POSCAR') : - os.remove('POSCAR') - os.symlink(os.path.relpath(equi_contcar), 'POSCAR') - os.chdir(cwd) - task_poscar = os.path.join(task_path, 'POSCAR') - # gen structure from equi poscar - edge = Structure.from_file(task_poscar) - edge.make_supercell([supercell[0],supercell[1],1]) - center=int(supercell[0]*int(supercell[1]/2)+supercell[0]/2) - s=[center+supercell[0]*ii for ii in range(int(supercell[1]/2+1))] - # gen edge dislocation - edge.remove_sites(s) - edge.make_supercell([1,1,supercell[2]]) - # gen screw dislocation - screw = Structure.from_file(task_poscar) - screw.make_supercell([supercell[0], supercell[1], supercell[2]],to_unit_cell=False) - c=[] - for jj in range(math.ceil(supercell[0]/2)): - for ii in range(supercell[2]): - c.append(ii+jj*supercell[2]) - v0 = np.asarray(screw._sites[0].coords, float) - np.asarray(screw._sites[1].coords, float) - for kk in range(math.ceil(supercell[1]/2)): - dc=[ii+kk*supercell[0]*supercell[2] for ii in c] - v=(math.ceil(supercell[1]/2)-kk)/math.ceil(supercell[1]/2)*v0 - screw.translate_sites(dc, vector=v, frac_coords=False, to_unit_cell=False) - dss = [] - dss.append(edge) - dss.append(screw) - - - # gen incar - fc = vasp.make_vasp_relax_incar(ecut, ediff, True, True, True, npar, kpar, kspacing = kspacing, kgamma = kgamma) - with open(os.path.join(task_path, 'INCAR'), 'w') as fp : - fp.write(fc) - # gen potcar - with open(task_poscar,'r') as fp : - lines = fp.read().split('\n') - ele_list = lines[5].split() - potcar_map = jdata['potcar_map'] - potcar_list = [] - for ii in ele_list : - assert(os.path.exists(potcar_map[ii])) - potcar_list.append(potcar_map[ii]) - with open(os.path.join(task_path,'POTCAR'), 'w') as outfile: - for fname in potcar_list: - with open(fname) as infile: - outfile.write(infile.read()) - # gen tasks - copy_str = "%sx%sx%s" % (supercell[0], supercell[1], supercell[2]) - cwd = os.getcwd() - for ii in range(len(dss)) : - struct_path = os.path.join(task_path, 'struct-%s-%s' % (copy_str,task_dict[ii])) - print('# generate %s' % (struct_path)) - os.makedirs(struct_path, exist_ok=True) - os.chdir(struct_path) - for jj in ['POSCAR', 'POTCAR', 'INCAR'] : - if os.path.isfile(jj): - os.remove(jj) - # make conf - dss[ii].to('POSCAR', 'POSCAR') - # link incar, potcar, kpoints - os.symlink(os.path.relpath(os.path.join(task_path, 'INCAR')), 'INCAR') - os.symlink(os.path.relpath(os.path.join(task_path, 'POTCAR')), 'POTCAR') - # save supercell - np.savetxt('supercell.out', supercell, fmt='%d') - os.chdir(cwd) - - -def make_lammps(jdata, conf_dir, supercell,task_type) : - - kspacing = jdata['vasp_params']['kspacing'] - fp_params = jdata['lammps_params'] - model_dir = fp_params['model_dir'] - type_map = fp_params['type_map'] - model_dir = os.path.abspath(model_dir) - model_name =fp_params['model_name'] - if not model_name : - models = glob.glob(os.path.join(model_dir, '*pb')) - model_name = [os.path.basename(ii) for ii in models] - else: - models = [os.path.join(model_dir,ii) for ii in model_name] - - model_param = {'model_name' : fp_params['model_name'], - 'param_type': fp_params['model_param_type']} - - ntypes = len(type_map) - - conf_path = os.path.abspath(conf_dir) - conf_poscar = os.path.join(conf_path, 'POSCAR') - # get equi poscar - equi_path = re.sub('confs', global_equi_name, conf_path) - equi_path = os.path.join(equi_path, 'vasp-k%.2f' % kspacing) - equi_contcar = os.path.join(equi_path, 'CONTCAR') - # equi_path = re.sub('confs', global_equi_name, conf_path) - # equi_path = os.path.join(equi_path, 'lmp') - # equi_dump = os.path.join(equi_path, 'dump.relax') - task_path = re.sub('confs', global_task_name, conf_path) - task_path = os.path.join(task_path, task_type) - os.makedirs(task_path, exist_ok=True) - # gen task poscar - task_poscar = os.path.join(task_path, 'POSCAR') - # lammps.poscar_from_last_dump(equi_dump, task_poscar, deepmd_type_map) - cwd = os.getcwd() - os.chdir(task_path) - if os.path.isfile('POSCAR') : - os.remove('POSCAR') - os.symlink(os.path.relpath(equi_contcar), 'POSCAR') - os.chdir(cwd) - # gen structure from equi poscar - edge = Structure.from_file(task_poscar) - edge.make_supercell([supercell[0],supercell[1],1]) - center=int(supercell[0]*int(supercell[1]/2)+supercell[0]/2) - s=[center+supercell[0]*ii for ii in range(int(supercell[1]/2+1))] - # gen edge dislocation - edge.remove_sites(s) - edge.make_supercell([1,1,supercell[2]]) - # gen screw dislocation - screw = Structure.from_file(task_poscar) - screw.make_supercell([supercell[0], supercell[1], supercell[2]],to_unit_cell=False) - c=[] - for jj in range(math.ceil(supercell[0]/2)): - for ii in range(supercell[2]): - c.append(ii+jj*supercell[2]) - v0 = np.asarray(screw._sites[0].coords, float) - np.asarray(screw._sites[1].coords, float) - for kk in range(math.ceil(supercell[1]/2)): - dc=[ii+kk*supercell[0]*supercell[2] for ii in c] - v=(math.ceil(supercell[1]/2)-kk)/math.ceil(supercell[1]/2)*v0 - screw.translate_sites(dc, vector=v, frac_coords=False, to_unit_cell=False) - dss = [] - dss.append(edge) - dss.append(screw) - - # gen tasks - cwd = os.getcwd() - # make lammps.in, relax at 0 bar (scale = 1) - if task_type=='deepmd': - fc = lammps.make_lammps_elastic('conf.lmp', - ntypes, - lammps.inter_deepmd, - model_name) - elif task_type =='meam': - fc = lammps.make_lammps_elastic('conf.lmp', - ntypes, - lammps.inter_meam, - model_param) - - f_lammps_in = os.path.join(task_path, 'lammps.in') - with open(f_lammps_in, 'w') as fp : - fp.write(fc) - # gen tasks - copy_str = "%sx%sx%s" % (supercell[0], supercell[1], supercell[2]) - cwd = os.getcwd() - if task_type=='deepmd': - os.chdir(task_path) - for ii in model_name : - if os.path.exists(ii) : - os.remove(ii) - for (ii,jj) in zip(models, model_name) : - os.symlink(os.path.relpath(ii), jj) - share_models = glob.glob(os.path.join(task_path, '*pb')) - else : - share_models=models - - for ii in range(len(dss)) : - struct_path = os.path.join(task_path, 'struct-%s-%s' % (copy_str,task_dict[ii])) - print('# generate %s' % (struct_path)) - os.makedirs(struct_path, exist_ok=True) - os.chdir(struct_path) - for jj in ['conf.lmp', 'lammps.in'] + model_name : - if os.path.isfile(jj): - os.remove(jj) - # make conf - dss[ii].to('POSCAR', 'POSCAR') - lammps.cvt_lammps_conf('POSCAR', 'conf.lmp') - ptypes = vasp.get_poscar_types('POSCAR') - lammps.apply_type_map('conf.lmp', type_map, ptypes) - # link lammps.in - os.symlink(os.path.relpath(f_lammps_in), 'lammps.in') - # link models - for (ii,jj) in zip(share_models, model_name) : - os.symlink(os.path.relpath(ii), jj) - # save supercell - np.savetxt('supercell.out', supercell, fmt='%d') - os.chdir(cwd) - -def _main() : - parser = argparse.ArgumentParser( - description="gen 08.dislocation") - parser.add_argument('TASK', type=str, - help='the task of generation, vasp or lammps') - parser.add_argument('PARAM', type=str, - help='json parameter file') - parser.add_argument('CONF', type=str, - help='the path to conf') - parser.add_argument('COPY', type=int, nargs = 3, - help='the path to conf') - args = parser.parse_args() - - with open (args.PARAM, 'r') as fp : - jdata = json.load (fp) - -# print('# generate %s task with conf %s' % (args.TASK, args.CONF)) - if args.TASK == 'vasp': - make_vasp(jdata, args.CONF, args.COPY) - elif args.TASK == 'deepmd' or args.TASK == 'meam' : - make_lammps(jdata, args.CONF, args.COPY, args.TASK) - #elif args.TASK == 'meam' : - # make_meam_lammps(jdata, args.CONF, args.COPY) - else : - raise RuntimeError("unknow task ", args.TASK) - -if __name__ == '__main__' : - _main() From 267ea7faf6ad1d205c8b5be18f88031ad12d5a1c Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 23:16:32 +0800 Subject: [PATCH 63/93] Delete cmpt_08_dislocation.py --- dpgen/auto_test/cmpt_08_dislocation.py | 117 ------------------------- 1 file changed, 117 deletions(-) delete mode 100644 dpgen/auto_test/cmpt_08_dislocation.py diff --git a/dpgen/auto_test/cmpt_08_dislocation.py b/dpgen/auto_test/cmpt_08_dislocation.py deleted file mode 100644 index 175c1fd07..000000000 --- a/dpgen/auto_test/cmpt_08_dislocation.py +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env python3 - -import os, re, argparse, filecmp, json, glob, sys -import subprocess as sp -import numpy as np -import dpgen.auto_test.lib.vasp as vasp -import dpgen.auto_test.lib.lammps as lammps - - -global_equi_name = '00.equi' -global_task_name = '08.dislocation' - -def comput_e_shift(poscar, task_name) : - a_types = vasp.get_poscar_types(poscar) - a_natoms = vasp.get_poscar_natoms(poscar) - ener_shift = 0 - if not os.path.isdir('stables') : - raise RuntimeError('no dir "stable". Stable energy and volume of components should be computed before calculating formation energy of an alloy') - for ii in range(len(a_types)) : - ref_e_file = a_types[ii] + '.' + task_name + '.e' - ref_e_file = os.path.join('stables', ref_e_file) - ener = float(open(ref_e_file).read()) - ener_shift += a_natoms[ii] * ener - return ener_shift - -def cmpt_vasp(jdata, conf_dir, supercell) : - fp_params = jdata['vasp_params'] - kspacing = fp_params['kspacing'] - - equi_path = re.sub('confs', global_equi_name, conf_dir) - equi_path = os.path.join(equi_path, 'vasp-k%.2f' % kspacing) - equi_path = os.path.abspath(equi_path) - equi_outcar = os.path.join(equi_path, 'OUTCAR') - task_path = re.sub('confs', global_task_name, conf_dir) - task_path = os.path.join(task_path, 'vasp-k%.2f' % kspacing) - task_path = os.path.abspath(task_path) - print("# ", task_path) - - equi_natoms, equi_epa, equi_vpa = vasp.get_nev(equi_outcar) - - copy_str = "%sx%sx%s" % (supercell[0], supercell[1], supercell[2]) - struct_path_widecard = os.path.join(task_path, 'struct-%s-*' % (copy_str)) - struct_path_list = glob.glob(struct_path_widecard) - struct_path_list.sort() - if len(struct_path_list) == 0: - print("# cannot find results for conf %s supercell %s" % (conf_dir, supercell)) - sys.stdout.write ("Structure: \tVac_E(eV) E(eV) equi_E(eV)\n") - for ii in struct_path_list : - struct_poscar = os.path.join(ii, 'POSCAR') - energy_shift = comput_e_shift(struct_poscar, 'vasp-k%.2f' % kspacing) - structure_dir = os.path.basename(ii) - outcar = os.path.join(ii, 'OUTCAR') - natoms, epa, vpa = vasp.get_nev(outcar) - evac = epa * natoms - equi_epa * natoms - sys.stdout.write ("%s: %7.3f %7.3f %7.3f \n" % (structure_dir, evac, epa * natoms, equi_epa*natoms)) - # evac = epa * natoms - energy_shift - # sys.stdout.write ("%s: %7.3f %7.3f %7.3f \n" % (structure_dir, evac, epa * natoms, energy_shift)) - # sys.stdout.write ("%s: %7.3f \n" % (structure_dir, evac)) - -def cmpt_lammps(jdata, conf_dir, supercell, task_name) : - equi_path = re.sub('confs', global_equi_name, conf_dir) - equi_path = os.path.join(equi_path, task_name) - equi_path = os.path.abspath(equi_path) - equi_log = os.path.join(equi_path, 'log.lammps') - task_path = re.sub('confs', global_task_name, conf_dir) - task_path = os.path.join(task_path, task_name) - task_path = os.path.abspath(task_path) - print("# ", task_path) - - equi_natoms, equi_epa, equi_vpa = lammps.get_nev(equi_log) - - copy_str = "%sx%sx%s" % (supercell[0], supercell[1], supercell[2]) - struct_path_widecard = os.path.join(task_path, 'struct-%s-*' % (copy_str)) - struct_path_list = glob.glob(struct_path_widecard) - struct_path_list.sort() - if len(struct_path_list) == 0: - print("# cannot find results for conf %s supercell %s" % (conf_dir, supercell)) - sys.stdout.write ("Structure: \tVac_E(eV) E(eV) equi_E(eV)\n") - for ii in struct_path_list : - struct_poscar = os.path.join(ii, 'POSCAR') - energy_shift = comput_e_shift(struct_poscar, task_name) - structure_dir = os.path.basename(ii) - lmp_log = os.path.join(ii, 'log.lammps') - natoms, epa, vpa = lammps.get_nev(lmp_log) - evac = epa * natoms - equi_epa * natoms - sys.stdout.write ("%s: %7.3f %7.3f %7.3f \n" % (structure_dir, evac, epa * natoms, equi_epa * natoms)) - # evac = epa * natoms - energy_shift - # sys.stdout.write ("%s: %7.3f %7.3f %7.3f \n" % (structure_dir, evac, epa * natoms, energy_shift)) - # sys.stdout.write ("%s: %7.3f\n" % (structure_dir, evac)) - -def _main() : - parser = argparse.ArgumentParser( - description="cmpt 08.dislocation") - parser.add_argument('TASK', type=str, - help='the task of generation, vasp or lammps') - parser.add_argument('PARAM', type=str, - help='json parameter file') - parser.add_argument('CONF', type=str, - help='the path to conf') - parser.add_argument('COPY', type=int, nargs = 3, - help='the path to conf') - args = parser.parse_args() - - with open (args.PARAM, 'r') as fp : - jdata = json.load (fp) - -# print('# generate %s task with conf %s' % (args.TASK, args.CONF)) - if args.TASK == 'vasp': - cmpt_vasp(jdata, args.CONF, args.COPY) - elif args.TASK == 'deepmd' or args.TASK =='meam' : - cmpt_lammps(jdata, args.CONF, args.COPY, args.TASK) - else : - raise RuntimeError("unknow task ", args.TASK) - -if __name__ == '__main__' : - _main() - From 1443eaeeb60bece539e12e9fec53966d262c8a1b Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 23:16:51 +0800 Subject: [PATCH 64/93] Delete commands --- dpgen/auto_test/commands | 164 --------------------------------------- 1 file changed, 164 deletions(-) delete mode 100644 dpgen/auto_test/commands diff --git a/dpgen/auto_test/commands b/dpgen/auto_test/commands deleted file mode 100644 index 5a057a1a6..000000000 --- a/dpgen/auto_test/commands +++ /dev/null @@ -1,164 +0,0 @@ -#!/bin/bash - -############################## -# 00 -############################## -# gen 00 equi -for ii in confs/*/mp* confs/*/std*; do ./gen_00_equi.py deepmd param.json $ii; done - -# run 00 equi -cwd=`pwd`; -for ii in 00.equi/*/std*/deepmd 00.equi/*/mp*/deepmd; do cd $ii; pwd; lmp_mpi_010 -i lammps.in; cd $cwd; done - -# result of 00, print with k0.16 -out=results/00.al.k0.16.out; rm -f $out; for ii in 00.equi/Al/*; do ./cmpt_00_equi.py param-k0.16.json $ii >> $out; done -out=results/00.mg.k0.16.out; rm -f $out; for ii in 00.equi/Mg/*; do ./cmpt_00_equi.py param-k0.16.json $ii >> $out; done -out=results/00.mgal.k0.16.out; rm -f $out; for ii in 00.equi/MgAl/*; do ./cmpt_00_equi.py param-k0.16.json $ii >> $out; done - -# result of 00, print with k0.08 -out=results/00.al.k0.08.out; rm -f $out; for ii in 00.equi/Al/*; do ./cmpt_00_equi.py param.json $ii >> $out; done -out=results/00.mg.k0.08.out; rm -f $out; for ii in 00.equi/Mg/*; do ./cmpt_00_equi.py param.json $ii >> $out; done - -# record stable info for Al and Mg -test ! -d stables && mkdir stables -out=results/00.al.k0.08.out -grep 'std-fcc' $out | grep -v 'std-fcc1' | awk '{print $2}' > stables/Al.vasp-k0.08.e -grep 'std-fcc' $out | grep -v 'std-fcc1' | awk '{print $5}' > stables/Al.vasp-k0.08.v -grep 'std-fcc' $out | grep -v 'std-fcc1' | awk '{print $3}' > stables/Al.deepmd.e -grep 'std-fcc' $out | grep -v 'std-fcc1' | awk '{print $6}' > stables/Al.deepmd.v -grep 'std-fcc' $out | grep -v 'std-fcc1' | awk '{print $4}' > stables/Al.meam.e -grep 'std-fcc' $out | grep -v 'std-fcc1' | awk '{print $7}' > stables/Al.meam.v -out=results/00.mg.k0.08.out -grep 'std-hcp' $out | awk '{print $2}' > stables/Mg.vasp-k0.08.e -grep 'std-hcp' $out | awk '{print $5}' > stables/Mg.vasp-k0.08.v -grep 'std-hcp' $out | awk '{print $3}' > stables/Mg.deepmd.e -grep 'std-hcp' $out | awk '{print $6}' > stables/Mg.deepmd.v -grep 'std-hcp' $out | awk '{print $4}' > stables/Mg.meam.e -grep 'std-hcp' $out | awk '{print $7}' > stables/Mg.meam.v - -# result of 00, print with k0.08 -out=results/00.mgal.k0.08.out; rm -f $out; for ii in 00.equi/MgAl/*; do ./cmpt_00_equi.py param.json $ii >> $out; done - - -############################## -# 01 -############################## -# 01 lammps -# gen 01 -for ii in confs/*/std*; do ./gen_01_eos.py --fix-shape deepmd param.json $ii; done - -# run 01 -cwd=`pwd`; -for ii in 01.eos/*/std*/deepmd/vol*; do cd $ii; pwd; lmp_mpi_010 -i lammps.in; cd $cwd; done - -# 01 vasp -for ii in fcc hcp bcc diamond dhcp sc; do out=results/01.al.$ii.vasp.k0.08.out; rm -f $out; ./cmpt_01_eos.py vasp param.json 01.eos/Al/std-$ii > $out; done -for ii in fcc hcp bcc diamond dhcp sc; do out=results/01.mg.$ii.vasp.k0.08.out; rm -f $out; ./cmpt_01_eos.py vasp param.json 01.eos/Mg/std-$ii > $out; done -for ii in fcc hcp bcc diamond dhcp sc; do out=results/01.al.$ii.vasp.k0.16.out; rm -f $out; ./cmpt_01_eos.py vasp param-k0.16.json 01.eos/Al/std-$ii > $out; done -for ii in fcc hcp bcc diamond dhcp sc; do out=results/01.mg.$ii.vasp.k0.16.out; rm -f $out; ./cmpt_01_eos.py vasp param-k0.16.json 01.eos/Mg/std-$ii > $out; done -# cmpt 01 deepmd -for ii in fcc hcp bcc diamond dhcp sc; do out=results/01.al.$ii.deepmd.out; rm -f $out; ./cmpt_01_eos.py deepmd param.json 01.eos/Al/std-$ii > $out; done -for ii in fcc hcp bcc diamond dhcp sc; do out=results/01.mg.$ii.deepmd.out; rm -f $out; ./cmpt_01_eos.py deepmd param.json 01.eos/Mg/std-$ii > $out; done -# cmpt 01 meam -for ii in fcc hcp bcc diamond dhcp sc; do out=results/01.al.$ii.meam.out; rm -f $out; ./cmpt_01_eos.py meam param.json 01.eos/Al/std-$ii > $out; done -for ii in fcc hcp bcc diamond dhcp sc; do out=results/01.mg.$ii.meam.out; rm -f $out; ./cmpt_01_eos.py meam param.json 01.eos/Mg/std-$ii > $out; done - -############################## -# 02 -############################## -# gen 02 -for ii in confs/*/std* confs/*/mp*; do ./gen_02_elastic.py deepmd param.json $ii; done - -# run 02 -cwd=`pwd`; -for ii in 02.elastic/*/std*/deepmd/dfm* 02.elastic/*/mp*/deepmd/dfm*; do cd $ii; pwd; lmp_mpi_010 -i lammps.in; cd $cwd; done - -# cmpt 02 -out=results/02.mgal.k0.08.out; rm -f $out; for ii in confs/MgAl/mp*; do deepmd=`./cmpt_02_elastic.py deepmd param-k0.08.json $ii | grep -v \# | tr '\n' ' '`; vasp=`./cmpt_02_elastic.py vasp param-k0.08.json $ii | grep -v \# | tr '\n' ' '`; echo $ii $vasp $deepmd >> $out; echo $ii; done -out=results/02.mgal.k0.16.out; rm -f $out; for ii in confs/MgAl/mp*; do deepmd=`./cmpt_02_elastic.py deepmd param-k0.16.json $ii | grep -v \# | tr '\n' ' '`; vasp=`./cmpt_02_elastic.py vasp param-k0.16.json $ii | grep -v \# | tr '\n' ' '`; echo $ii $vasp $deepmd >> $out; echo $ii; done -out=results/02.al.out; rm -f $out; for ii in confs/Al/std* confs/Al/mp*; do deepmd=`./cmpt_02_elastic.py deepmd param.json $ii | grep -v \# | tr '\n' ' '`; vasp=`./cmpt_02_elastic.py vasp param.json $ii | grep -v \# | tr '\n' ' '`; echo $ii $vasp $deepmd >> $out; echo $ii; done -out=results/02.mg.out; rm -f $out; for ii in confs/Mg/std* confs/Mg/mp*; do deepmd=`./cmpt_02_elastic.py deepmd param.json $ii | grep -v \# | tr '\n' ' '`; vasp=`./cmpt_02_elastic.py vasp param.json $ii | grep -v \# | tr '\n' ' '`; echo $ii $vasp $deepmd >> $out; echo $ii; done - -out=results/02.mgal.meam.k0.08.out; rm -f $out; for ii in confs/MgAl/mp*; do deepmd=`./cmpt_02_elastic.py meam param-k0.08.json $ii | grep -v \# | tr '\n' ' '`; vasp=`./cmpt_02_elastic.py vasp param-k0.08.json $ii | grep -v \# | tr '\n' ' '`; echo $ii $vasp $deepmd >> $out; echo $ii; done - -out=results/02.mgal.compk.out; rm -f $out; for ii in confs/MgAl/mp*; do lammps=`./cmpt_02_elastic.py vasp param-k0.16.json $ii | grep -v \# | tr '\n' ' '`; vasp=`./cmpt_02_elastic.py vasp param-k0.08.json $ii | grep -v \# | tr '\n' ' '`; echo $ii $vasp $lammps >> $out; echo $ii; done -out=results/02.al.compk.out; rm -f $out; for ii in confs/Al/std* confs/Al/mp*; do lammps=`./cmpt_02_elastic.py vasp param-k0.16.json $ii | grep -v \# | tr '\n' ' '`; vasp=`./cmpt_02_elastic.py vasp param-k0.08.json $ii | grep -v \# | tr '\n' ' '`; echo $ii $vasp $lammps >> $out; echo $ii; done -out=results/02.mg.compk.out; rm -f $out; for ii in confs/Mg/std* confs/Mg/mp*; do lammps=`./cmpt_02_elastic.py vasp param-k0.16.json $ii | grep -v \# | tr '\n' ' '`; vasp=`./cmpt_02_elastic.py vasp param-k0.08.json $ii | grep -v \# | tr '\n' ' '`; echo $ii $vasp $lammps >> $out; echo $ii; done - -out=results/02.mgal.mods.k0.08.out; rm -f $out; for ii in confs/MgAl/mp*; do deepmd=`./cmpt_02_elastic.py deepmd param-k0.08.json $ii | grep \# | grep = | cut -d = -f 2 | tr '\n' ' ' | sed 's/GPa//g'`; vasp=`./cmpt_02_elastic.py vasp param-k0.08.json $ii | grep \# | grep = | cut -d = -f 2 | tr '\n' ' ' | sed 's/GPa//g'`; meam=`./cmpt_02_elastic.py meam param-k0.08.json $ii | grep \# | grep = | cut -d = -f 2 | tr '\n' ' ' | sed 's/GPa//g'`; echo $ii $vasp $deepmd $meam >> $out; echo $ii; done - - - -############################## -# 03 -############################## -# gen 03 -for ii in confs/*/std* confs/*/mp*; do ./gen_03_vacancy.py deepmd param.json $ii `cat $ii/supercell.dfct`; done - -# run 03 -cwd=`pwd`; -for ii in 03.vacancy/*/std*/deepmd/struct* 03.vacancy/*/mp*/deepmd/struct*; do cd $ii; pwd; lmp_mpi_010 -i lammps.in; cd $cwd; done - -# cmpt 03 -#out=results/03.mgal.vasp.k0.16.out; rm -f $out; for ii in confs/MgAl/mp*; do ./cmpt_03_vacancy.py vasp param-k0.16.json $ii `cat $ii/supercell.dfct` >> $out ; echo $ii; done -# almg -out=results/03.mgal.vasp.k0.08.out; rm -f $out; for ii in confs/MgAl/mp*; do ./cmpt_03_vacancy.py vasp param-k0.08.json $ii `cat $ii/supercell.dfct` >> $out ; echo $ii; done -out=results/03.mgal.deepmd.out; rm -f $out; for ii in confs/MgAl/mp*; do ./cmpt_03_vacancy.py deepmd param-k0.08.json $ii `cat $ii/supercell.dfct` >> $out ; echo $ii; done -out=results/03.mgal.meam.out; rm -f $out; for ii in confs/MgAl/mp*; do ./cmpt_03_vacancy.py meam param-k0.08.json $ii `cat $ii/supercell.dfct` >> $out ; echo $ii; done - -# al -out=results/03.al.vasp.k0.08.out; rm -f $out; for ii in confs/Al/std*; do ./cmpt_03_vacancy.py vasp param-k0.08.json $ii `cat $ii/supercell.dfct` >> $out ; echo $ii; done -out=results/03.al.deepmd.out; rm -f $out; for ii in confs/Al/std*; do ./cmpt_03_vacancy.py deepmd param-k0.08.json $ii `cat $ii/supercell.dfct` >> $out ; echo $ii; done -out=results/03.al.meam.out; rm -f $out; for ii in confs/Al/std*; do ./cmpt_03_vacancy.py meam param-k0.08.json $ii `cat $ii/supercell.dfct` >> $out ; echo $ii; done - -# mg -out=results/03.mg.vasp.k0.08.out; rm -f $out; for ii in confs/Mg/std*; do ./cmpt_03_vacancy.py vasp param-k0.08.json $ii `cat $ii/supercell.dfct` >> $out ; echo $ii; done -out=results/03.mg.deepmd.out; rm -f $out; for ii in confs/Mg/std*; do ./cmpt_03_vacancy.py deepmd param-k0.08.json $ii `cat $ii/supercell.dfct` >> $out ; echo $ii; done -out=results/03.mg.meam.out; rm -f $out; for ii in confs/Mg/std*; do ./cmpt_03_vacancy.py meam param-k0.08.json $ii `cat $ii/supercell.dfct` >> $out ; echo $ii; done - -############################## -# 04 -############################## -# gen 04 -# for ii in confs/*/std* confs/*/mp*; do ./gen_04_interstitial.py lammps param.json $ii `cat $ii/supercell.dfct` Al Mg; done -# for ii in confs/MgAl/mp*; do ./gen_04_interstitial.py reprod param-k0.08.json $ii `cat $ii/supercell.dfct` Al Mg; done - -# gen 04 reprod -for ss in `cat confs/MgAl/sel.out`; do ii=confs/MgAl/$ss; ./gen_04_interstitial.py deepmd-reprod param-k0.16.json $ii `cat $ii/supercell.dfct` Al Mg; done -for ss in `cat confs/MgAl/sel.out`; do ii=confs/MgAl/$ss; ./gen_04_interstitial.py deepmd-reprod param-k0.08.json $ii `cat $ii/supercell.dfct` Al Mg; done - -# run 04 -cwd=`pwd` -for ii in 04.interstitial/*/mp*/deepmd-reprod-k0.16/struct*/frame*; do cd $ii; pwd; lmp_mpi_010 -i lammps.in; cd $cwd; done -for ii in 04.interstitial/*/mp*/deepmd-reprod-k0.08/struct*/frame*; do cd $ii; pwd; lmp_mpi_010 -i lammps.in; cd $cwd; done - -# cmpt 04 -for ss in `cat confs/MgAl/sel.out`; do ii=confs/MgAl/$ss; ./cmpt_04_interstitial.py deepmd-reprod param-k0.16.json $ii `cat $ii/supercell.dfct` Al Mg; done -for ss in `cat confs/MgAl/sel.out`; do ii=confs/MgAl/$ss; ./cmpt_04_interstitial.py deepmd-reprod param-k0.08.json $ii `cat $ii/supercell.dfct` Al Mg; done - -# collect 04 -cat 04.interstitial/MgAl/mp-*/vasp-k0.16/struct-*/ener.vasp.out > results/04.mgal.ener.vasp.k0.16.out -cat 04.interstitial/MgAl/mp-*/deepmd-reprod-k0.16/struct-*/ener.lmp.out > results/04.mgal.ener.deepmd.k0.16.out -paste results/04.mgal.ener.vasp.out results/04.mgal.ener.deepmd.out > results/04.mgal.ener.k0.16.out - -cat 04.interstitial/MgAl/mp-*/vasp-k0.08/struct-*/ener.vasp.out > results/04.mgal.ener.vasp.k0.08.out -cat 04.interstitial/MgAl/mp-*/deepmd-reprod-k0.08/struct-*/ener.lmp.out > results/04.mgal.ener.deepmd.k0.08.out -cat 04.interstitial/MgAl/mp-*/meam-reprod-k0.08/struct-*/ener.lmp.out > results/04.mgal.ener.meam.k0.08.out -paste results/04.mgal.ener.vasp.k0.08.out results/04.mgal.ener.deepmd.k0.08.out > results/04.mgal.ener.deepmd.k0.08.cmp.out -paste results/04.mgal.ener.vasp.k0.08.out results/04.mgal.ener.meam.k0.08.out > results/04.mgal.ener.meam.k0.08.cmp.out - -############################## -# 05 -############################## -# gen 05 -for ii in confs/MgAl/mp*; do ./gen_05_surf.py vasp-static param-k0.08.json $ii 1; done -for ii in confs/MgAl/mp*; do ./gen_05_surf.py vasp-static param-k0.16.json $ii 1; done -for ii in confs/MgAl/mp*; do ./gen_05_surf.py deepmd-static param-k0.08.json $ii 1; done - -# run 05 -cwd=`pwd`; -for ii in 05.surf//*/mp*/deepmd-static/struct*; do cd $ii; pwd; lmp_mpi_010 -i lammps.in; cd $cwd; done - -out=results/05.mgal.vasp.static.k0.08.out; rm -f $out; for ii in confs/MgAl/mp*; do ./cmpt_05_surf.py vasp-static param-k0.08.json $ii >> $out ; echo $ii; done -out=results/05.mgal.deepmd.static.out; rm -f $out; for ii in confs/MgAl/mp*; do ./cmpt_05_surf.py deepmd-static param-k0.08.json $ii >> $out ; echo $ii; done -out=results/05.mgal.meam.static.out; rm -f $out; for ii in confs/MgAl/mp*; do ./cmpt_05_surf.py meam-static param-k0.08.json $ii >> $out ; echo $ii; done From b5c15d1bb969e053c613e7e9bfb34f3a1f947ebd Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 23:18:28 +0800 Subject: [PATCH 65/93] Update util.py --- dpgen/auto_test/lib/util.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dpgen/auto_test/lib/util.py b/dpgen/auto_test/lib/util.py index 159d2248a..8607f58d4 100644 --- a/dpgen/auto_test/lib/util.py +++ b/dpgen/auto_test/lib/util.py @@ -17,6 +17,7 @@ def voigt_to_stress(inpt) : def insert_data(task,task_type,username,file_name): assert task in ['eos','elastic','surf'] assert task_type in ['vasp','deepmd'] + #check the corresponding of expr_type and data_type url='http://115.27.161.2:5000/insert_test_data?username=%s&expr_type=%s&data_type=%s' % (username,task_type,task) res = requests.post(url, data=open(file_name).read()) print('Successful upload!') From f048c0074125fa1ee4074a28ddbf25f992f38094 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 23:22:59 +0800 Subject: [PATCH 66/93] Update and rename param.json to deepmd_param.json --- examples/test/{param.json => deepmd_param.json} | 15 --------------- 1 file changed, 15 deletions(-) rename examples/test/{param.json => deepmd_param.json} (80%) diff --git a/examples/test/param.json b/examples/test/deepmd_param.json similarity index 80% rename from examples/test/param.json rename to examples/test/deepmd_param.json index 2ca1c5b98..294455623 100644 --- a/examples/test/param.json +++ b/examples/test/deepmd_param.json @@ -23,21 +23,6 @@ "model_name":false, "model_param_type":false }, - "deepmd_model_dir": "somewhere/example/Al_model", - "deepmd_type_map": [ - "Al" - ], - "meam_potfile_dir": "meam", - "meam_type_map": [ - "Al", "Si", "Mg", "Cu", "Fe" - ], - "meam_potfile": [ - "library.meam", - "AlSiMgCuFe.meam" - ], - "meam_param_type": [ - "AlS", "SiS", "MgS", "CuS", "FeS" - ], "_comment":"00.equi", "store_stable":true, From 88acf682711317094d4b9b33d2558574217bd926 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 23:24:13 +0800 Subject: [PATCH 67/93] Create vasp_param.json --- examples/test/vasp_param.json | 54 +++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 examples/test/vasp_param.json diff --git a/examples/test/vasp_param.json b/examples/test/vasp_param.json new file mode 100644 index 000000000..2ec2ed9df --- /dev/null +++ b/examples/test/vasp_param.json @@ -0,0 +1,54 @@ +{ + "_comment": "models", + "potcar_map" : { + "Al" : "/somewhere/example/POTCAR" + }, + "conf_dir":"confs/Al/std-fcc", + "key_id":"key id of Material project", + "task_type":"vasp", + "task":"all", + + "vasp_params": { + "ecut": 650, + "ediff": 1e-6, + "kspacing": 0.1, + "kgamma": false, + "npar": 1, + "kpar": 1, + "_comment": " that's all " + }, + + "_comment":"00.equi", + "store_stable":true, + + "_comment": "01.eos", + "vol_start": 12, + "vol_end": 22, + "vol_step": 0.5, + + "_comment": "02.elastic", + "norm_deform": 2e-2, + "shear_deform": 5e-2, + + "_comment":"03.vacancy", + "supercell":[3,3,3], + + "_comment":"04.interstitial", + "insert_ele":["Al"], + "reprod-opt":false, + + "_comment": "05.surface", + "min_slab_size": 10, + "min_vacuum_size": 11, + "_comment": "pert xz to work around vasp bug...", + "pert_xz": 0.01, + "max_miller": 2, + "static-opt":false, + "relax_box":false, + + "_comment":"06.phonon", + "supercell_matrix":[2,2,2], + "band":"0 1 0 0.5 1 0.5 0.375 0.75 0.375 0 0 0 0.5 0.5 0.5", + + "_comment": "that's all" +} From 4d4468ce8e1b3b1318aefac4b9920a572af4480e Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 23:24:30 +0800 Subject: [PATCH 68/93] Delete machine.json --- examples/test/machine.json | 75 -------------------------------------- 1 file changed, 75 deletions(-) delete mode 100644 examples/test/machine.json diff --git a/examples/test/machine.json b/examples/test/machine.json deleted file mode 100644 index d879f1e59..000000000 --- a/examples/test/machine.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "deepmd_path": "the folder of deepmd", - "train_machine": { - "machine_type": "slurm", - "hostname" : "localhost", - "port" : 22, - "username": "username", - "password": "password", - "work_path" : "the path of workplace", - "_comment" : "that's all" - }, - "train_resources": { - "numb_node": 1, - "numb_gpu": 1, - "task_per_node":7, - "source_list": [ "the path of deepmd source" ], - "module_list": [ ], - "time_limit": "23:0:0", - "mem_limit": 32, - "_comment": "that's all" - }, - - "lmp_command": "the command of lammps", - "model_devi_group_size": 10, - "_comment": "model_devi on localhost", - "model_devi_machine": { - "machine_type": "slurm", - "hostname" : "localhost", - "port" : 22, - "username": "username", - "password": "password", - "work_path" : "the path of workplace", - "_comment" : "that's all" - }, - "_comment": " if use GPU, numb_nodes(nn) should always be 1 ", - "_comment": " if numb_nodes(nn) = 1 multi-threading rather than mpi is assumed", - "model_devi_resources": { - "numb_node": 1, - "numb_gpu": 0, - "task_per_node":8, - "partition" : "partition", - "source_list": ["the path of lammps source" ], - "module_list": [ ], - "time_limit": "19:0:0", - "mem_limit": 32, - "_comment": "that's all" - }, - - "_comment": "fp on localhost ", - "fp_command": "the command of vasp", - "fp_group_size": 1, - "fp_machine": { - "machine_type": "slurm", - "hostname" : "localhost", - "port" : 22, - "username": "username", - "password": "password", - "work_path" : "the path of workplace", - "_comment" : "that's all" - }, - "fp_resources": { - "task_per_node":16, - "numb_gpu": 0, - "source_list": ["the path of source" ], - "module_list": [], - "with_mpi" : 1, - "partition" : "CPU-Node", - "time_limit": "20:0:0", - "mem_limit": 64, - "_comment": "that's all" - }, - - - "_comment": " that's all " -} From 8d67a32b351d3739ab30bee0259f226d26578a97 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 23:24:39 +0800 Subject: [PATCH 69/93] Delete param.yaml --- examples/test/param.yaml | 66 ---------------------------------------- 1 file changed, 66 deletions(-) delete mode 100644 examples/test/param.yaml diff --git a/examples/test/param.yaml b/examples/test/param.yaml deleted file mode 100644 index b28017565..000000000 --- a/examples/test/param.yaml +++ /dev/null @@ -1,66 +0,0 @@ ---- -_comment: that's all -potcar_map: - Al: "/somewhere/example/POTCAR" -conf_dir: confs/Al/std-fcc -key_id: key id of Material project -task_type: deepmd -task: all -vasp_params: - ecut: 650 - ediff: 1.0e-06 - kspacing: 0.1 - kgamma: false - npar: 1 - kpar: 1 - _comment: " that's all " -lammps_params: - model_dir: somewhere/example/Al_model - type_map: - - Al - model_name: false - model_param_type: false -deepmd_model_dir: somewhere/example/Al_model -deepmd_type_map: -- Al -meam_potfile_dir: meam -meam_type_map: -- Al -- Si -- Mg -- Cu -- Fe -meam_potfile: -- library.meam -- AlSiMgCuFe.meam -meam_param_type: -- AlS -- SiS -- MgS -- CuS -- FeS -store_stable: true -vol_start: 12 -vol_end: 22 -vol_step: 0.5 -norm_deform: 0.02 -shear_deform: 0.05 -supercell: -- 3 -- 3 -- 3 -insert_ele: -- Al -reprod-opt: false -min_slab_size: 10 -min_vacuum_size: 11 -pert_xz: 0.01 -max_miller: 2 -static-opt: false -relax_box: false -supercell_matrix: -- 2 -- 2 -- 2 -band: 0 1 0 0.5 1 0.5 0.375 0.75 0.375 0 0 0 0.5 0.5 0.5 - From 279c5497d5d945a7882fd27c2c86c88853577689 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 23:24:49 +0800 Subject: [PATCH 70/93] Delete machine.yaml --- examples/test/machine.yaml | 64 -------------------------------------- 1 file changed, 64 deletions(-) delete mode 100644 examples/test/machine.yaml diff --git a/examples/test/machine.yaml b/examples/test/machine.yaml deleted file mode 100644 index 15a43841a..000000000 --- a/examples/test/machine.yaml +++ /dev/null @@ -1,64 +0,0 @@ ---- -deepmd_path: the folder of deepmd -train_machine: - machine_type: slurm - hostname: localhost - port: 22 - username: username - password: password - work_path: the path of workplace - _comment: that's all -train_resources: - numb_node: 1 - numb_gpu: 1 - task_per_node: 7 - source_list: - - the path of deepmd source - module_list: [] - time_limit: '23:0:0' - mem_limit: 32 - _comment: that's all -lmp_command: the command of lammps -model_devi_group_size: 10 -_comment: " that's all " -model_devi_machine: - machine_type: slurm - hostname: localhost - port: 22 - username: username - password: password - work_path: the path of workplace - _comment: that's all -model_devi_resources: - numb_node: 1 - numb_gpu: 0 - task_per_node: 8 - partition: partition - source_list: - - the path of lammps source - module_list: [] - time_limit: '19:0:0' - mem_limit: 32 - _comment: that's all -fp_command: the command of vasp -fp_group_size: 1 -fp_machine: - machine_type: slurm - hostname: localhost - port: 22 - username: username - password: password - work_path: the path of workplace - _comment: that's all -fp_resources: - task_per_node: 16 - numb_gpu: 0 - source_list: - - the path of source - module_list: [] - with_mpi: 1 - partition: CPU-Node - time_limit: '20:0:0' - mem_limit: 64 - _comment: that's all - From 327dca7d426ca2dd9cd8a8b43d93fd40f1629bda Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 23:27:45 +0800 Subject: [PATCH 71/93] Create meam_param.json --- examples/test/meam_param.json | 60 +++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 examples/test/meam_param.json diff --git a/examples/test/meam_param.json b/examples/test/meam_param.json new file mode 100644 index 000000000..5beff5324 --- /dev/null +++ b/examples/test/meam_param.json @@ -0,0 +1,60 @@ +{ + "_comment": "models", + "potcar_map" : { + "Al" : "/somewhere/example/POTCAR" + }, + "conf_dir":"confs/Al/std-fcc", + "key_id":"key id of Material project", + "task_type":"meam", + "task":"all", + + "vasp_params": { + "ecut": 650, + "ediff": 1e-6, + "kspacing": 0.1, + "kgamma": false, + "npar": 1, + "kpar": 1, + "_comment": " that's all " + }, + "lammps_params": { + "model_dir":"somewhere/example/meam", + "type_map":["Al","Si","Mg","Cu","Fe"], + "model_name":["meam.AlSiMgCuFe","meam.library"], + "model_param_type":["AlS", "SiS", "MgS", "CuS", "FeS"] + }, + + "_comment":"00.equi", + "store_stable":true, + + "_comment": "01.eos", + "vol_start": 12, + "vol_end": 22, + "vol_step": 0.5, + + "_comment": "02.elastic", + "norm_deform": 2e-2, + "shear_deform": 5e-2, + + "_comment":"03.vacancy", + "supercell":[3,3,3], + + "_comment":"04.interstitial", + "insert_ele":["Al"], + "reprod-opt":false, + + "_comment": "05.surface", + "min_slab_size": 10, + "min_vacuum_size": 11, + "_comment": "pert xz to work around vasp bug...", + "pert_xz": 0.01, + "max_miller": 2, + "static-opt":false, + "relax_box":false, + + "_comment":"06.phonon", + "supercell_matrix":[2,2,2], + "band":"0 1 0 0.5 1 0.5 0.375 0.75 0.375 0 0 0 0.5 0.5 0.5", + + "_comment": "that's all" +} From 66fb60743da9beeac15da8d73bb466c1093a63b2 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Thu, 24 Oct 2019 23:29:38 +0800 Subject: [PATCH 72/93] Create vasp_poscar_param.json --- examples/test/vasp_poscar_param.json | 47 ++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 examples/test/vasp_poscar_param.json diff --git a/examples/test/vasp_poscar_param.json b/examples/test/vasp_poscar_param.json new file mode 100644 index 000000000..eeca53d7d --- /dev/null +++ b/examples/test/vasp_poscar_param.json @@ -0,0 +1,47 @@ +{ + "_comment": "models", + "potcar_map" : { + "Al" : "/somewhere/example/POTCAR" + }, + "conf_dir":"confs/Al/std-fcc", + "key_id":"key id of Material project", + "task_type":"vasp", + "task":"all", + + "relax_incar":"somewhere/relax_incar", + "scf_incar":"somewhere/scf_incar", + + "_comment":"00.equi", + "store_stable":true, + + "_comment": "01.eos", + "vol_start": 12, + "vol_end": 22, + "vol_step": 0.5, + + "_comment": "02.elastic", + "norm_deform": 2e-2, + "shear_deform": 5e-2, + + "_comment":"03.vacancy", + "supercell":[3,3,3], + + "_comment":"04.interstitial", + "insert_ele":["Al"], + "reprod-opt":false, + + "_comment": "05.surface", + "min_slab_size": 10, + "min_vacuum_size": 11, + "_comment": "pert xz to work around vasp bug...", + "pert_xz": 0.01, + "max_miller": 2, + "static-opt":false, + "relax_box":false, + + "_comment":"06.phonon", + "supercell_matrix":[2,2,2], + "band":"0 1 0 0.5 1 0.5 0.375 0.75 0.375 0 0 0 0.5 0.5 0.5", + + "_comment": "that's all" +} From 503d83fb3444a821b5c6fa2a7c0aaee4f8c6922c Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Fri, 25 Oct 2019 14:15:53 +0800 Subject: [PATCH 73/93] Add files via upload --- dpgen/auto_test/run.py | 316 ++++------------------------------------- 1 file changed, 28 insertions(+), 288 deletions(-) diff --git a/dpgen/auto_test/run.py b/dpgen/auto_test/run.py index b730fec68..fb514a7fb 100644 --- a/dpgen/auto_test/run.py +++ b/dpgen/auto_test/run.py @@ -15,6 +15,7 @@ import sys import os, re, argparse, filecmp, json, glob +import dpgen.auto_test.lib.util as util import dpgen.auto_test.lib.vasp as vasp import dpgen.auto_test.lib.lammps as lammps import random @@ -28,7 +29,7 @@ from dpgen.auto_test.lib.utils import create_path from dpgen.auto_test.lib.utils import copy_file_list from dpgen.auto_test.lib.utils import replace -from dpgen.auto_test.lib.utils import cmd_append_log + from dpgen.auto_test.lib.utils import log_iter from dpgen.auto_test.lib.utils import record_iter from dpgen.auto_test.lib.utils import log_iter @@ -111,41 +112,7 @@ def _run(machine, else : raise RuntimeError("unknow machine type") -def make_work_path(jdata,task,reprod_opt,static,user): - task_type=jdata['task_type'] - conf_dir=jdata['conf_dir'] - conf_path = os.path.abspath(conf_dir) - task_path = re.sub('confs', task, conf_path) - if task_type=="vasp": - if user: - work_path=os.path.join(task_path, 'vasp-user_incar') - assert(os.path.isdir(work_path)) - return work_path - if static: - if 'scf_incar' in jdata.keys(): - task_type=task_type+'-static-scf_incar' - else: - kspacing = jdata['vasp_params']['kspacing'] - task_type=task_type+'-static-k%.2f' % (kspacing) - else: - if 'relax_incar' in jdata.keys(): - task_type=task_type+'-relax_incar' - else: - kspacing = jdata['vasp_params']['kspacing'] - task_type=task_type+'-k%.2f' % (kspacing) - elif task_type in lammps_task_type: - if static: - task_type=task_type+'-static' - elif reprod_opt : - if 'relax_incar' in jdata.keys(): - task_type=task_type+'-reprod-relax_incar' - else: - task_type=task_type+'-reprod-k%.2f'% (kspacing) - - work_path=os.path.join(task_path, task_type) - assert(os.path.isdir(work_path)) - return work_path def gen_equi(task_type,jdata,mdata): conf_dir=jdata['conf_dir'] @@ -163,28 +130,12 @@ def gen_equi(task_type,jdata,mdata): def run_equi(task_type,jdata,mdata,ssh_sess): #rmprint("This module has been run !") - work_path=make_work_path(jdata,'00.equi',False,False,False) + work_path=util.make_work_path(jdata,'00.equi',False,False,False) all_task = glob.glob(os.path.join(work_path,'.')) #vasp if task_type=="vasp": mdata=decide_fp_machine(mdata) - vasp_exec=mdata['fp_command'] - group_size = mdata['fp_group_size'] - resources = mdata['fp_resources'] - machine=mdata['fp_machine'] - machine_type = mdata['fp_machine']['machine_type'] - command = vasp_exec - command = cmd_append_log(command, "log") - - run_tasks_ = [] - for ii in all_task: - fres = os.path.join(ii, 'OUTCAR') - if os.path.isfile(fres) : - if not vasp.check_finished(fres): - run_tasks_.append(ii) - else : - run_tasks_.append(ii) forward_files = ['INCAR', 'POTCAR'] backward_files = ['OUTCAR','CONTCAR','OSZICAR'] @@ -193,29 +144,6 @@ def run_equi(task_type,jdata,mdata,ssh_sess): #lammps elif task_type in lammps_task_type: mdata = decide_model_devi_machine(mdata) - lmp_exec = mdata['lmp_command'] - group_size = mdata['model_devi_group_size'] - resources = mdata['model_devi_resources'] - machine=mdata['model_devi_machine'] - machine_type = mdata['model_devi_machine']['machine_type'] - - command = lmp_exec + " -i lammps.in" - command = cmd_append_log(command, "model_devi.log") - - run_tasks_ = [] - for ii in all_task: - fres = os.path.join(ii, 'log.lammps') - if os.path.isfile(fres) : - with open(fres, 'r') as fp : - lines = fp.read().split('\n') - flag=False - for jj in lines: - if ("Final energy per atoms" in jj) and (not 'print' in jj): - flag=True - if not flag: - run_tasks_.append(ii) - else : - run_tasks_.append(ii) forward_files = ['conf.lmp', 'lammps.in'] backward_files = ['dump.relax','log.lammps', 'model_devi.log'] @@ -237,7 +165,10 @@ def run_equi(task_type,jdata,mdata,ssh_sess): else: raise RuntimeError ("unknow task %s, something wrong" % task_type) - run_tasks = [os.path.basename(ii) for ii in run_tasks_] + run_tasks = util.collect_task(all_task,task_type) + + machine,machine_type,resources,command,group_size=util.get_machine_info(mdata,task_type) + _run(machine, machine_type, ssh_sess, @@ -266,7 +197,6 @@ def cmpt_equi(task_type,jdata,mdata): def gen_eos(task_type,jdata,mdata): conf_dir=jdata['conf_dir'] - #fix_shape=jdata['fix_shape'] fix_shape = True cwd=os.getcwd() #vasp @@ -283,7 +213,7 @@ def gen_eos(task_type,jdata,mdata): os.chdir(cwd) def run_eos(task_type,jdata,mdata,ssh_sess): - work_path=make_work_path(jdata,'01.eos',False,False,False) + work_path=util.make_work_path(jdata,'01.eos',False,False,False) print(work_path) all_task = glob.glob(os.path.join(work_path, "vol-*")) @@ -292,22 +222,6 @@ def run_eos(task_type,jdata,mdata,ssh_sess): #vasp if task_type=="vasp": mdata=decide_fp_machine(mdata) - vasp_exec=mdata['fp_command'] - group_size = mdata['fp_group_size'] - resources = mdata['fp_resources'] - machine=mdata['fp_machine'] - machine_type = mdata['fp_machine']['machine_type'] - command = vasp_exec - command = cmd_append_log(command, "log") - - run_tasks_ = [] - for ii in all_task: - fres = os.path.join(ii, 'OUTCAR') - if os.path.isfile(fres) : - if not vasp.check_finished(fres): - run_tasks_.append(ii) - else : - run_tasks_.append(ii) forward_files = ['INCAR', 'POSCAR','POTCAR'] backward_files = ['OUTCAR','OSZICAR'] @@ -316,28 +230,6 @@ def run_eos(task_type,jdata,mdata,ssh_sess): #lammps elif task_type in lammps_task_type: mdata = decide_model_devi_machine(mdata) - lmp_exec = mdata['lmp_command'] - group_size = mdata['model_devi_group_size'] - resources = mdata['model_devi_resources'] - machine=mdata['model_devi_machine'] - machine_type = mdata['model_devi_machine']['machine_type'] - command = lmp_exec + " -i lammps.in" - command = cmd_append_log(command, "model_devi.log") - - run_tasks_ = [] - for ii in all_task: - fres = os.path.join(ii, 'log.lammps') - if os.path.isfile(fres) : - with open(fres, 'r') as fp : - lines = fp.read().split('\n') - flag=False - for jj in lines: - if ("Final energy per atoms" in jj) and (not 'print' in jj): - flag=True - if not flag: - run_tasks_.append(ii) - else : - run_tasks_.append(ii) fp_params = jdata['lammps_params'] model_dir = fp_params['model_dir'] @@ -358,7 +250,9 @@ def run_eos(task_type,jdata,mdata,ssh_sess): else: raise RuntimeError ("unknow task %s, something wrong" % task_type) - run_tasks = [os.path.basename(ii) for ii in run_tasks_] + run_tasks = util.collect_task(all_task,task_type) + + machine,machine_type,resources,command,group_size=util.get_machine_info(mdata,task_type) _run(machine, machine_type, ssh_sess, @@ -396,7 +290,7 @@ def gen_elastic(task_type,jdata,mdata): os.chdir(cwd) def run_elastic(task_type,jdata,mdata,ssh_sess): - work_path=make_work_path(jdata,'02.elastic',False,False,False) + work_path=util.make_work_path(jdata,'02.elastic',False,False,False) print(work_path) all_task = glob.glob(os.path.join(work_path, "dfm-*")) @@ -405,22 +299,6 @@ def run_elastic(task_type,jdata,mdata,ssh_sess): #vasp if task_type == "vasp": mdata=decide_fp_machine(mdata) - vasp_exec=mdata['fp_command'] - group_size = mdata['fp_group_size'] - resources = mdata['fp_resources'] - machine=mdata['fp_machine'] - machine_type = mdata['fp_machine']['machine_type'] - command = vasp_exec - command = cmd_append_log(command, "log") - - run_tasks_ = [] - for ii in all_task: - fres = os.path.join(ii, 'OUTCAR') - if os.path.isfile(fres) : - if not vasp.check_finished(fres): - run_tasks_.append(ii) - else : - run_tasks_.append(ii) forward_files = ['INCAR', 'POSCAR','POTCAR','KPOINTS'] backward_files = ['OUTCAR','CONTCAR','OSZICAR'] @@ -429,28 +307,6 @@ def run_elastic(task_type,jdata,mdata,ssh_sess): #lammps elif task_type in lammps_task_type: mdata = decide_model_devi_machine(mdata) - lmp_exec = mdata['lmp_command'] - group_size = mdata['model_devi_group_size'] - resources = mdata['model_devi_resources'] - machine=mdata['model_devi_machine'] - machine_type = mdata['model_devi_machine']['machine_type'] - command = lmp_exec + " -i lammps.in" - command = cmd_append_log(command, "model_devi.log") - - run_tasks_ = [] - for ii in all_task: - fres = os.path.join(ii, 'log.lammps') - if os.path.isfile(fres) : - with open(fres, 'r') as fp : - lines = fp.read().split('\n') - flag=False - for jj in lines: - if ('Final Stress' in jj) and (not 'print' in jj): - flag=True - if not flag: - run_tasks_.append(ii) - else : - run_tasks_.append(ii) fp_params = jdata['lammps_params'] model_dir = fp_params['model_dir'] @@ -471,7 +327,8 @@ def run_elastic(task_type,jdata,mdata,ssh_sess): else: raise RuntimeError ("unknow task %s, something wrong" % task_type) - run_tasks = [os.path.basename(ii) for ii in run_tasks_] + run_tasks = util.collect_task(all_task,task_type) + machine,machine_type,resources,command,group_size=util.get_machine_info(mdata,task_type) _run(machine, machine_type, ssh_sess, @@ -509,28 +366,12 @@ def gen_vacancy(task_type,jdata,mdata): def run_vacancy(task_type,jdata,mdata,ssh_sess): - work_path=make_work_path(jdata,'03.vacancy',False,False,False) + work_path=util.make_work_path(jdata,'03.vacancy',False,False,False) all_task = glob.glob(os.path.join(work_path,'struct-*')) #vasp if task_type == "vasp": mdata=decide_fp_machine(mdata) - vasp_exec=mdata['fp_command'] - group_size = mdata['fp_group_size'] - resources = mdata['fp_resources'] - machine=mdata['fp_machine'] - machine_type = mdata['fp_machine']['machine_type'] - command = vasp_exec - command = cmd_append_log(command, "log") - - run_tasks_ = [] - for ii in all_task: - fres = os.path.join(ii, 'OUTCAR') - if os.path.isfile(fres) : - if not vasp.check_finished(fres): - run_tasks_.append(ii) - else : - run_tasks_.append(ii) forward_files = ['INCAR', 'POSCAR','POTCAR'] backward_files = ['OUTCAR','OSZICAR'] @@ -539,28 +380,6 @@ def run_vacancy(task_type,jdata,mdata,ssh_sess): #lammps elif task_type in lammps_task_type: mdata = decide_model_devi_machine(mdata) - lmp_exec = mdata['lmp_command'] - group_size = mdata['model_devi_group_size'] - resources = mdata['model_devi_resources'] - machine=mdata['model_devi_machine'] - machine_type = mdata['model_devi_machine']['machine_type'] - command = lmp_exec + " -i lammps.in" - command = cmd_append_log(command, "model_devi.log") - - run_tasks_ = [] - for ii in all_task: - fres = os.path.join(ii, 'log.lammps') - if os.path.isfile(fres) : - with open(fres, 'r') as fp : - lines = fp.read().split('\n') - flag=False - for jj in lines: - if ("Final energy per atoms" in jj) and (not 'print' in jj): - flag=True - if not flag: - run_tasks_.append(ii) - else : - run_tasks_.append(ii) fp_params = jdata['lammps_params'] model_dir = fp_params['model_dir'] @@ -582,7 +401,8 @@ def run_vacancy(task_type,jdata,mdata,ssh_sess): else: raise RuntimeError ("unknow task %s, something wrong" % task_type) - run_tasks = [os.path.basename(ii) for ii in run_tasks_] + run_tasks = util.collect_task(all_task,task_type) + machine,machine_type,resources,command,group_size=util.get_machine_info(mdata,task_type) _run(machine, machine_type, ssh_sess, @@ -629,28 +449,12 @@ def gen_interstitial(task_type,jdata,mdata): def run_interstitial(task_type,jdata,mdata,ssh_sess): reprod_opt=jdata['reprod-opt'] - work_path=make_work_path(jdata,'04.interstitial',reprod_opt,False,False) + work_path=util.make_work_path(jdata,'04.interstitial',reprod_opt,False,False) all_task = glob.glob(os.path.join(work_path,'struct-*')) #vasp if task_type == "vasp": mdata=decide_fp_machine(mdata) - vasp_exec=mdata['fp_command'] - group_size = mdata['fp_group_size'] - resources = mdata['fp_resources'] - machine=mdata['fp_machine'] - machine_type = mdata['fp_machine']['machine_type'] - command = vasp_exec - command = cmd_append_log(command, "log") - - run_tasks_ = [] - for ii in all_task: - fres = os.path.join(ii, 'OUTCAR') - if os.path.isfile(fres) : - if not vasp.check_finished(fres): - run_tasks_.append(ii) - else : - run_tasks_.append(ii) forward_files = ['INCAR', 'POSCAR','POTCAR'] backward_files = ['OUTCAR','XDATCAR','OSZICAR'] @@ -659,13 +463,6 @@ def run_interstitial(task_type,jdata,mdata,ssh_sess): #lammps elif task_type in lammps_task_type: mdata = decide_model_devi_machine(mdata) - lmp_exec = mdata['lmp_command'] - group_size = mdata['model_devi_group_size'] - resources = mdata['model_devi_resources'] - machine=mdata['model_devi_machine'] - machine_type = mdata['model_devi_machine']['machine_type'] - command = lmp_exec + " -i lammps.in" - command = cmd_append_log(command, "model_devi.log") if reprod_opt: all_frame=[] @@ -678,13 +475,7 @@ def run_interstitial(task_type,jdata,mdata,ssh_sess): for ii in all_task: fres = os.path.join(ii, 'log.lammps') if os.path.isfile(fres) : - with open(fres, 'r') as fp : - lines = fp.read().split('\n') - flag=False - for jj in lines: - if ("Final energy per atoms" in jj) and (not 'print' in jj): - flag=True - if not flag: + if not lammps.check_finished(fres): run_tasks_.append(ii) else : run_tasks_.append(ii) @@ -708,6 +499,8 @@ def run_interstitial(task_type,jdata,mdata,ssh_sess): else: raise RuntimeError ("unknow task %s, something wrong" % task_type) + machine,machine_type,resources,command,group_size=util.get_machine_info(mdata,task_type) + if reprod_opt: for ii in work_path: run_tasks=[] @@ -726,7 +519,7 @@ def run_interstitial(task_type,jdata,mdata,ssh_sess): forward_files, backward_files) else: - run_tasks = [os.path.basename(ii) for ii in run_tasks_] + run_tasks = util.collect_task(all_task,task_type) _run(machine, machine_type, ssh_sess, @@ -777,30 +570,13 @@ def gen_surf(task_type,jdata,mdata): def run_surf(task_type,jdata,mdata,ssh_sess): static=jdata['static-opt'] - work_path=make_work_path(jdata,'05.surf',False,static,False) + work_path=util.make_work_path(jdata,'05.surf',False,static,False) all_task = glob.glob(os.path.join(work_path,'struct-*')) #vasp if task_type == "vasp": mdata=decide_fp_machine(mdata) - vasp_exec=mdata['fp_command'] - group_size = mdata['fp_group_size'] - resources = mdata['fp_resources'] - machine=mdata['fp_machine'] - machine_type = mdata['fp_machine']['machine_type'] - command = vasp_exec - command = cmd_append_log(command, "log") - - run_tasks_ = [] - for ii in all_task: - fres = os.path.join(ii, 'OUTCAR') - if os.path.isfile(fres) : - if not vasp.check_finished(fres): - run_tasks_.append(ii) - else : - run_tasks_.append(ii) - forward_files = ['INCAR', 'POSCAR','POTCAR'] backward_files = ['OUTCAR','OSZICAR'] @@ -809,28 +585,6 @@ def run_surf(task_type,jdata,mdata,ssh_sess): #lammps elif task_type in lammps_task_type: mdata = decide_model_devi_machine(mdata) - lmp_exec = mdata['lmp_command'] - group_size = mdata['model_devi_group_size'] - resources = mdata['model_devi_resources'] - machine=mdata['model_devi_machine'] - machine_type = mdata['model_devi_machine']['machine_type'] - command = lmp_exec + " -i lammps.in" - command = cmd_append_log(command, "model_devi.log") - - run_tasks_ = [] - for ii in all_task: - fres = os.path.join(ii, 'log.lammps') - if os.path.isfile(fres) : - with open(fres, 'r') as fp : - lines = fp.read().split('\n') - flag=False - for jj in lines: - if ("Final energy per atoms" in jj) and (not 'print' in jj): - flag=True - if not flag: - run_tasks_.append(ii) - else : - run_tasks_.append(ii) fp_params = jdata['lammps_params'] model_dir = fp_params['model_dir'] @@ -851,7 +605,8 @@ def run_surf(task_type,jdata,mdata,ssh_sess): else: raise RuntimeError ("unknow task %s, something wrong" % task_type) - run_tasks = [os.path.basename(ii) for ii in run_tasks_] + run_tasks = util.collect_task(all_task,task_type) + machine,machine_type,resources,command,group_size=util.get_machine_info(mdata,task_type) _run(machine, machine_type, ssh_sess, @@ -897,31 +652,16 @@ def gen_phonon(task_type,jdata,mdata): def run_phonon(task_type,jdata,mdata,ssh_sess): user= ('user_incar' in jdata.keys()) - work_path=make_work_path(jdata,'06.phonon',False,False,user) + work_path=util.make_work_path(jdata,'06.phonon',False,False,user) all_task = glob.glob(os.path.join(work_path,'.')) #vasp if task_type == "vasp": mdata=decide_fp_machine(mdata) - vasp_exec=mdata['fp_command'] - group_size = mdata['fp_group_size'] - resources = mdata['fp_resources'] - machine=mdata['fp_machine'] - machine_type = mdata['fp_machine']['machine_type'] - command = vasp_exec - command = cmd_append_log(command, "log") - - run_tasks_ = [] - for ii in all_task: - fres = os.path.join(ii, 'OUTCAR') - if os.path.isfile(fres) : - if not vasp.check_finished(fres): - run_tasks_.append(ii) - else : - run_tasks_.append(ii) + machine,machine_type,resources,command,group_size=util.get_machine_info(mdata,task_type) - run_tasks = [os.path.basename(ii) for ii in run_tasks_] + run_tasks = util.collect_task(all_task,task_type) forward_files = ['INCAR', 'POTCAR','KPOINTS'] backward_files = ['OUTCAR','OSZICAR','vasprun.xml'] common_files=['POSCAR'] From bff1e2a1e6b36932a1ef4869566e50128272d838 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Fri, 25 Oct 2019 14:16:34 +0800 Subject: [PATCH 74/93] Add files via upload --- dpgen/auto_test/lib/lammps.py | 55 ++++++++++++---------- dpgen/auto_test/lib/util.py | 86 ++++++++++++++++++++++++++++++++++- 2 files changed, 117 insertions(+), 24 deletions(-) diff --git a/dpgen/auto_test/lib/lammps.py b/dpgen/auto_test/lib/lammps.py index 1da497c99..f3788067f 100644 --- a/dpgen/auto_test/lib/lammps.py +++ b/dpgen/auto_test/lib/lammps.py @@ -52,7 +52,7 @@ def apply_type_map(conf_file, deepmd_type_map, ptypes) : raise RuntimeError("cannot find the entry 'atom types' in ", conf_file) words = lines[idx_ntypes].split() words[0] = str(ntypes) - new_lines[idx_ntypes] = " ".join(words) + new_lines[idx_ntypes] = " ".join(words) # find number of atoms idx_atom_entry = -1 for idx, ii in enumerate(lines) : @@ -71,7 +71,7 @@ def apply_type_map(conf_file, deepmd_type_map, ptypes) : ii = " ".join(words) new_lines[idx] = ii with open(conf_file, 'w') as fp: - fp.write("\n".join(new_lines)) + fp.write("\n".join(new_lines)) def _get_ntype(conf) : with open(conf, 'r') as fp: @@ -127,7 +127,7 @@ def make_lammps_eval(conf, ntypes, interaction, param) : ret += "box tilt large\n" ret += "read_data %s\n" % conf for ii in range(ntypes) : - ret += "mass %d 1\n" % (ii+1) + ret += "mass %d 1\n" % (ii+1) ret += "neigh_modify every 1 delay 0 check no\n" ret += interaction(param) ret += "compute mype all pe\n" @@ -157,9 +157,9 @@ def make_lammps_eval(conf, ntypes, interaction, param) : return ret -def make_lammps_equi(conf, ntypes, interaction, param, - etol=1e-12, ftol=1e-6, - maxiter=5000, maxeval=500000, +def make_lammps_equi(conf, ntypes, interaction, param, + etol=1e-12, ftol=1e-6, + maxiter=5000, maxeval=500000, change_box = True) : """ make lammps input for equilibritation @@ -173,7 +173,7 @@ def make_lammps_equi(conf, ntypes, interaction, param, ret += "box tilt large\n" ret += "read_data %s\n" % conf for ii in range(ntypes) : - ret += "mass %d 1\n" % (ii+1) + ret += "mass %d 1\n" % (ii+1) ret += "neigh_modify every 1 delay 0 check no\n" ret += interaction(param) ret += "compute mype all pe\n" @@ -208,8 +208,8 @@ def make_lammps_equi(conf, ntypes, interaction, param, ret += "print \"Final Stress (xx yy zz xy xz yz) = ${Pxx} ${Pyy} ${Pzz} ${Pxy} ${Pxz} ${Pyz}\"\n" return ret -def make_lammps_elastic(conf, ntypes, interaction, param, - etol=1e-12, ftol=1e-6, +def make_lammps_elastic(conf, ntypes, interaction, param, + etol=1e-12, ftol=1e-6, maxiter=5000, maxeval=500000) : """ make lammps input for elastic calculation @@ -223,7 +223,7 @@ def make_lammps_elastic(conf, ntypes, interaction, param, ret += "box tilt large\n" ret += "read_data %s\n" % conf for ii in range(ntypes) : - ret += "mass %d 1\n" % (ii+1) + ret += "mass %d 1\n" % (ii+1) ret += "neigh_modify every 1 delay 0 check no\n" ret += interaction(param) ret += "compute mype all pe\n" @@ -251,8 +251,8 @@ def make_lammps_elastic(conf, ntypes, interaction, param, return ret def make_lammps_press_relax(conf, ntypes, scale2equi, interaction, param, - B0 = 70, bp = 0, - etol=1e-12, ftol=1e-6, + B0 = 70, bp = 0, + etol=1e-12, ftol=1e-6, maxiter=5000, maxeval=500000) : """ make lammps input for relaxation at a certain volume @@ -274,7 +274,7 @@ def make_lammps_press_relax(conf, ntypes, scale2equi, interaction, param, ret += "box tilt large\n" ret += "read_data %s\n" % conf for ii in range(ntypes) : - ret += "mass %d 1\n" % (ii+1) + ret += "mass %d 1\n" % (ii+1) ret += "neigh_modify every 1 delay 0 check no\n" ret += interaction(param) ret += "compute mype all pe\n" @@ -305,8 +305,8 @@ def make_lammps_press_relax(conf, ntypes, scale2equi, interaction, param, ret += "print \"Final Stress (xx yy zz xy xz yz) = ${Pxx} ${Pyy} ${Pzz} ${Pxy} ${Pxz} ${Pyz}\"\n" return ret -def make_lammps_phonon(conf, masses, interaction, param, - etol=1e-12, ftol=1e-6, +def make_lammps_phonon(conf, masses, interaction, param, + etol=1e-12, ftol=1e-6, maxiter=5000, maxeval=500000): """ make lammps input for elastic calculation @@ -318,10 +318,10 @@ def make_lammps_phonon(conf, masses, interaction, param, ret += "boundary p p p\n" ret += "atom_style atomic\n" ret += "box tilt large\n" - ret += "read_data %s\n" % conf + ret += "read_data %s\n" % conf ntypes=len(masses) for ii in range(ntypes) : - ret += "mass %d %f\n" % (ii+1,masses[ii]) + ret += "mass %d %f\n" % (ii+1,masses[ii]) ret += "neigh_modify every 1 delay 0 check no\n" ret += interaction(param) return ret @@ -329,7 +329,7 @@ def make_lammps_phonon(conf, masses, interaction, param, def _get_epa (lines) : for ii in lines: if ("Final energy per atoms" in ii) and (not 'print' in ii): - return float(ii.split('=')[1].split()[0]) + return float(ii.split('=')[1].split()[0]) raise RuntimeError("cannot find key \"Final energy per atoms\" in lines, something wrong") def _get_vpa (lines) : @@ -349,7 +349,7 @@ def get_nev (log) : get natoms, energy_per_atom and volume_per_atom from lammps log """ with open(log, 'r') as fp: - lines = fp.read().split('\n') + lines = fp.read().split('\n') epa = _get_epa(lines) vpa = _get_vpa(lines) natoms = _get_natoms(lines) @@ -360,7 +360,7 @@ def get_base_area (log) : get base area """ with open(log, 'r') as fp: - lines = fp.read().split('\n') + lines = fp.read().split('\n') for ii in lines: if ("Final Base area" in ii) and (not 'print' in ii): return float(ii.split('=')[1].split()[0]) @@ -388,7 +388,7 @@ def poscar_from_last_dump(dump, poscar_out, deepmd_type_map) : if 'ITEM: TIMESTEP' in ii : step_idx = idx if step_idx == -1 : - raise RuntimeError("cannot find timestep in lammps dump, something wrong") + raise RuntimeError("cannot find timestep in lammps dump, something wrong") with open('tmp_dump', 'w') as fp: fp.write("\n".join(lines[step_idx:])) cvt_lammps_conf('tmp_dump', poscar_out, ofmt='vasp') @@ -401,6 +401,15 @@ def poscar_from_last_dump(dump, poscar_out, deepmd_type_map) : lines = fp.write("\n".join(lines)) +def check_finished_new(fname,keyword): + with open(fname, 'r') as fp : + lines = fp.read().split('\n') + flag=False + for jj in lines: + if (keyword in jj) and (not 'print' in jj): + flag=True + return flag - - +def check_finished(fname): + with open(fname, 'r') as fp: + return 'Total wall time:' in fp.read() diff --git a/dpgen/auto_test/lib/util.py b/dpgen/auto_test/lib/util.py index 8607f58d4..8554cf5b8 100644 --- a/dpgen/auto_test/lib/util.py +++ b/dpgen/auto_test/lib/util.py @@ -1,5 +1,11 @@ import numpy as np import requests +import os,re +import dpgen.auto_test.lib.vasp as vasp +import dpgen.auto_test.lib.lammps as lammps +from dpgen.auto_test.lib.utils import cmd_append_log + +lammps_task_type=['deepmd','meam','eam'] def voigt_to_stress(inpt) : ret = np.zeros((3,3)) @@ -17,7 +23,85 @@ def voigt_to_stress(inpt) : def insert_data(task,task_type,username,file_name): assert task in ['eos','elastic','surf'] assert task_type in ['vasp','deepmd'] - #check the corresponding of expr_type and data_type url='http://115.27.161.2:5000/insert_test_data?username=%s&expr_type=%s&data_type=%s' % (username,task_type,task) res = requests.post(url, data=open(file_name).read()) print('Successful upload!') + + +def make_work_path(jdata,task,reprod_opt,static,user): + + task_type=jdata['task_type'] + conf_dir=jdata['conf_dir'] + conf_path = os.path.abspath(conf_dir) + task_path = re.sub('confs', task, conf_path) + + if task_type=="vasp": + if user: + work_path=os.path.join(task_path, 'vasp-user_incar') + assert(os.path.isdir(work_path)) + return work_path + if static: + if 'scf_incar' in jdata.keys(): + task_type=task_type+'-static-scf_incar' + else: + kspacing = jdata['vasp_params']['kspacing'] + task_type=task_type+'-static-k%.2f' % (kspacing) + else: + if 'relax_incar' in jdata.keys(): + task_type=task_type+'-relax_incar' + else: + kspacing = jdata['vasp_params']['kspacing'] + task_type=task_type+'-k%.2f' % (kspacing) + elif task_type in lammps_task_type: + if static: + task_type=task_type+'-static' + elif reprod_opt : + if 'relax_incar' in jdata.keys(): + task_type=task_type+'-reprod-relax_incar' + else: + task_type=task_type+'-reprod-k%.2f'% (kspacing) + + work_path=os.path.join(task_path, task_type) + assert(os.path.isdir(work_path)) + return work_path + + +def get_machine_info(mdata,task_type): + if task_type=="vasp": + vasp_exec=mdata['fp_command'] + group_size = mdata['fp_group_size'] + resources = mdata['fp_resources'] + machine=mdata['fp_machine'] + machine_type = mdata['fp_machine']['machine_type'] + command = vasp_exec + command = cmd_append_log(command, "log") + elif task_type in lammps_task_type: + lmp_exec = mdata['lmp_command'] + group_size = mdata['model_devi_group_size'] + resources = mdata['model_devi_resources'] + machine=mdata['model_devi_machine'] + machine_type = mdata['model_devi_machine']['machine_type'] + command = lmp_exec + " -i lammps.in" + command = cmd_append_log(command, "model_devi.log") + return machine, machine_type, resources, command, group_size + +def collect_task(all_task,task_type): + + if task_type == 'vasp': + output_file ='OUTCAR' + check_finished = vasp.check_finished + elif task_type in lammps_task_type: + output_file = 'log.lammps' + check_finished = lammps.check_finished + + run_tasks_ = [] + for ii in all_task: + fres = os.path.join(ii, output_file) + if os.path.isfile(fres) : + if not check_finished(fres): + run_tasks_.append(ii) + else : + run_tasks_.append(ii) + + run_tasks = [os.path.basename(ii) for ii in run_tasks_] + return run_tasks From 3a8ab9540542af3de7e7677dd508d6f183aecd6f Mon Sep 17 00:00:00 2001 From: felix5572 Date: Fri, 25 Oct 2019 06:54:37 +0000 Subject: [PATCH 75/93] aws bug fix 3 --- dpgen/dispatcher/AWS.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dpgen/dispatcher/AWS.py b/dpgen/dispatcher/AWS.py index 7554b470d..ddb91dad6 100644 --- a/dpgen/dispatcher/AWS.py +++ b/dpgen/dispatcher/AWS.py @@ -5,13 +5,14 @@ from dpgen.dispatcher.JobStatus import JobStatus from dpgen import dlog -try: - import boto3 -except ModuleNotFoundError: - pass class AWS(Batch): - batch_client = boto3.client('batch') + try: + import boto3 + except ModuleNotFoundError: + pass + else: + batch_client = boto3.client('batch') _query_max_results = 1000 _query_time_interval = 30 _job_id_map_status = {} From f736586a00f914aeefceec46344460c93eed327b Mon Sep 17 00:00:00 2001 From: BaozCWJ Date: Fri, 25 Oct 2019 23:05:19 +0800 Subject: [PATCH 76/93] modify run.py --- .DS_Store | Bin 0 -> 10244 bytes dpgen/.DS_Store | Bin 0 -> 8196 bytes dpgen/auto_test/.DS_Store | Bin 0 -> 8196 bytes dpgen/auto_test/cmpt_01_eos.py | 12 ++++-- dpgen/auto_test/cmpt_02_elastic.py | 13 ++++--- dpgen/auto_test/cmpt_05_surf.py | 14 ++++--- dpgen/auto_test/lib/util.py | 10 +++-- dpgen/auto_test/run.py | 60 ++++++++++------------------- examples/.DS_Store | Bin 0 -> 8196 bytes 9 files changed, 52 insertions(+), 57 deletions(-) create mode 100644 .DS_Store create mode 100644 dpgen/.DS_Store create mode 100644 dpgen/auto_test/.DS_Store create mode 100644 examples/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..c92ac095aea083e65669756f6fe9c88c386f6fa1 GIT binary patch literal 10244 zcmeHMTWl3Y82oc7HONdP`RD9hfBEx(YXmd`8iCsgi1$O1E+JE~oKRA}I;fII0FqVIEeo~j z93X9yu}sBsLP=>#zo||S7@J~z#6V?E`lJ|6G8M}SC6zg#G6#%j#`uJSa(1#y%He=1 zC3US4&byk1W@B^3vF~9U5|?&-Lw~*clXjJCwhZ zQ3}Ig1{>rn$Hum_G&Uq#n%l=4lB(U>zGZxz87tN`ZSOuceE!1Nawb zyu38oMK2ufQYngxS4u8^UviPL1!niY{Raj)FNDq!$Fm}L)Ja>B6AtplA^F;!3;e@* zXO#Tv%LQIx*e6YO&hl~v8timPNTBE;^bv-H| z%B*cOGy6uBt9*alxpf;e`*XqYFu533V?*4X>M+fdV&(%@7#$jMd|K5fG`;k$#@u5V z147$j+qA0MRK4182}5nFQQdJ7QA}un9k3gYK@NN@?*;a$N%I7NW4who#G2@`_*Co=-;5ZWlXXM`-a0RZz zNAMZ(?pwG8Kfy2XCj!nzE;*OLRk#}0V;w$#8?XUev5nZ*j$1K}yKoQgB?e}&2ajSO z4iE!#l7T~b7V{WkftWafPZAHG#%E$CzJxF1>v*}0cikn%DT!An^KLYg_r1VBL%o8j z2E~VSV8JlO3Xj_19l74SDppK!R7VUQF=l_nn2xqOZp5ER<=;U%Zv4Y>V+#AqqK67G zy4DD21ZE2Ym1-eLk^kQ{^Z);|Wx0AC8Uc;KzkmQ%r8DVH`r%SSqI?dKYfsX3iY`&a zxCtet2~{#3Pg17i=|2#)8>k&e9GRH H=l{O}jHv^C literal 0 HcmV?d00001 diff --git a/dpgen/.DS_Store b/dpgen/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..47f09172fee0a67226d7f54049f421bdb3fd8aff GIT binary patch literal 8196 zcmeHMU2GLa6h7y+(49hMiiLJB0#}*>Vv)9Kfy&=)d!dw{6uE_#QYm}yE_CB|x7^)( zFKw-?P2jClhVLPBQb& z%sFRg&Y5p_a_$8H?97|Z0CfPMQ5DFSP%}pna#3fMSU6Koh-42i3;|f+Ly#%X(vBvg z2t*NxA`nF&ia->Bg%AO{vqjP7x%ZVcYNH555x6HKAifU?ssfWCPAin34r*iyKqyiG zS*TBWfV4@3m<(}Rp){pus_X$nQw&oKROTd42zA0_h|>y{IiNBJ3|Gc5LqWMZ*(Ibp zU{Yb!MiGc2FgpU`^A(o`ey5Q;DMm+(U?dav`#jIN-8VAFZL2uUYq~r)Fl^V#Nn_izNM)$sc1^F? z>E&J1m(NKnfu=Ey4fDFm$?dI8jfvKl_Nm5%>bJFTpPFJ?ZA0^}p3|e_6O&I)J@uOM z4#O`5ESur&rMX>o{6d#B^E5m^2(U*?m~ zJz38^lCuirUw_tf@}n+EswF-3gT9vwx}@TOO}1igm@gOh zy<>sxx&Co0=Mysa*3uQL*R6lJsqN7{sT)=IE#uY885^Y7xPg7fwsOacwi%3^F#N3L znznnkzhL`z#bV5F#VWg zWGsi9Oqp%n#`OMza+MzpCwJ^*`asqj9VHk2YHSRrlO4K#O00ay@Ppnl%cWg?O3O>{ z*6Q7wc0x!yOp|t1pWLVpUWTDQ*`!8X+%P&c!fx0HgOCLmitrpEji|~ODQPR)%81OoTuIy64vjd=7c1#*mSo~}51S>L*B5*d#-oR!B2c{_`IKqWeF(|0VP8?dBi$+vcGF literal 0 HcmV?d00001 diff --git a/dpgen/auto_test/.DS_Store b/dpgen/auto_test/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..6024b30f6cc24793b5397d9f7caa311b53fa92e6 GIT binary patch literal 8196 zcmeHMTTC5A82*2tutSRsl@|6?%CUrk^EZvm(V0EHeQ`D&`}P=sAP%Su6@DI$p!5AI~ja#Ga$EH$~zJ5+=S zgb0KPgb0KPgb4f}5THF<6lH~dUs}UDL?A@qoVoKD*p&TQXB#N zLTxS@B%^_h2XanIvQR-8N>YYmaKu0vPWouz7Z2o|lrkJJIDB9*G6p9U^hc-PkNWO_ zaVf((L?A?9IRfJKDFh2lNTqVOpWiLh^_rW%$AZG5RmCNWQmT}el|G&vcXCNj^RjN2 zmN_nZM>TIe6}0;u$C__zsX^1ojq%EE$M!VSHZp#&sT<^SV#u_0C)edMCn*hz z!W1^ft7m3*v^K}0t=l?gV^P^|>)0_n%ap46mfgLlCeBaKJURQ+YceAYz6wyjB*RM! z=~?bnx4fPxcr`UC)B7Qx9%HN3-h+n@k8z%LjbnzTdFGUn&^*H(ER-deM+X4B?}o7*1Uo48SSUpcQ>%h)L4VSDCj)5r|uOx+tF(cH9Q>!y8XXv%cW zlx6hW+JsSoZH(PmUsYYEM$`xLrllbYuTzGzDf4XB^v?TZY^+t;37uws#L>klI)7JT zzNM~KRgVixcgCPvR}^2}(5SM0m$Kkm;23LStp5pGNbb@U#Kc>+F?GPwQijEKCd1md zGj(W6rpgZm%ALEII-GVUCMZR>0%L(X-l?i5#mI*>*Xx@!Y?{@lG`yc(t=gj~Bf{FL z>olvnc%xiwABMVkv+QxPlc*4bJ+L1}Aq_U<;5oPm&%-6S4A z@Duz3zrpYD2mA?tV+mH`daS}~d=Q)P5!{M9a5wJ7ICkPe?8C?K7$)%qrcg%%Posl5 zJde{jgU{ead;wp?m+*DGf>-fvyoT@L`*m zL{Gj-T3cB=BLedxY3*P;72+u`mexHi&crLmLH6q-38rvdiG3?_?@hP@*WqLMoH+L# z+=8FsSNID7i;??$i{J*V!Ohr!58)P!VH>s+^Ez-RCU772-~nP^68muwhj4`0m-g8= zj%P809%hM!bNDoI@L9YNu<&Jk1>eBSOE}k?XPcCGb%AqJ$&76|_8HRT8M@dx?A=`m z6v}j}#rc2V%J=_wSJGiNAp#)+ix9w~L^9Dus+B(b;;bE|=M+7n2){Wg{Sc}aT?9~n m{trWHN6A&h!~;1eC26Sq>lXo$aR2v#m*|K4{{k5IRO=tHU(|2_ literal 0 HcmV?d00001 diff --git a/dpgen/auto_test/cmpt_01_eos.py b/dpgen/auto_test/cmpt_01_eos.py index 0000710c5..f5670c422 100755 --- a/dpgen/auto_test/cmpt_01_eos.py +++ b/dpgen/auto_test/cmpt_01_eos.py @@ -13,17 +13,19 @@ def comput_lmp_eos(jdata,conf_dir, task_name) : conf_path = os.path.join(conf_path, task_name) vol_paths = glob.glob(os.path.join(conf_path, 'vol-*')) vol_paths.sort() + result = os.path.join(conf_path,'result') print('Vpa(A^3)\tEpA(eV)') - with open(os.path.join(conf_path,'result'),'w') as fp: + with open(result,'w') as fp: fp.write('conf_dir:%s\n VpA(A^3) EpA(eV)\n'% (conf_dir)) for ii in vol_paths : log_lammps = os.path.join(ii, 'log.lammps') natoms, epa, vpa = lammps.get_nev(log_lammps) print(vpa, epa) fp.write('%7.3f %8.4f \n' % (vpa,epa)) + fp.close() if 'upload_username' in jdata.keys() and task_name =='deepmd': upload_username=jdata['upload_username'] - util.insert_data('eos','deepmd',upload_username,'result') + util.insert_data('eos','deepmd',upload_username,result) def comput_vasp_eos(jdata, conf_dir) : conf_path = re.sub('confs', global_task_name, conf_dir) @@ -37,17 +39,19 @@ def comput_vasp_eos(jdata, conf_dir) : task_path = os.path.join(conf_path, vasp_str) vol_paths = glob.glob(os.path.join(task_path, 'vol-*')) vol_paths.sort() + result = os.path.join(task_path,'result') print('Vpa(A^3)\tEpA(eV)') - with open(os.path.join(conf_path,'result'),'w') as fp: + with open(result,'w') as fp: fp.write('conf_dir:%s\n VpA(A^3) EpA(eV)\n'% (conf_dir)) for ii in vol_paths : outcar = os.path.join(ii, 'OUTCAR') natoms, epa, vpa = vasp.get_nev(outcar) print(vpa, epa) fp.write('%7.3f %8.4f \n' % (vpa,epa)) + fp.close() if 'upload_username' in jdata.keys(): upload_username=jdata['upload_username'] - util.insert_data('eos','vasp',upload_username,'result') + util.insert_data('eos','vasp',upload_username,result) def _main(): parser = argparse.ArgumentParser( diff --git a/dpgen/auto_test/cmpt_02_elastic.py b/dpgen/auto_test/cmpt_02_elastic.py index 7eb9e376f..fc3480110 100755 --- a/dpgen/auto_test/cmpt_02_elastic.py +++ b/dpgen/auto_test/cmpt_02_elastic.py @@ -13,8 +13,8 @@ global_equi_name = '00.equi' global_task_name = '02.elastic' -def result_et(et,conf_dir,task_path): - with open(os.path.join(task_path,'result'),'w') as fp: +def result_et(et,conf_dir,result): + with open(result,'w') as fp: fp.write('conf_dir:%s\n'% (conf_dir)) for ii in range(6) : for jj in range(6) : @@ -28,6 +28,7 @@ def result_et(et,conf_dir,task_path): fp.write("# Shear Modulus GV = %.2f GPa\n" % (GV)) fp.write("# Youngs Modulus EV = %.2f GPa\n" % (EV)) fp.write("# Poission Ratio uV = %.2f \n" % (uV)) + fp.close() def print_et (et): @@ -73,10 +74,11 @@ def cmpt_vasp(jdata, conf_dir) : # bar to GPa # et = -et / 1e4 print_et(et) - result_et(et,conf_dir,task_path) + result = os.path.join(task_path,'result') + result_et(et,conf_dir,result) if 'upload_username' in jdata.keys(): upload_username=jdata['upload_username'] - util.insert_data('elastic','vasp',upload_username,'result') + util.insert_data('elastic','vasp',upload_username,result) def cmpt_deepmd_lammps(jdata, conf_dir, task_name) : @@ -101,10 +103,11 @@ def cmpt_deepmd_lammps(jdata, conf_dir, task_name) : # bar to GPa # et = -et / 1e4 print_et(et) + result = os.path.join(task_path,'result') result_et(et,conf_dir,task_path) if 'upload_username' in jdata.keys() and task_name=='deepmd': upload_username=jdata['upload_username'] - util.insert_data('elastic','deepmd',upload_username,'result') + util.insert_data('elastic','deepmd',upload_username,result) diff --git a/dpgen/auto_test/cmpt_05_surf.py b/dpgen/auto_test/cmpt_05_surf.py index 5e58cfac7..2cb1e40f2 100755 --- a/dpgen/auto_test/cmpt_05_surf.py +++ b/dpgen/auto_test/cmpt_05_surf.py @@ -43,7 +43,8 @@ def cmpt_vasp(jdata, conf_dir, static = False) : print("# cannot find results for conf %s" % (conf_dir)) sys.stdout.write ("Miller_Indices: \tSurf_E(J/m^2) EpA(eV) equi_EpA(eV)\n") - with open(os.path.join(task_path,'result'),'w') as fp: + result = os.path.join(task_path,'result') + with open(result,'w') as fp: fp.write('conf_dir:%s\n'% (conf_dir)) fp.write("Miller_Indices: \tSurf_E(J/m^2) EpA(eV) equi_EpA(eV)\n") for ii in struct_path_list : @@ -59,9 +60,10 @@ def cmpt_vasp(jdata, conf_dir, static = False) : evac = (epa * natoms - equi_epa * natoms) / AA * Cf sys.stdout.write ("%s:\t %7.3f %8.3f %8.3f\n" % (structure_dir, evac, epa, equi_epa)) fp.write("%s:\t %7.3f %8.3f %8.3f\n" % (structure_dir, evac, epa, equi_epa)) + fp.close() if 'upload_username' in jdata.keys(): upload_username=jdata['upload_username'] - util.insert_data('surf','vasp',upload_username,'result') + util.insert_data('surf','vasp',upload_username,result) def cmpt_deepmd_lammps(jdata, conf_dir, task_name, static = False) : equi_path = re.sub('confs', global_equi_name, conf_dir) @@ -80,7 +82,8 @@ def cmpt_deepmd_lammps(jdata, conf_dir, task_name, static = False) : if len(struct_path_list) == 0: print("# cannot find results for conf %s" % (conf_dir)) sys.stdout.write ("Miller_Indices: \tSurf_E(J/m^2) EpA(eV) equi_EpA(eV)\n") - with open(os.path.join(task_path,'result'),'w') as fp: + result = os.path.join(task_path,'result') + with open(result,'w') as fp: fp.write('conf_dir:%s\n'% (conf_dir)) fp.write("Miller_Indices: \tSurf_E(J/m^2) EpA(eV) equi_EpA(eV)\n") for ii in struct_path_list : @@ -92,9 +95,10 @@ def cmpt_deepmd_lammps(jdata, conf_dir, task_name, static = False) : evac = (epa * natoms - equi_epa * natoms) / AA * Cf sys.stdout.write ("%s: \t%7.3f %8.3f %8.3f\n" % (structure_dir, evac, epa, equi_epa)) fp.write("%s:\t %7.3f %8.3f %8.3f\n" % (structure_dir, evac, epa, equi_epa)) - if 'upload_username' in jdata.keys() and task_name=='deepmd': + fp.close() + if 'upload_username' in jdata.keys() and task_name=='deepm': upload_username=jdata['upload_username'] - util.insert_data('surf','deepmd',upload_username,'result') + util.insert_data('surf','deepmd',upload_username,result) def _main() : parser = argparse.ArgumentParser( diff --git a/dpgen/auto_test/lib/util.py b/dpgen/auto_test/lib/util.py index 8554cf5b8..bbb8d438b 100644 --- a/dpgen/auto_test/lib/util.py +++ b/dpgen/auto_test/lib/util.py @@ -1,8 +1,9 @@ import numpy as np import requests import os,re -import dpgen.auto_test.lib.vasp as vasp -import dpgen.auto_test.lib.lammps as lammps +from dpgen.remote.RemoteJob import SSHSession +from dpgen.auto_test.lib import vasp +from dpgen.auto_test.lib import lammps from dpgen.auto_test.lib.utils import cmd_append_log lammps_task_type=['deepmd','meam','eam'] @@ -83,7 +84,8 @@ def get_machine_info(mdata,task_type): machine_type = mdata['model_devi_machine']['machine_type'] command = lmp_exec + " -i lammps.in" command = cmd_append_log(command, "model_devi.log") - return machine, machine_type, resources, command, group_size + ssh_sess = SSHSession(machine) + return machine, machine_type,ssh_sess,resources, command, group_size def collect_task(all_task,task_type): @@ -102,6 +104,6 @@ def collect_task(all_task,task_type): run_tasks_.append(ii) else : run_tasks_.append(ii) - + run_tasks = [os.path.basename(ii) for ii in run_tasks_] return run_tasks diff --git a/dpgen/auto_test/run.py b/dpgen/auto_test/run.py index fb514a7fb..ce76ca69d 100644 --- a/dpgen/auto_test/run.py +++ b/dpgen/auto_test/run.py @@ -127,7 +127,7 @@ def gen_equi(task_type,jdata,mdata): raise RuntimeError ("unknow task %s, something wrong" % task_type) os.chdir(cwd) -def run_equi(task_type,jdata,mdata,ssh_sess): +def run_equi(task_type,jdata,mdata): #rmprint("This module has been run !") work_path=util.make_work_path(jdata,'00.equi',False,False,False) @@ -167,7 +167,7 @@ def run_equi(task_type,jdata,mdata,ssh_sess): run_tasks = util.collect_task(all_task,task_type) - machine,machine_type,resources,command,group_size=util.get_machine_info(mdata,task_type) + machine,machine_type,ssh_sess,resources,command,group_size=util.get_machine_info(mdata,task_type) _run(machine, machine_type, @@ -212,9 +212,8 @@ def gen_eos(task_type,jdata,mdata): raise RuntimeError("unknow task ", task_type) os.chdir(cwd) -def run_eos(task_type,jdata,mdata,ssh_sess): +def run_eos(task_type,jdata,mdata): work_path=util.make_work_path(jdata,'01.eos',False,False,False) - print(work_path) all_task = glob.glob(os.path.join(work_path, "vol-*")) all_task.sort() @@ -252,7 +251,7 @@ def run_eos(task_type,jdata,mdata,ssh_sess): run_tasks = util.collect_task(all_task,task_type) - machine,machine_type,resources,command,group_size=util.get_machine_info(mdata,task_type) + machine,machine_type,ssh_sess,resources,command,group_size=util.get_machine_info(mdata,task_type) _run(machine, machine_type, ssh_sess, @@ -289,9 +288,8 @@ def gen_elastic(task_type,jdata,mdata): raise RuntimeError ("unknow task %s, something wrong" % task_type) os.chdir(cwd) -def run_elastic(task_type,jdata,mdata,ssh_sess): +def run_elastic(task_type,jdata,mdata): work_path=util.make_work_path(jdata,'02.elastic',False,False,False) - print(work_path) all_task = glob.glob(os.path.join(work_path, "dfm-*")) all_task.sort() @@ -328,7 +326,7 @@ def run_elastic(task_type,jdata,mdata,ssh_sess): raise RuntimeError ("unknow task %s, something wrong" % task_type) run_tasks = util.collect_task(all_task,task_type) - machine,machine_type,resources,command,group_size=util.get_machine_info(mdata,task_type) + machine,machine_type,ssh_sess,resources,command,group_size=util.get_machine_info(mdata,task_type) _run(machine, machine_type, ssh_sess, @@ -364,7 +362,7 @@ def gen_vacancy(task_type,jdata,mdata): raise RuntimeError("unknow task ", task_type) os.chdir(cwd) -def run_vacancy(task_type,jdata,mdata,ssh_sess): +def run_vacancy(task_type,jdata,mdata): work_path=util.make_work_path(jdata,'03.vacancy',False,False,False) all_task = glob.glob(os.path.join(work_path,'struct-*')) @@ -402,7 +400,7 @@ def run_vacancy(task_type,jdata,mdata,ssh_sess): raise RuntimeError ("unknow task %s, something wrong" % task_type) run_tasks = util.collect_task(all_task,task_type) - machine,machine_type,resources,command,group_size=util.get_machine_info(mdata,task_type) + machine,machine_type,ssh_sess,resources,command,group_size=util.get_machine_info(mdata,task_type) _run(machine, machine_type, ssh_sess, @@ -446,7 +444,7 @@ def gen_interstitial(task_type,jdata,mdata): raise RuntimeError("unknow task ", task_type) os.chdir(cwd) -def run_interstitial(task_type,jdata,mdata,ssh_sess): +def run_interstitial(task_type,jdata,mdata): reprod_opt=jdata['reprod-opt'] work_path=util.make_work_path(jdata,'04.interstitial',reprod_opt,False,False) @@ -499,7 +497,7 @@ def run_interstitial(task_type,jdata,mdata,ssh_sess): else: raise RuntimeError ("unknow task %s, something wrong" % task_type) - machine,machine_type,resources,command,group_size=util.get_machine_info(mdata,task_type) + machine,machine_type,ssh_sess,resources,command,group_size=util.get_machine_info(mdata,task_type) if reprod_opt: for ii in work_path: @@ -568,7 +566,7 @@ def gen_surf(task_type,jdata,mdata): raise RuntimeError("unknow task ", task_type) os.chdir(cwd) -def run_surf(task_type,jdata,mdata,ssh_sess): +def run_surf(task_type,jdata,mdata): static=jdata['static-opt'] work_path=util.make_work_path(jdata,'05.surf',False,static,False) @@ -606,7 +604,7 @@ def run_surf(task_type,jdata,mdata,ssh_sess): raise RuntimeError ("unknow task %s, something wrong" % task_type) run_tasks = util.collect_task(all_task,task_type) - machine,machine_type,resources,command,group_size=util.get_machine_info(mdata,task_type) + machine,machine_type,ssh_sess,resources,command,group_size=util.get_machine_info(mdata,task_type) _run(machine, machine_type, ssh_sess, @@ -650,7 +648,7 @@ def gen_phonon(task_type,jdata,mdata): raise RuntimeError("unknow task ", task_type) os.chdir(cwd) -def run_phonon(task_type,jdata,mdata,ssh_sess): +def run_phonon(task_type,jdata,mdata): user= ('user_incar' in jdata.keys()) work_path=util.make_work_path(jdata,'06.phonon',False,False,user) @@ -659,7 +657,7 @@ def run_phonon(task_type,jdata,mdata,ssh_sess): #vasp if task_type == "vasp": mdata=decide_fp_machine(mdata) - machine,machine_type,resources,command,group_size=util.get_machine_info(mdata,task_type) + machine,machine_type,ssh_sess,resources,command,group_size=util.get_machine_info(mdata,task_type) run_tasks = util.collect_task(all_task,task_type) forward_files = ['INCAR', 'POTCAR','KPOINTS'] @@ -704,22 +702,6 @@ def run_task (json_file, machine_file) : record = "record.auto_test" - model_devi_mdata = decide_model_devi_machine(mdata) - model_devi_machine = model_devi_mdata['model_devi_machine'] - if ('machine_type' in model_devi_machine) and \ - (model_devi_machine['machine_type'] == 'ucloud'): - model_devi_ssh_sess = None - else : - model_devi_ssh_sess = SSHSession(model_devi_machine) - - fp_mdata=decide_fp_machine(mdata) - fp_machine = fp_mdata['fp_machine'] - if ('machine_type' in fp_machine) and \ - (fp_machine['machine_type'] == 'ucloud'): - fp_ssh_sess = None - else : - fp_ssh_sess = SSHSession(fp_machine) - confs = jdata['conf_dir'] ele_list=[key for key in jdata['potcar_map'].keys()] key_id = jdata['key_id'] @@ -744,42 +726,42 @@ def run_task (json_file, machine_file) : log_iter ("gen_equi", ii, "equi") gen_equi (ii, jdata, mdata) log_iter ("run_equi", ii, "equi") - run_equi (ii, jdata, mdata,model_devi_ssh_sess) + run_equi (ii, jdata, mdata) log_iter ("cmpt_equi", ii,"equi") cmpt_equi (ii, jdata, mdata) if jj == "eos" or jj=="all": log_iter ("gen_eos", ii, "eos") gen_eos (ii, jdata, mdata) log_iter ("run_eos", ii, "eos") - run_eos (ii, jdata, mdata,model_devi_ssh_sess) + run_eos (ii, jdata, mdata) log_iter ("cmpt_eos", ii, "eos") cmpt_eos (ii, jdata, mdata) if jj=="elastic" or jj=="all": log_iter ("gen_elastic", ii, "elastic") gen_elastic (ii, jdata, mdata) log_iter ("run_elastic", ii, "elastic") - run_elastic (ii, jdata, mdata,model_devi_ssh_sess) + run_elastic (ii, jdata, mdata) log_iter ("cmpt_elastic", ii, "elastic") cmpt_elastic (ii, jdata, mdata) if jj=="vacancy" or jj=="all": log_iter ("gen_vacancy", ii, "vacancy") gen_vacancy (ii, jdata, mdata) log_iter ("run_vacancy", ii, "vacancy") - run_vacancy (ii, jdata, mdata,model_devi_ssh_sess) + run_vacancy (ii, jdata, mdata) log_iter ("cmpt_vacancy", ii, "vacancy") cmpt_vacancy (ii, jdata, mdata) if jj=="interstitial" or jj=="all": log_iter ("gen_interstitial", ii, "interstitial") gen_interstitial (ii, jdata, mdata) log_iter ("run_interstitial", ii, "interstitial") - run_interstitial (ii, jdata, mdata,model_devi_ssh_sess) + run_interstitial (ii, jdata, mdata) log_iter ("cmpt_interstitial", ii, "interstitial") cmpt_interstitial (ii, jdata, mdata) if jj=="surf" or jj=="all": log_iter ("gen_surf", ii, "surf") gen_surf (ii, jdata, mdata) log_iter ("run_surf", ii, "surf") - run_surf (ii, jdata, mdata,model_devi_ssh_sess) + run_surf (ii, jdata, mdata) log_iter ("cmpt_surf", ii, "surf") cmpt_surf (ii, jdata, mdata) ''' @@ -787,7 +769,7 @@ def run_task (json_file, machine_file) : log_iter ("gen_phonon", ii, "phonon") gen_phonon (ii, jdata, mdata) log_iter ("run_phonon", ii, "phonon") - run_phonon (ii, jdata, mdata,model_devi_ssh_sess) + run_phonon (ii, jdata, mdata) log_iter ("cmpt_phonon", ii, "phonon") cmpt_phonon (ii, jdata, mdata) ''' diff --git a/examples/.DS_Store b/examples/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..c3ea4212bbee53087bdee5da47c738776a67b582 GIT binary patch literal 8196 zcmeHMU2IfE6h3DuaHmk2Vxhf@r7I1zVk<47rM3KQ+l5ko0L^>Eqm|o z($<=qXm}B$Mq|Xp#PEj5lSX;*#h>^Se_}973=jI^qtR&Mlkv=*yG>iVuWH~6#yudh2(3fSSAU*$akbj&{IMZ$sbaAcQR!;DQbUqhjrKy zA`l`FA`l`FA`l|*e?WlFY>|{A=f2d2Wr#qCz&(k8*dJn)g^UMsPD+34pu)cbkQ7${ zKT(~F3dvX?x>J8Fu!{$BPD<$x7+gLu7#V{b3i_kd@5g*| zz_^rQ86prOa3=!d^C|-sd>hd|gWom_~k#S9CkJrwJZmg^-Q={qw1=Ug)h1V)W*_3%cYkE`u7@KQUHmcLik2$&+Md$A- z%-7V`sOl-9>CPBb>Wbob*VU`6&!s5178o`(GS>G5EhTqp3S#2TJDJ*VX(_|vI+Jd# zyO}zelcDk>L1)JvrVgc@i3tkPEysqSJKm|Pr^U!eHP<^nY1lNYPic5Rx*D}dQHF)K zQ`c!$wefnn+&&Do@g~{g;xtjA0rtT`7=bj{kca2s5 zZoyCR3;YJZ!yoV`{Ee%z0yknMR^fx#h>ze7Y{R{{ALH1Ghw(T*h9@zJqnJV+4Lpku z=5Y$AaR#5kOZWo5h%e#mconbV+jt${!}sw9euy98m-sFIC}$Wc(Dj&X7fQTMwfXOn z=o-AIMNThA*XY5XLy7-{uD8}oj^1CfVRLPL2po)#xTxU5w5B#5v=FB8bCROY2y4i$YxCK3UZ0)@YqVgys=n%eF_!Qd9T}X}p6q zD@0JfQfhaxRz?)&B~shYIuv3mUnRBsSe%KEjDu`%jV74Fu^9h~vhPi}3OC?m_?%ex z9o&YW;aB(z0aqdS85hM(SdH7T4j;np*nlnAO5AJ54ou(y?7>6Cza;kI01o0X@h|Q3 zZye8K20hFY59jb{V&SuRG2r3L_zJ#(SC+7@x4<_k@!CSx<&qiOa_n=|S77O4^RRVy zAh1G)Q6=vG2a3P{-yOk*QG^JD2rP>LmL!siE>acS?!{d@M)?e7k%Zlxl)eiUiyi`~ jJ^zOx)njBTeByzelahKU{p$|_;rR~`p8r1g?&abiuZ7rN literal 0 HcmV?d00001 From baedd55f3cf5fcee02f8c857eec63aa7e3e7e8b3 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Sat, 26 Oct 2019 12:39:04 -0400 Subject: [PATCH 77/93] support openbabel >=3.0 --- dpgen/generator/lib/gaussian.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dpgen/generator/lib/gaussian.py b/dpgen/generator/lib/gaussian.py index e8ec40a5b..2669e5f56 100644 --- a/dpgen/generator/lib/gaussian.py +++ b/dpgen/generator/lib/gaussian.py @@ -9,9 +9,12 @@ from scipy.sparse.csgraph import connected_components from scipy.spatial import cKDTree try: - import openbabel + from openbabel import openbabel except ImportError: - pass + try: + import openbabel + except ImportError: + pass try: from ase import Atoms, Atom from ase.data import atomic_numbers From 2b810d03acfd6c94e0677e8bc31c9375e6b48f03 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Sun, 27 Oct 2019 12:11:31 +0800 Subject: [PATCH 78/93] Update gen_01_eos.py --- dpgen/auto_test/gen_01_eos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpgen/auto_test/gen_01_eos.py b/dpgen/auto_test/gen_01_eos.py index 1071ec697..c129a4df3 100755 --- a/dpgen/auto_test/gen_01_eos.py +++ b/dpgen/auto_test/gen_01_eos.py @@ -66,7 +66,7 @@ def make_vasp(jdata, conf_dir) : kpar = fp_params['kpar'] kspacing = fp_params['kspacing'] kgamma = fp_params['kgamma'] - fc = vasp.make_vasp_relax_incar(ecut, ediff, is_alloy, True, True, npar, kpar, kspacing, kgamma) + fc = vasp.make_vasp_relax_incar(ecut, ediff, is_alloy, True, False, npar, kpar, kspacing, kgamma) vasp_path = os.path.join(task_path, 'vasp-k%.2f' % kspacing) os.makedirs(vasp_path, exist_ok = True) From 63ef8fee0a1be11e888093a50aa4bb95e3808103 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 28 Oct 2019 08:21:51 +0800 Subject: [PATCH 79/93] run/report for more properties --- dpgen/main.py | 2 + dpgen/tools/run_report.py | 99 ++++----------------------------------- dpgen/tools/stat_sys.py | 85 +++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 90 deletions(-) create mode 100644 dpgen/tools/stat_sys.py diff --git a/dpgen/main.py b/dpgen/main.py index f5b03a9b5..5a339fbd7 100644 --- a/dpgen/main.py +++ b/dpgen/main.py @@ -85,6 +85,8 @@ def main(): help="Report the systems and the thermodynamic conditions of the labeled frames.") parser_rr.add_argument("JOB_DIR", type=str, help="the directory of the DP-GEN job") + parser_rr.add_argument('-s',"--stat-sys", action = 'store_true', + help="count the labeled frames for each system") parser_rr.add_argument('-p',"--param", type=str, default = 'param.json', help="the json file provides DP-GEN paramters, should be located in JOB_DIR") parser_rr.add_argument('-v',"--verbose", action = 'store_true', diff --git a/dpgen/tools/run_report.py b/dpgen/tools/run_report.py index 4cded779b..8c7d31a36 100755 --- a/dpgen/tools/run_report.py +++ b/dpgen/tools/run_report.py @@ -3,98 +3,17 @@ import os,sys,json,glob,argparse,shutil import numpy as np import subprocess as sp -sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')) -from dpgen.tools.relabel import get_lmp_info +from dpgen.tools.stat_sys import stat_sys -def ascii_hist(count) : - np = (count-1) // 5 + 1 - ret = " |" - for ii in range(np): - ret += '=' - return ret - -def stat_tasks(target_folder, - param_file = 'param.json', - verbose = True, - mute = False) : - target_folder = os.path.abspath(target_folder) - with open(os.path.join(target_folder, param_file)) as fp: - jdata = json.load(fp) - # goto input - cwd = os.getcwd() - os.chdir(target_folder) - sys = jdata['sys_configs'] - numb_sys = len(sys) - sys_tasks_count = [0 for ii in sys] - sys_tasks_trait = [[] for ii in sys] - sys_tasks_trait_count = [[] for ii in sys] - # collect tasks from iter dirs - iters = glob.glob('iter.[0-9]*[0-9]') - iters.sort() - # iters = iters[:2] - for ii in iters : - iter_tasks = glob.glob(os.path.join(ii, '02.fp', 'task.[0-9]*[0-9].[0-9]*[0-9]')) - iter_tasks.sort() - if verbose : - print('# check iter ' + ii + ' with %6d tasks' % len(iter_tasks)) - for jj in iter_tasks : - sys_idx = int(os.path.basename(jj).split('.')[-2]) - sys_tasks_count[sys_idx] += 1 - linked_file = os.path.realpath(os.path.join(jj, 'conf.dump')) - linked_keys = linked_file.split('/') - task_record = linked_keys[-5] + '.' + linked_keys[-3] + '.' + linked_keys[-1].split('.')[0] - task_record_keys = task_record.split('.') - ens, temp, pres = get_lmp_info(os.path.join(ii, '01.model_devi', linked_keys[-3], 'input.lammps')) - trait = [ens, temp, pres] - if not trait in sys_tasks_trait[sys_idx] : - sys_tasks_trait[sys_idx].append(trait) - sys_tasks_trait_count[sys_idx].append(0) - t_idx = sys_tasks_trait[sys_idx].index(trait) - sys_tasks_trait_count[sys_idx][t_idx] += 1 - sys_tasks_all = [] - for ii in range(numb_sys) : - # print(sys[ii], sys_tasks_count[ii]) - tmp_all = [] - for jj in range(len(sys_tasks_trait[ii])) : - tmp_all.append(sys_tasks_trait[ii][jj] + [sys_tasks_trait_count[ii][jj]]) - sys_tasks_all.append(tmp_all) - for ii in sys_tasks_all: - ii.sort() - max_str_len = max([len(str(ii)) for ii in sys]) - sys_fmt = '%%%ds %%6d' % (max_str_len+1) - blank = max_str_len - 50 - str_blk = "" - for ii in range(blank): - str_blk += " " - trait_fmt = str_blk + 'ens: %s T: %10.2f P: %12.2f count: %6d' - for ii in range(numb_sys): - if not mute: - print(sys_fmt % (str(sys[ii]), sys_tasks_count[ii])) - for jj in range(len(sys_tasks_all[ii])): - hist_str = ascii_hist(sys_tasks_all[ii][jj][3]) - if not mute: - print((trait_fmt + hist_str) % (sys_tasks_all[ii][jj][0], - sys_tasks_all[ii][jj][1], - sys_tasks_all[ii][jj][2], - sys_tasks_all[ii][jj][3])) - return sys, sys_tasks_count, sys_tasks_all def run_report(args): - stat_tasks(args.JOB_DIR, args.param, args.verbose) - - -def _main() : - parser = argparse.ArgumentParser(description='Some data statistics of DP-GEN iterations') - parser.add_argument("JOB_DIR", type=str, - help="the directory of the DP-GEN job") - parser.add_argument('-p',"--param", type=str, default = 'param.json', - help="the json file provides DP-GEN paramters, should be located in JOB_DIR") - parser.add_argument('-v',"--verbose", action = 'store_true', - help="being loud") - args = parser.parse_args() - - stat_tasks(args.JOB_DIR, args.param, args.verbose) + report_count = 0 + if args.stat_sys: + stat_sys(args.JOB_DIR, args.param, args.verbose) + report_count += 1 + # other stats added in the following + if report_count == 0: + print('nothing to report, rerun with -h for help') -if __name__ == '__main__': - _main() + return report_count diff --git a/dpgen/tools/stat_sys.py b/dpgen/tools/stat_sys.py new file mode 100644 index 000000000..45d1d80db --- /dev/null +++ b/dpgen/tools/stat_sys.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 + +import os,sys,json,glob,argparse,shutil +import numpy as np +import subprocess as sp +sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')) +from dpgen.tools.relabel import get_lmp_info + +def ascii_hist(count) : + np = (count-1) // 5 + 1 + ret = " |" + for ii in range(np): + ret += '=' + return ret + +def stat_sys(target_folder, + param_file = 'param.json', + verbose = True, + mute = False) : + target_folder = os.path.abspath(target_folder) + with open(os.path.join(target_folder, param_file)) as fp: + jdata = json.load(fp) + # goto input + cwd = os.getcwd() + os.chdir(target_folder) + sys = jdata['sys_configs'] + numb_sys = len(sys) + sys_tasks_count = [0 for ii in sys] + sys_tasks_trait = [[] for ii in sys] + sys_tasks_trait_count = [[] for ii in sys] + # collect tasks from iter dirs + iters = glob.glob('iter.[0-9]*[0-9]') + iters.sort() + # iters = iters[:2] + for ii in iters : + iter_tasks = glob.glob(os.path.join(ii, '02.fp', 'task.[0-9]*[0-9].[0-9]*[0-9]')) + iter_tasks.sort() + if verbose : + print('# check iter ' + ii + ' with %6d tasks' % len(iter_tasks)) + for jj in iter_tasks : + sys_idx = int(os.path.basename(jj).split('.')[-2]) + sys_tasks_count[sys_idx] += 1 + linked_file = os.path.realpath(os.path.join(jj, 'conf.dump')) + linked_keys = linked_file.split('/') + task_record = linked_keys[-5] + '.' + linked_keys[-3] + '.' + linked_keys[-1].split('.')[0] + task_record_keys = task_record.split('.') + ens, temp, pres = get_lmp_info(os.path.join(ii, '01.model_devi', linked_keys[-3], 'input.lammps')) + trait = [ens, temp, pres] + if not trait in sys_tasks_trait[sys_idx] : + sys_tasks_trait[sys_idx].append(trait) + sys_tasks_trait_count[sys_idx].append(0) + t_idx = sys_tasks_trait[sys_idx].index(trait) + sys_tasks_trait_count[sys_idx][t_idx] += 1 + sys_tasks_all = [] + for ii in range(numb_sys) : + # print(sys[ii], sys_tasks_count[ii]) + tmp_all = [] + for jj in range(len(sys_tasks_trait[ii])) : + tmp_all.append(sys_tasks_trait[ii][jj] + [sys_tasks_trait_count[ii][jj]]) + sys_tasks_all.append(tmp_all) + for ii in sys_tasks_all: + ii.sort() + max_str_len = max([len(str(ii)) for ii in sys]) + sys_fmt = '%%%ds %%6d' % (max_str_len+1) + blank = max_str_len - 50 + str_blk = "" + for ii in range(blank): + str_blk += " " + trait_fmt = str_blk + 'ens: %s T: %10.2f P: %12.2f count: %6d' + for ii in range(numb_sys): + if not mute: + print(sys_fmt % (str(sys[ii]), sys_tasks_count[ii])) + for jj in range(len(sys_tasks_all[ii])): + hist_str = ascii_hist(sys_tasks_all[ii][jj][3]) + if not mute: + print((trait_fmt + hist_str) % (sys_tasks_all[ii][jj][0], + sys_tasks_all[ii][jj][1], + sys_tasks_all[ii][jj][2], + sys_tasks_all[ii][jj][3])) + return sys, sys_tasks_count, sys_tasks_all + +def run_report(args): + stat_tasks(args.JOB_DIR, args.param, args.verbose) + + From 942b12e2727d9eb050810274bdc151735d956753 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 28 Oct 2019 08:26:01 +0800 Subject: [PATCH 80/93] fix bug in unittest --- tests/tools/test_run_report.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tools/test_run_report.py b/tests/tools/test_run_report.py index b19b89b36..34146a697 100644 --- a/tests/tools/test_run_report.py +++ b/tests/tools/test_run_report.py @@ -4,12 +4,12 @@ test_dir = os.path.abspath(os.path.join(os.path.dirname(__file__))) sys.path.insert(0, os.path.join(test_dir, '..')) __package__ = 'tools' -from .context import stat_tasks +from .context import stat_sys class TestRunReport(unittest.TestCase): def test (self): folder = 'run_report_test_output' - sys, sys_count, sys_all = stat_tasks(os.path.join(test_dir,folder), verbose = False, mute = True) + sys, sys_count, sys_all = stat_sys(os.path.join(test_dir,folder), verbose = False, mute = True) with open(os.path.join(test_dir, folder, 'param.json')) as fp: jdata = json.load(fp) self.assertEqual(sys, jdata['sys_configs']) From 0fe2ae4663cf1e82b69c3db15a36b7d239bc59ad Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 28 Oct 2019 08:26:42 +0800 Subject: [PATCH 81/93] better name of test function --- tests/tools/test_run_report.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tools/test_run_report.py b/tests/tools/test_run_report.py index 34146a697..e31ac3a56 100644 --- a/tests/tools/test_run_report.py +++ b/tests/tools/test_run_report.py @@ -7,7 +7,7 @@ from .context import stat_sys class TestRunReport(unittest.TestCase): - def test (self): + def test_stat_sys (self): folder = 'run_report_test_output' sys, sys_count, sys_all = stat_sys(os.path.join(test_dir,folder), verbose = False, mute = True) with open(os.path.join(test_dir, folder, 'param.json')) as fp: From dae24a9967f3784a7ef9e74f38c21dcd8a6b061c Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Mon, 28 Oct 2019 11:38:18 +0800 Subject: [PATCH 82/93] Delete .DS_Store --- .DS_Store | Bin 10244 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index c92ac095aea083e65669756f6fe9c88c386f6fa1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeHMTWl3Y82oc7HONdP`RD9hfBEx(YXmd`8iCsgi1$O1E+JE~oKRA}I;fII0FqVIEeo~j z93X9yu}sBsLP=>#zo||S7@J~z#6V?E`lJ|6G8M}SC6zg#G6#%j#`uJSa(1#y%He=1 zC3US4&byk1W@B^3vF~9U5|?&-Lw~*clXjJCwhZ zQ3}Ig1{>rn$Hum_G&Uq#n%l=4lB(U>zGZxz87tN`ZSOuceE!1Nawb zyu38oMK2ufQYngxS4u8^UviPL1!niY{Raj)FNDq!$Fm}L)Ja>B6AtplA^F;!3;e@* zXO#Tv%LQIx*e6YO&hl~v8timPNTBE;^bv-H| z%B*cOGy6uBt9*alxpf;e`*XqYFu533V?*4X>M+fdV&(%@7#$jMd|K5fG`;k$#@u5V z147$j+qA0MRK4182}5nFQQdJ7QA}un9k3gYK@NN@?*;a$N%I7NW4who#G2@`_*Co=-;5ZWlXXM`-a0RZz zNAMZ(?pwG8Kfy2XCj!nzE;*OLRk#}0V;w$#8?XUev5nZ*j$1K}yKoQgB?e}&2ajSO z4iE!#l7T~b7V{WkftWafPZAHG#%E$CzJxF1>v*}0cikn%DT!An^KLYg_r1VBL%o8j z2E~VSV8JlO3Xj_19l74SDppK!R7VUQF=l_nn2xqOZp5ER<=;U%Zv4Y>V+#AqqK67G zy4DD21ZE2Ym1-eLk^kQ{^Z);|Wx0AC8Uc;KzkmQ%r8DVH`r%SSqI?dKYfsX3iY`&a zxCtet2~{#3Pg17i=|2#)8>k&e9GRH H=l{O}jHv^C From c1139b1d2b484d9da87c55ce9bdbdaf285a400cd Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Mon, 28 Oct 2019 11:38:28 +0800 Subject: [PATCH 83/93] Delete .DS_Store --- dpgen/.DS_Store | Bin 8196 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 dpgen/.DS_Store diff --git a/dpgen/.DS_Store b/dpgen/.DS_Store deleted file mode 100644 index 47f09172fee0a67226d7f54049f421bdb3fd8aff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMU2GLa6h7y+(49hMiiLJB0#}*>Vv)9Kfy&=)d!dw{6uE_#QYm}yE_CB|x7^)( zFKw-?P2jClhVLPBQb& z%sFRg&Y5p_a_$8H?97|Z0CfPMQ5DFSP%}pna#3fMSU6Koh-42i3;|f+Ly#%X(vBvg z2t*NxA`nF&ia->Bg%AO{vqjP7x%ZVcYNH555x6HKAifU?ssfWCPAin34r*iyKqyiG zS*TBWfV4@3m<(}Rp){pus_X$nQw&oKROTd42zA0_h|>y{IiNBJ3|Gc5LqWMZ*(Ibp zU{Yb!MiGc2FgpU`^A(o`ey5Q;DMm+(U?dav`#jIN-8VAFZL2uUYq~r)Fl^V#Nn_izNM)$sc1^F? z>E&J1m(NKnfu=Ey4fDFm$?dI8jfvKl_Nm5%>bJFTpPFJ?ZA0^}p3|e_6O&I)J@uOM z4#O`5ESur&rMX>o{6d#B^E5m^2(U*?m~ zJz38^lCuirUw_tf@}n+EswF-3gT9vwx}@TOO}1igm@gOh zy<>sxx&Co0=Mysa*3uQL*R6lJsqN7{sT)=IE#uY885^Y7xPg7fwsOacwi%3^F#N3L znznnkzhL`z#bV5F#VWg zWGsi9Oqp%n#`OMza+MzpCwJ^*`asqj9VHk2YHSRrlO4K#O00ay@Ppnl%cWg?O3O>{ z*6Q7wc0x!yOp|t1pWLVpUWTDQ*`!8X+%P&c!fx0HgOCLmitrpEji|~ODQPR)%81OoTuIy64vjd=7c1#*mSo~}51S>L*B5*d#-oR!B2c{_`IKqWeF(|0VP8?dBi$+vcGF From 65849a5a2dce4d9c40954f86ef5901a800c2e507 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Mon, 28 Oct 2019 11:38:38 +0800 Subject: [PATCH 84/93] Delete .DS_Store --- dpgen/auto_test/.DS_Store | Bin 8196 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 dpgen/auto_test/.DS_Store diff --git a/dpgen/auto_test/.DS_Store b/dpgen/auto_test/.DS_Store deleted file mode 100644 index 6024b30f6cc24793b5397d9f7caa311b53fa92e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMTTC5A82*2tutSRsl@|6?%CUrk^EZvm(V0EHeQ`D&`}P=sAP%Su6@DI$p!5AI~ja#Ga$EH$~zJ5+=S zgb0KPgb0KPgb4f}5THF<6lH~dUs}UDL?A@qoVoKD*p&TQXB#N zLTxS@B%^_h2XanIvQR-8N>YYmaKu0vPWouz7Z2o|lrkJJIDB9*G6p9U^hc-PkNWO_ zaVf((L?A?9IRfJKDFh2lNTqVOpWiLh^_rW%$AZG5RmCNWQmT}el|G&vcXCNj^RjN2 zmN_nZM>TIe6}0;u$C__zsX^1ojq%EE$M!VSHZp#&sT<^SV#u_0C)edMCn*hz z!W1^ft7m3*v^K}0t=l?gV^P^|>)0_n%ap46mfgLlCeBaKJURQ+YceAYz6wyjB*RM! z=~?bnx4fPxcr`UC)B7Qx9%HN3-h+n@k8z%LjbnzTdFGUn&^*H(ER-deM+X4B?}o7*1Uo48SSUpcQ>%h)L4VSDCj)5r|uOx+tF(cH9Q>!y8XXv%cW zlx6hW+JsSoZH(PmUsYYEM$`xLrllbYuTzGzDf4XB^v?TZY^+t;37uws#L>klI)7JT zzNM~KRgVixcgCPvR}^2}(5SM0m$Kkm;23LStp5pGNbb@U#Kc>+F?GPwQijEKCd1md zGj(W6rpgZm%ALEII-GVUCMZR>0%L(X-l?i5#mI*>*Xx@!Y?{@lG`yc(t=gj~Bf{FL z>olvnc%xiwABMVkv+QxPlc*4bJ+L1}Aq_U<;5oPm&%-6S4A z@Duz3zrpYD2mA?tV+mH`daS}~d=Q)P5!{M9a5wJ7ICkPe?8C?K7$)%qrcg%%Posl5 zJde{jgU{ead;wp?m+*DGf>-fvyoT@L`*m zL{Gj-T3cB=BLedxY3*P;72+u`mexHi&crLmLH6q-38rvdiG3?_?@hP@*WqLMoH+L# z+=8FsSNID7i;??$i{J*V!Ohr!58)P!VH>s+^Ez-RCU772-~nP^68muwhj4`0m-g8= zj%P809%hM!bNDoI@L9YNu<&Jk1>eBSOE}k?XPcCGb%AqJ$&76|_8HRT8M@dx?A=`m z6v}j}#rc2V%J=_wSJGiNAp#)+ix9w~L^9Dus+B(b;;bE|=M+7n2){Wg{Sc}aT?9~n m{trWHN6A&h!~;1eC26Sq>lXo$aR2v#m*|K4{{k5IRO=tHU(|2_ From 8b6deced798b8a824fd5e6c9d93f93b525aeb453 Mon Sep 17 00:00:00 2001 From: Waikit Chan <37867949+BaozCWJ@users.noreply.github.com> Date: Mon, 28 Oct 2019 11:43:46 +0800 Subject: [PATCH 85/93] Delete insert_data.py --- dpgen/auto_test/lib/insert_data.py | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 dpgen/auto_test/lib/insert_data.py diff --git a/dpgen/auto_test/lib/insert_data.py b/dpgen/auto_test/lib/insert_data.py deleted file mode 100644 index e8598a3c3..000000000 --- a/dpgen/auto_test/lib/insert_data.py +++ /dev/null @@ -1,9 +0,0 @@ -#coding=utf-8 -# ls 0{1,2,5}*/*/*/vasp-k0.10/result|python insert_data.py -import sys -import requests -for line in sys.stdin: - expr_type, element, structure, data_type, result = line.strip().split('/') - expr_type = expr_type.split('.')[-1] - data_type = data_type.split('-')[0].strip() - res = requests.post('http://115.27.161.2:5000/insert_test_data?username=chenweijie&expr_type=%s&data_type=%s' % (data_type, expr_type), data=open(line.strip()).read()) From 1e3a8d4bc4cc81bf5f6d1ff473c0b23b874ed7fd Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Mon, 28 Oct 2019 14:53:08 +0800 Subject: [PATCH 86/93] add smtp logging --- dpgen/generator/run.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dpgen/generator/run.py b/dpgen/generator/run.py index cf92dbdb4..86984e208 100644 --- a/dpgen/generator/run.py +++ b/dpgen/generator/run.py @@ -16,6 +16,7 @@ import json import random import logging +import logging.handlers import warnings import shutil import time @@ -1670,6 +1671,10 @@ def run_iter (param_file, machine_file) : fmachine=SHORT_CMD+'_'+machine_file.split('.')[0]+'.'+jdata.get('pretty_format','json') dumpfn(mdata,fmachine,indent=4) + if mdata.get('handlers', None): + if mdata['handlers'].get('smtp', None): + dlog.addHandler(logging.handlers.SMTPHandler(**mdata['handlers']['smtp'])) + max_tasks = 10000 numb_task = 9 record = "record.dpgen" From ee7d97f219f5e768cef0aeeb572f7d92c3da9139 Mon Sep 17 00:00:00 2001 From: Jinzhe Zeng Date: Mon, 28 Oct 2019 23:34:16 +0800 Subject: [PATCH 87/93] add queue for smtp logging --- dpgen/generator/run.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dpgen/generator/run.py b/dpgen/generator/run.py index 86984e208..7fa034773 100644 --- a/dpgen/generator/run.py +++ b/dpgen/generator/run.py @@ -17,6 +17,7 @@ import random import logging import logging.handlers +import queue import warnings import shutil import time @@ -1673,7 +1674,12 @@ def run_iter (param_file, machine_file) : if mdata.get('handlers', None): if mdata['handlers'].get('smtp', None): - dlog.addHandler(logging.handlers.SMTPHandler(**mdata['handlers']['smtp'])) + que = queue.Queue(-1) + queue_handler = logging.handlers.QueueHandler(que) + smtp_handler = logging.handlers.SMTPHandler(**mdata['handlers']['smtp']) + listener = logging.handlers.QueueListener(que, smtp_handler) + dlog.addHandler(queue_handler) + listener.start() max_tasks = 10000 numb_task = 9 From 7355c032b9cd7ea052021899681b3052584a79cc Mon Sep 17 00:00:00 2001 From: Yuan Fengbo Date: Mon, 28 Oct 2019 23:46:41 +0800 Subject: [PATCH 88/93] calculate time and iteration info --- dpgen/main.py | 6 ++- dpgen/tools/run_report.py | 8 +++- dpgen/tools/stat_iter.py | 78 ++++++++++++++++++++++++++++++++++++ dpgen/tools/update_time.py | 81 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 dpgen/tools/stat_iter.py create mode 100755 dpgen/tools/update_time.py diff --git a/dpgen/main.py b/dpgen/main.py index 5a339fbd7..41c17bd53 100644 --- a/dpgen/main.py +++ b/dpgen/main.py @@ -84,9 +84,13 @@ def main(): "run/report", help="Report the systems and the thermodynamic conditions of the labeled frames.") parser_rr.add_argument("JOB_DIR", type=str, - help="the directory of the DP-GEN job") + help="the directory of the DP-GEN job,") parser_rr.add_argument('-s',"--stat-sys", action = 'store_true', help="count the labeled frames for each system") + parser_rr.add_argument('-i', "--stat-iter", action= 'store_true', + help="print the iteration candidate,failed,accurate count and fp calculation,success and fail count") + parser_rr.add_argument('-t', "--stat-time", action= 'store_true', + help="print the iteration time, warning!! assume model_devi parallel cores == 1") parser_rr.add_argument('-p',"--param", type=str, default = 'param.json', help="the json file provides DP-GEN paramters, should be located in JOB_DIR") parser_rr.add_argument('-v',"--verbose", action = 'store_true', diff --git a/dpgen/tools/run_report.py b/dpgen/tools/run_report.py index 8c7d31a36..ec0ef6dbd 100755 --- a/dpgen/tools/run_report.py +++ b/dpgen/tools/run_report.py @@ -4,6 +4,7 @@ import numpy as np import subprocess as sp from dpgen.tools.stat_sys import stat_sys +from dpgen.tools.stat_iter import stat_iter, stat_time def run_report(args): @@ -12,7 +13,12 @@ def run_report(args): stat_sys(args.JOB_DIR, args.param, args.verbose) report_count += 1 # other stats added in the following - + if args.stat_iter: + stat_iter(args.JOB_DIR, args.param, args.verbose) + report_count += 1 + if args.stat_time: + stat_time(args.JOB_DIR, args.param, args.verbose) + report_count += 1 if report_count == 0: print('nothing to report, rerun with -h for help') diff --git a/dpgen/tools/stat_iter.py b/dpgen/tools/stat_iter.py new file mode 100644 index 000000000..8bfb19831 --- /dev/null +++ b/dpgen/tools/stat_iter.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 + +import os,sys,json +import subprocess +from collections import defaultdict + +import dpdata + +def stat_iter(target_folder, + param_file = 'param.json', + verbose = True, + mute = False): + jdata={} + with open(f"{target_folder}/{param_file}") as param_file: + jdata = json.load(param_file) + iter_dict = defaultdict(lambda: defaultdict(int)) + output = subprocess.run([f"wc -l {target_folder}/iter.??????/02.fp/*out", ], + shell=True,stdout=subprocess.PIPE).stdout + data = output.decode() # split(b'\n') + for line in data.split('\n'): + if 'out' in line: + num, relative_path_doc = line.strip().split(' ') + path_doc = os.path.abspath(relative_path_doc) + num = int(num) + prefix, iter_dirname, stage, out_filename = path_doc.rsplit('/',3) + pk_id, out_filename = path_doc.rsplit('/', 1) + iter = int(iter_dirname.split('.')[-1]) + out_id = int(out_filename.strip().split('.')[-2]) + out_type = out_filename.strip().split('.')[0] + iter_dict[pk_id][out_type] += num + # for ii in + output2 = subprocess.run([f"ls -d -1 {target_folder}/iter.??????/02.fp/task.*/OUTCAR", ], + shell=True,stdout=subprocess.PIPE).stdout + data2 = output2.decode() + if verbose: + # print('find OUTCAR', data2) + print("use param_jsonfile jdata['type_map']", jdata['type_map']) + for line in data2.split('\n'): + if line: + # [/home/felix/workplace/SiC/iter.000002/02.fp/task.018.000040/OUTCAR] + path_doc = os.path.abspath(line) + pk_id, task_dirname, OUTCAR_filename=path_doc.rsplit('/', 2) + try: + _sys = dpdata.LabeledSystem(path_doc, type_map = jdata['type_map'] ) + except: + try: + _sys = dpdata.LabeledSystem(path_doc.replace('OUTCAR','vasprun.xml'), type_map = jdata['type_map']) + except: + _sys = dpdata.LabeledSystem() + if len(_sys) == 1: + pass + else: + if verbose: + print('OUTCAR not label by dpdata, not convergence or unfinshed', path_doc) + iter_dict[pk_id]['OUTCAR_not_convergence'] +=1 + iter_dict[pk_id]['OUTCAR_total_count'] +=1 + for pk_id in {**iter_dict}: + if iter_dict[pk_id]['OUTCAR_total_count']: + iter_dict[pk_id]['reff']=round(iter_dict[pk_id]['OUTCAR_not_convergence']/iter_dict[pk_id]['OUTCAR_total_count'],5) + for pk_id, value in iter_dict.items(): + print(f"{pk_id}:candidate:{value['candidate']}" + f":rest_failed:{value['rest_failed']}" + f":rest_accurate:{value['rest_accurate']}" + f":OUTCAR_total_count:{value['OUTCAR_total_count']}" + f":OUTCAR_not_convergence:{value['OUTCAR_not_convergence']}" + f":reff:{value['reff']}") + + + +def stat_time(target_folder, + param_file = 'param.json', + verbose = True, + mute = False): + script = os.path.join(os.path.dirname(__file__), 'update_time.py') + output = subprocess.run([f'bash {script}'], + shell=True,stdout=subprocess.PIPE).stdout + data = output.decode() + print(data) \ No newline at end of file diff --git a/dpgen/tools/update_time.py b/dpgen/tools/update_time.py new file mode 100755 index 000000000..ca258aea8 --- /dev/null +++ b/dpgen/tools/update_time.py @@ -0,0 +1,81 @@ +#!/bin/bash + +model_devi_paral_cores=1 + +if [[ -a time.log ]] +then + rm time.log +fi +for train_dir in `ls -d -1 iter.??????/00.train/`;do +sec=0 +tothour=0 +upload_task_dir_num=0 +recycle_task_file_num=0 +# echo $train_dir +upload_task_dir_num=$(ls -1 -d $train_dir/??? |wc -l) +if [[ -a train_time.log ]] +then + rm train_time.log +fi +grep -H --text 'wall time' $train_dir/???/train.log > train_time.log +recycle_task_file_num=$(wc -l < train_time.log) + while read line; do +mysec=$(echo "$line" |cut -d: -f4 |sed 's/s\| //g') +sec=$(echo "$mysec + $sec" | bc) + done < train_time.log +# echo $hour:$min:$sec +tothour=$(echo "scale=3; $sec/3600"|bc) +echo "00.train:$(realpath $train_dir):paral_cores:GPUV100:upload_task_dir_num:$upload_task_dir_num:recycle_task_file_num:$recycle_task_file_num:total core hour:$tothour" | tee -a time.log +done + +for model_devi_dir in `ls -d -1 iter.??????/01.model_devi/`;do +sec=0 +min=0 +hour=0 +tothour=0 +upload_task_dir_num=0 +recycle_task_file_num=0 +# echo $model_devi_dir +upload_task_dir_num=$(ls -1 -d $model_devi_dir/task.* |wc -l) +if [[ -a model_devi_time.log ]] +then + rm model_devi_time.log +fi +grep -H --text 'wall' $model_devi_dir/task.*/log.lammps > model_devi_time.log +recycle_task_file_num=$(wc -l < model_devi_time.log) + while read line; do +mysec=$(echo "$line" |cut -d: -f5) +sec=$(echo "$mysec + $sec" | bc) +mymin=$(echo "$line" |cut -d: -f4) +min=$(echo "$mymin + $min" | bc) +myhour=$(echo "$line" |cut -d: -f3) +hour=$(echo "$myhour + $hour" | bc) + done < model_devi_time.log +# echo $hour:$min:$sec +tothour=$(echo "scale=3; ($hour*3600+$min*60+$sec)*$model_devi_paral_cores/3600"|bc) +echo "01.model_devi:$(realpath $model_devi_dir):paral_cores:$model_devi_paral_cores:upload_task_dir_num:$upload_task_dir_num:recycle_task_file_num:$recycle_task_file_num:total core hour:$tothour" | tee -a time.log +done + +for fp_dir in `ls -d -1 iter.??????/02.fp/`;do +core_sec=0 +tothour=0 +upload_task_dir_num=0 +recycle_task_file_num=0 +# echo $fp_dir +upload_task_dir_num=$(ls -1 -d $fp_dir/task.* |wc -l) +if [[ -a fp_time.log ]] +then + rm fp_time.log +fi +grep -H --text 'CPU time' $fp_dir/task.*/OUTCAR > fp_time.log +recycle_task_file_num=$(wc -l < fp_time.log) + while read line;do +mysec=$(echo "$line" |cut -d: -f3 |sed 's| ||g') +file_name=$(echo "$line" | cut -d: -f1) +fp_paral_cores=$(grep 'total cores' $file_name |grep -o '[0-9]*') +core_sec=$(echo "$mysec * $fp_paral_cores + $core_sec" | bc) + done < fp_time.log +tothour=$(echo "scale=3; $core_sec/3600"|bc) +echo "02.fp:$(realpath $fp_dir):paral_cores:$fp_paral_cores:upload_task_dir_num:$upload_task_dir_num:recycle_task_file_num:$recycle_task_file_num:total core hour:$tothour" | tee -a time.log +done +wc -l iter.??????/02.fp/*out> candi_fail_accu.log From d4187d60996f28fa396b3be4975574eea4895c44 Mon Sep 17 00:00:00 2001 From: Yuan Fengbo Date: Tue, 29 Oct 2019 00:20:50 +0800 Subject: [PATCH 89/93] time && iteration info --- dpgen/tools/stat_iter.py | 2 +- dpgen/tools/update_time.py | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/dpgen/tools/stat_iter.py b/dpgen/tools/stat_iter.py index 8bfb19831..43eabd4a0 100644 --- a/dpgen/tools/stat_iter.py +++ b/dpgen/tools/stat_iter.py @@ -72,7 +72,7 @@ def stat_time(target_folder, verbose = True, mute = False): script = os.path.join(os.path.dirname(__file__), 'update_time.py') - output = subprocess.run([f'bash {script}'], + output = subprocess.run([f'bash {script} {target_folder}'], shell=True,stdout=subprocess.PIPE).stdout data = output.decode() print(data) \ No newline at end of file diff --git a/dpgen/tools/update_time.py b/dpgen/tools/update_time.py index ca258aea8..29a08e311 100755 --- a/dpgen/tools/update_time.py +++ b/dpgen/tools/update_time.py @@ -2,11 +2,18 @@ model_devi_paral_cores=1 +if [[ -n $1 ]] +then + target_dir=$1 +else + target_dir="./" +fi + if [[ -a time.log ]] then rm time.log fi -for train_dir in `ls -d -1 iter.??????/00.train/`;do +for train_dir in `ls -d -1 $target_dir/iter.??????/00.train/`;do sec=0 tothour=0 upload_task_dir_num=0 @@ -28,7 +35,7 @@ echo "00.train:$(realpath $train_dir):paral_cores:GPUV100:upload_task_dir_num:$upload_task_dir_num:recycle_task_file_num:$recycle_task_file_num:total core hour:$tothour" | tee -a time.log done -for model_devi_dir in `ls -d -1 iter.??????/01.model_devi/`;do +for model_devi_dir in `ls -d -1 $target_dir/iter.??????/01.model_devi/`;do sec=0 min=0 hour=0 @@ -56,7 +63,7 @@ echo "01.model_devi:$(realpath $model_devi_dir):paral_cores:$model_devi_paral_cores:upload_task_dir_num:$upload_task_dir_num:recycle_task_file_num:$recycle_task_file_num:total core hour:$tothour" | tee -a time.log done -for fp_dir in `ls -d -1 iter.??????/02.fp/`;do +for fp_dir in `ls -d -1 $target_dir/iter.??????/02.fp/`;do core_sec=0 tothour=0 upload_task_dir_num=0 @@ -78,4 +85,4 @@ tothour=$(echo "scale=3; $core_sec/3600"|bc) echo "02.fp:$(realpath $fp_dir):paral_cores:$fp_paral_cores:upload_task_dir_num:$upload_task_dir_num:recycle_task_file_num:$recycle_task_file_num:total core hour:$tothour" | tee -a time.log done -wc -l iter.??????/02.fp/*out> candi_fail_accu.log +wc -l $target_dir/iter.??????/02.fp/*out> candi_fail_accu.log From 6f5a248ba1e47964ab952148319935e3fe049a9e Mon Sep 17 00:00:00 2001 From: AnguseZhang <529133328@qq.con> Date: Tue, 29 Oct 2019 16:19:13 +0800 Subject: [PATCH 90/93] Converge database interface and provide examples. --- dpgen/database/run.py | 150 ++++++++++++++++++++++---------- dpgen/main.py | 14 +-- examples/database/param_Ti.json | 19 ++++ tests/database/data.tar.gz | Bin 64996 -> 1413120 bytes tests/database/param_Al.json | 19 ++++ tests/database/test_db_vasp.py | 14 ++- 6 files changed, 160 insertions(+), 56 deletions(-) create mode 100644 examples/database/param_Ti.json create mode 100644 tests/database/param_Al.json diff --git a/dpgen/database/run.py b/dpgen/database/run.py index 5416bcfb9..7a524a459 100644 --- a/dpgen/database/run.py +++ b/dpgen/database/run.py @@ -4,6 +4,7 @@ import os import time +import json from uuid import uuid4 from threading import Thread from glob import glob @@ -13,31 +14,43 @@ from dpgen.database.vasp import VaspInput from dpdata import System,LabeledSystem from monty.serialization import loadfn,dumpfn +import numpy as np +import traceback OUTPUT=SHORT_CMD+'_db.json' -SUPPORTED_CACULATOR=['vasp','pwscf','siesta','gaussian'] +SUPPORTED_CACULATOR=['vasp','pwscf','gaussian'] ITERS_PAT="iter.*/02.fp/task*" INIT_PAT="init/*/02.md/sys-*/scale-*/*" def db_run(args): dlog.info ("collecting data") - print(args.ID_PREFIX) - _main(args.PATH, args.CALCULATOR, args.OUTPUT,args.ID_PREFIX) + #print(args.ID_PREFIX) + _main(args.PARAM) dlog.info ("finished") -def _main(path,calculator,output,id_prefix): +def _main(param): + with open(param, "r") as fp: + jdata = json.load(fp) + calculator = jdata["calculator"] + path = jdata["path"] + calulator = jdata["calculator"] + output = jdata["output"] + config_info_dict = jdata["config_info_dict"] + id_prefix = jdata["id_prefix"] + skip_init = False + if "skip_init" in jdata: + skip_init = jdata["skip_init"] + ## The mapping from sys_info to sys_configs assert calculator.lower() in SUPPORTED_CACULATOR dlog.info('data collection from: %s'%path) if calculator == "vasp": - parsing_vasp(path,output,id_prefix) + parsing_vasp(path,config_info_dict,skip_init, output,id_prefix) elif calculator == 'gaussian': parsing_gaussian(path,output) - elif calculator == "siesta": - parsing_siesta(path, output) else: parsing_pwscf(path,output) -def parsing_vasp(path,output=OUTPUT,id_prefix=None): +def parsing_vasp(path,config_info_dict, skip_init, output=OUTPUT,id_prefix=None): fp_iters=os.path.join(path,ITERS_PAT) dlog.debug(fp_iters) @@ -46,54 +59,103 @@ def parsing_vasp(path,output=OUTPUT,id_prefix=None): fp_init=os.path.join(path,INIT_PAT) dlog.debug(fp_init) f_fp_init=glob(fp_init) - dlog.info("len initialization data: %s"%len(f_fp_init)) - entries=_parsing_vasp(f_fp_init,id_prefix,iters=False) - entries.extend(_parsing_vasp(f_fp_iters,id_prefix)) - dlog.info("len collected data: %s"%len(entries)) - + if skip_init: + entries = _parsing_vasp(f_fp_iters,config_info_dict, id_prefix) + dlog.info("len collected data: %s"%len(entries)) + else: + dlog.info("len initialization data: %s"%len(f_fp_init)) + entries=_parsing_vasp(f_fp_init,config_info_dict, id_prefix,iters=False) + entries.extend(_parsing_vasp(f_fp_iters,config_info_dict, id_prefix)) + dlog.info("len collected data: %s"%len(entries)) + #print(output) + #print(entries) dumpfn(entries,output,indent=4) -def _parsing_vasp(paths,id_prefix,iters=True): +def _parsing_vasp(paths,config_info_dict, id_prefix,iters=True): entries=[] icount=0 + if iters: + iter_record = [] + iter_record_new = [] + try: + with open ("record.database", "r") as f_record: + iter_record = [i.split()[0] for i in f_record.readlines()] + iter_record.sort() + dlog.info("iter_record") + dlog.info(iter_record) + except: + pass for path in paths: + try: f_outcar = os.path.join(path,'OUTCAR') f_job = os.path.join(path,'job.json') - - try: - vi = VaspInput.from_directory(path) - if os.path.isfile(f_job): - attrib=loadfn(f_job) - else: - attrib={} + tmp_iter = path.split('/')[-3] + if (tmp_iter in iter_record) and (tmp_iter != iter_record[-1]): + continue + if tmp_iter not in iter_record_new: + iter_record_new.append(tmp_iter) + vi = VaspInput.from_directory(path) + if os.path.isfile(f_job): + attrib=loadfn(f_job) + else: + attrib={} - if iters and attrib: - tmp_=path.split('/')[-1] - iter_info=tmp_.split('.')[1] - task_info=tmp_.split('.')[-1] - attrib['iter_info']=iter_info - attrib['task_info']=task_info - else: - pass - comp=vi['POSCAR'].structure.composition - ls = LabeledSystem(f_outcar) - lss=ls.to_list() - for ls in lss: - if id_prefix: - eid=id_prefix+"_"+str(icount) - else: - eid = str(uuid4()) - entry=Entry(comp,'vasp',vi.as_dict(),ls.as_dict(),attribute=attrib,entry_id=eid) - entries.append(entry) - icount+=1 - except: - dlog.info("failed here : %s"%path) + if iters and attrib: + # generator/Cu/iter.000031/02.fp/task.007.000000 + tmp_=path.split('/')[-1] + #config_info=tmp_.split('.')[1] + task_info=tmp_.split('.')[-1] + tmp_iter = path.split('/')[-3] + iter_info = tmp_iter.split('.')[-1] + sys_info = path.split('/')[-4] + config_info_int = int(tmp_.split('.')[1]) + for (key, value) in config_info_dict.items(): + if config_info_int in value: + config_info = key + attrib['config_info']=config_info + attrib['task_info']=task_info + attrib['iter_info']=iter_info + attrib['sys_info']=sys_info + with open(f_outcar , "r") as fin_outcar: + infile_outcar = fin_outcar.readlines() + for line in infile_outcar: + if "running on" in line: + attrib["core"] = int(line.split()[2]) + if "Elapse" in line: + attrib["wall_time"] = float(line.split()[-1]) + if "executed on" in line: + attrib["date"] = line.split()[-2] + attrib["clocktime"] = line.split()[-1] + dlog.info("Attrib") + dlog.info(attrib) + comp=vi['POSCAR'].structure.composition + ls = LabeledSystem(f_outcar) + lss=ls.to_list() + for ls in lss: + if id_prefix: + eid=id_prefix+"_"+str(icount) + else: + eid = str(uuid4()) + entry=Entry(comp,'vasp',vi.as_dict(),ls.as_dict(),attribute=attrib,entry_id=eid) + entries.append(entry) + icount+=1 + except Exception: + #dlog.info(str(Exception)) + dlog.info("failed for %s"%(path)) + #pass + if iters: + iter_record.sort() + iter_record_new.sort() + with open("record.database" , "w") as fw: + for line in iter_record: + fw.write(line + "\n") + for line in iter_record_new: + fw.write(line + "\n") return entries def parsing_pwscf(path,output=OUTPUT): pass -def parsing_siesta(path,output=OUTPUT): - pass + def parsing_gaussian(path,output=OUTPUT): pass diff --git a/dpgen/main.py b/dpgen/main.py index 5a339fbd7..283e6d89e 100644 --- a/dpgen/main.py +++ b/dpgen/main.py @@ -104,16 +104,10 @@ def main(): # db parser_db = subparsers.add_parser( "db", - help="Collecting data from Deep Generator.") - parser_db.add_argument('PATH', type=str, - help="root path for dpgen modeling") - parser_db.add_argument('ENGINE', type=str, - help="engine used for labeling: vasp/pwscf/cp2k/gaussian/siesta") - parser_db.add_argument('OUTPUT', type=str, - help="output filename : file.json/file.yaml") - parser_db.add_argument("ID_PREFIX", type=str, default=None, - nargs="?", - help="prefix of an entry id") + help="Collecting data from DP-GEN.") + + parser_db.add_argument('PARAM', type=str, + help="parameter file, json format") parser_db.set_defaults(func=db_run) diff --git a/examples/database/param_Ti.json b/examples/database/param_Ti.json new file mode 100644 index 000000000..5b222f30a --- /dev/null +++ b/examples/database/param_Ti.json @@ -0,0 +1,19 @@ +{ + "path" : "/path/to/Ti", + "calculator" : "vasp", + "_comment" : "Current only support VASP", + "output" : "./db_Ti.json", + "id_prefix" : "", + "config_info_dict" : { + "fcc-bulk" : [0,1,2,3,4,5,6,7], + "hcp-bulk" : [8,9,10,11,12,13,14,15], + "bcc-bulk" : [16,17,18,19,20,21,22,23], + "fcc-surf-100" : [24,25,26,27,28,29,30,31], + "fcc-surf-111" : [32,33,34,35,36,37,38,39], + "fcc-surf-110" : [40,41,42,43,44,45,46,47], + "hcp-surf-001" : [48,49,50,51,52,53,54,55], + "hcp-surf-100" : [56,57,58,59,60,61,62,63], + "hcp-surf-110" : [64,65,66,67,68,69,70,71] + }, + "skip_init" : true +} diff --git a/tests/database/data.tar.gz b/tests/database/data.tar.gz index 2f733dd0fdf51e987a4e1f5780404b9b160f12b1..ad7e54d6b226c46b71b6af46360a4b46c34bf808 100644 GIT binary patch literal 1413120 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

s8` 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 T1I-LHGtkUHGXwt@XW)MUl_5>Q literal 64996 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�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∋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 Date: Tue, 29 Oct 2019 16:20:30 +0800 Subject: [PATCH 91/93] rename update_time.py to .sh --- dpgen/tools/stat_iter.py | 7 +++---- dpgen/tools/stat_sys.py | 1 + dpgen/tools/{update_time.py => update_time.sh} | 0 setup.py | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) rename dpgen/tools/{update_time.py => update_time.sh} (100%) diff --git a/dpgen/tools/stat_iter.py b/dpgen/tools/stat_iter.py index 43eabd4a0..228b051d4 100644 --- a/dpgen/tools/stat_iter.py +++ b/dpgen/tools/stat_iter.py @@ -65,14 +65,13 @@ def stat_iter(target_folder, f":OUTCAR_not_convergence:{value['OUTCAR_not_convergence']}" f":reff:{value['reff']}") - - def stat_time(target_folder, param_file = 'param.json', verbose = True, mute = False): - script = os.path.join(os.path.dirname(__file__), 'update_time.py') + script = os.path.join(os.path.dirname(__file__), 'update_time.sh') output = subprocess.run([f'bash {script} {target_folder}'], shell=True,stdout=subprocess.PIPE).stdout data = output.decode() - print(data) \ No newline at end of file + print(data) + diff --git a/dpgen/tools/stat_sys.py b/dpgen/tools/stat_sys.py index 45d1d80db..83ddf75ad 100644 --- a/dpgen/tools/stat_sys.py +++ b/dpgen/tools/stat_sys.py @@ -77,6 +77,7 @@ def stat_sys(target_folder, sys_tasks_all[ii][jj][1], sys_tasks_all[ii][jj][2], sys_tasks_all[ii][jj][3])) + os.chdir(cwd) return sys, sys_tasks_count, sys_tasks_all def run_report(args): diff --git a/dpgen/tools/update_time.py b/dpgen/tools/update_time.sh similarity index 100% rename from dpgen/tools/update_time.py rename to dpgen/tools/update_time.sh diff --git a/setup.py b/setup.py index 8e1b8747b..c2451552d 100755 --- a/setup.py +++ b/setup.py @@ -42,6 +42,7 @@ 'dpgen/database', 'dpgen/tools' ], + data_files = [('dpgen/tools/', ['dpgen/tools/update_time.sh', ])], # package_data={'example':['*.json']}, classifiers=[ "Programming Language :: Python :: 3.6", From 41b6e4632dbb2e0ddd2b17ed089a0255c018e518 Mon Sep 17 00:00:00 2001 From: AnguseZhang <529133328@qq.con> Date: Tue, 29 Oct 2019 22:19:23 +0800 Subject: [PATCH 92/93] Unittest for database --- tests/database/test_db_vasp.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/database/test_db_vasp.py b/tests/database/test_db_vasp.py index 3cc583cba..fb9c3a8e0 100644 --- a/tests/database/test_db_vasp.py +++ b/tests/database/test_db_vasp.py @@ -118,11 +118,13 @@ def testEntry(self): def testParsingVasp(self): parsing_vasp(self.cwd, self.config_info_dict, self.skip_init,self.output, id_prefix=dpgen.SHORT_CMD ) - try: - Potcar(['Al']) - ref=os.path.join(self.cwd,'data/all_data_pp.json') - except: - ref=os.path.join(self.cwd,'data/all_data.json') + #try: + # Potcar(['Al']) + # ref=os.path.join(self.cwd,'data/all_data_pp.json') + #except: + # ref=os.path.join(self.cwd,'data/all_data.json') + Potcar(['Al']) + ref=os.path.join(self.cwd,'data/all_data_pp.json') ret=os.path.join(self.cwd,'dpgen_db.json') retd=loadfn(ret) From 420b41d0f935dd32ac246599620a90eceaa6478c Mon Sep 17 00:00:00 2001 From: AnguseZhang <529133328@qq.con> Date: Tue, 29 Oct 2019 22:26:38 +0800 Subject: [PATCH 93/93] Unittest for database --- tests/database/test_db_vasp.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/database/test_db_vasp.py b/tests/database/test_db_vasp.py index fb9c3a8e0..577d2f7da 100644 --- a/tests/database/test_db_vasp.py +++ b/tests/database/test_db_vasp.py @@ -123,8 +123,9 @@ def testParsingVasp(self): # ref=os.path.join(self.cwd,'data/all_data_pp.json') #except: # ref=os.path.join(self.cwd,'data/all_data.json') - Potcar(['Al']) + #Potcar(['Al']) ref=os.path.join(self.cwd,'data/all_data_pp.json') + ret=os.path.join(self.cwd,'dpgen_db.json') retd=loadfn(ret)