def write_requench_data(lmpdat_a, dcd_ab, index, lmpdat_b=None, output_lmpdat_a="output_name_a.lmpdat", output_lmpdat_b="output_name_b.lmpdat"): """ Write a new data file with the coordinates from a dcd file given by the index. Writes a new lammps data file, which has the same topology but different coordinates than the lmpdat that is given. Parameters ---------- lmpdat_a : str lammps data file with the topology e.g. for the solvate lmpdat_b : None or str lammps data file with the topology e.g. for the solvent dcd_ab : str dcd file with frames to read from the solvate-solvent system index : int index to extract the frame from (i.e. index of energetically best frame) """ sys_lmpdat_a = aglmp.read_lmpdat(lmpdat_a) sys_lmpdat_a_natoms = len(sys_lmpdat_a.atoms) sys_dcd_ab = aglmp.LmpStuff() sys_dcd_ab.import_dcd(dcd_ab) # read only the best frame which will be appended to the existing ones sys_dcd_ab.read_frames(frame=index, to_frame=index + 1) # apply box from dcd, since we are dealing with coordinates considering # that box (not doing this leads to errors during wrapping) sys_lmpdat_a.ts_boxes = sys_dcd_ab.ts_boxes # write only relevant coordinates for system a sys_lmpdat_a.ts_coords.append(sys_dcd_ab.ts_coords[-1][:sys_lmpdat_a_natoms]) # wrap coordinates outside the box back inside (may happen when a molecule # flies of and reconnects with the aggregate) sys_lmpdat_a.wrap_cell(frame_id=-1, same_molecule=True) sys_lmpdat_a.change_indices() sys_lmpdat_a.write_lmpdat(output_lmpdat_a, -1, title="Best frame of {} with index {}".format(os.path.basename(dcd_ab), index), cgcmm=True) # write only relevant coordinates for system b if lmpdat_b is not None: sys_lmpdat_b = aglmp.read_lmpdat(lmpdat_b) sys_lmpdat_b.ts_coords.append(sys_dcd_ab.ts_coords[sys_lmpdat_a_natoms + 1:]) sys_lmpdat_b.change_indices() sys_lmpdat_b.write_lmpdat(output_lmpdat_b, -1, title="Best frame of {} with index {}".format(os.path.basename(dcd_ab), index), cgcmm=True)
def _check_success(): """ Check aggregation state and close lammps instance properly. """ if rank == 0: quench_sys = aglmp.read_lmpdat(lmpcuts.input_lmpdat, dcd=lmpcuts.output_dcd) succeeded = quench_sys.check_aggregate() # send data to the other ranks for other_rank in other_ranks: comm.send(succeeded, dest=other_rank) else: succeeded = comm.recv(source=0) #print(succeeded) #succeeded = comm.bcast(succeeded, 0) # stop trying if it was if succeeded is True: # write restart file lmpcuts.unfix_undump(pylmp, lmp) lmp.command("reset_timestep 0") lmp.command("write_restart {}".format(lmpcuts.output_lmprst)) lmp.command("clear") lmp.close() return succeeded
def requench(lmpcuts, minstyle="cg"): """[summary] [description] Parameters ---------- lmpcuts : {[type]} [description] minstyle : {str}, optional [description] (the default is "cg", which [default_description]) Returns ------- [type] [description] """ lmp = lammps() pylmp = PyLammps(ptr=lmp) lmp.command("log {} append".format(lmpcuts.output_lmplog)) lmp.file(lmpcuts.settings_file) # change dielectric if lmpcuts.dielectric is not None: lmp.command("dielectric {}".format(lmpcuts.dielectric)) # read restart file from previous run lmpcuts.load_system(lmp) lmpcuts.thermo(lmp) lmp.command("fix ic_prevention all momentum 100 linear 1 1 1 angular rescale") lmp.command("fix integrator all nvt temp {0} {1} 0.1".format(lmpcuts.tstart, lmpcuts.tstop)) lmpcuts.dump(lmp, unwrap=True) if lmpcuts.pc_file is not None: lmp.file(lmpcuts.pc_file) lmp.command("reset_timestep 0") lmp.command("run {}".format(lmpcuts.runsteps)) lmpcuts.minimize(lmp, style=minstyle) lmpcuts.unfix_undump(pylmp, lmp) lmp.command("write_restart {}".format(lmpcuts.output_lmprst)) lmp.command("clear") lmp.close() # check if aggregate is intact after requenching md_sys = aglmp.read_lmpdat(lmpcuts.input_lmpdat, lmpcuts.output_dcd) aggregate_ok = md_sys.check_aggregate(frame_id=-1) return aggregate_ok
def add_dummy_to_lmpdat(lmpdat, indices_and_values, key_index=0): """ Read and write a new data file with dummy bond-/angle- or dihedral-coeffs. Compile a bond-/angle-/dihedral-coeff string for lammps and alter the lammps instance. The 'coeff-string' has only values of 0 which means it gets omitted. Needed to switch off the energy contribution of a given dihedral in the system. Parameters ---------- lmp : lammps.lammps instance the instance of lammps which will be altered lmpdat : str lammps data file that is to be read indices_and_values : dict atom ids and according entity values, e.g. {"1 2 3 4": 120, ...} key_index : int index of indices_and_values to be processed """ lmp_sys = aglmp.read_lmpdat(lmpdat) num_geom_types = None key = list(indices_and_values.keys())[key_index] cur_geometry = get_geometry_by_key(key) null_coeff = None if cur_geometry == "bond": # geometry types start with 0 num_geom_types = len(lmp_sys.bnd_types) - 1 null_coeff_id = num_geom_types + 1 elif cur_geometry == "angle": # geometry types start with 0 num_geom_types = len(lmp_sys.ang_types) - 1 null_coeff_id = num_geom_types + 1 elif cur_geometry == "dihedral": # geometry types start with 0 num_geom_types = len(lmp_sys.dih_types) - 1 null_coeff_id = num_geom_types + 1 # impropers are not supported by fix restrain else: raise Warning("***Warning: Something went wrong!") return (cur_geometry, null_coeff_id)
def add_dummy_entry(lmpdat): """ Add dummy entries to the lammps data file. Parameters ---------- lmpdat : str name of the lammps data file """ md_sys = aglmp.read_lmpdat(lmpdat) if md_sys.bnd_types != {}: ntypes = len(md_sys.bnd_types) if md_sys.bnd_types[ntypes - 1].prm1 > 0: md_sys.bnd_types[ntypes] = mds.Bond( bnd_key=ntypes, prm1=0.0, prm2=0.0, comment=" dummy bond for force field fitting") if md_sys.ang_types != {}: ntypes = len(md_sys.ang_types) if md_sys.ang_types[ntypes - 1].prm1 > 0: md_sys.ang_types[ntypes] = mds.Angle( ang_key=ntypes, prm1=0.0, prm2=0.0, comment=" dummy bond for force field fitting") if md_sys.dih_types != {}: ntypes = len(md_sys.dih_types) if md_sys.dih_types[ntypes - 1].prm_k > 0: md_sys.dih_types[ntypes] = mds.Dihedral( dih_key=ntypes, prm_k=0.0, prm_n=1, prm_d=0, weigh_factor=0, comment=" dummy angle for force field fitting") md_sys.change_indices(incr=1, mode="increase") md_sys.write_lmpdat(lmpdat, frame_id=-1, title="Default Title", cgcmm=True) return True
def get_shift_vector(lmpdat, atoms_cog1, atoms_cog2, dcd=None, frame_id=-1): """ Calculate the vector for shifting both molecules. Parameters ---------- lmpdat : str lammps data file dcd : str or None default: None dcd file from molecular dynamics run which supplies the latest coordinates atoms_cog1 : tuple or list atom indices that form the first center of geometry; if only one atom is given, it will be the center of geometry atoms_cog2 : tuple or list same as atoms_cog1 but for 2nd center of geometry Returns: -------- vt_shift : np-array normalized shifting vector """ dimer = read_lmpdat(lmpdat, dcd) if len(atoms_cog1) > 1: cog1 = dimer.get_cog(frame_id, *atoms_cog1) cog2 = dimer.get_cog(frame_id, *atoms_cog2) else: cog1 = dimer.ts_coords[frame_id][atoms_cog1[0]] cog2 = dimer.ts_coords[frame_id][atoms_cog2[0]] vt_shift = cog1 - cog2 vt_shift /= np.linalg.norm(vt_shift) return vt_shift
def calculate_distances(lmpdat, dcd, idxs_atm1, idxs_atm2): """ Calculate the distance between the center of geometry of the two benzene rings. """ distances = [] dimer_sys = read_lmpdat(lmpdat, dcd, frame_idx_start=0) #pdb.set_trace() for frame_idx in range(0, len(dimer_sys.ts_coords)): if len(idxs_atm1) == 1: cog1 = dimer_sys.ts_coords[frame_idx][idxs_atm1[0]] else: cog1 = dimer_sys.get_cog(frame_idx, *idxs_atm1) if len(idxs_atm2) == 1: cog2 = dimer_sys.ts_coords[frame_idx][idxs_atm2[0]] else: cog2 = dimer_sys.get_cog(frame_idx, *idxs_atm2) distance = np.linalg.norm(cog1 - cog2) distances.append(distance) return distances
#------------------------------------------------------------------------------- inverse_help = "Selection: box (normal), negative of box (inverted)" shft_cut_result = "Shift the cut out coordinates by these 3 vectors (index 0, 1, 2: a; 3, 4, 5: b; 6, 7, 8: c" enlarge_cut_help = "Enlarge the box of the cuttings shape by this vector" parser.add_argument("-inverse", default=False, action="store_true", help=inverse_help) parser.add_argument("-shft_cut_result", nargs=3, type=float, default=(0.0, 0.0, 0.0), metavar=("sx, sy, sz"), help=shft_cut_result) parser.add_argument("-scale_cut", default=None, nargs=9, type=float, metavar=2.42, help=enlarge_cut_help) parser.add_argument("-out", default="test.lmpdat") args = parser.parse_args() #=============================================================================== # PREPARE THE MAIN SYSTEM #=============================================================================== sys_cutfrom = ag_lammps.read_lmpdat(args.lmpdat, dcd=args.dcd, frame_idx_start=args.f, frame_idx_stop=args.f) # replicate cell if desired if args.rep is not None: # read last frame since the frame selection was done with read_lmpdat already sys_cutfrom.replicate_cell(n_start=args.rep[0], n_stop=args.rep[1], direction="a", frame_id=-1, adjust_box=True) sys_cutfrom.replicate_cell(n_start=args.rep[2], n_stop=args.rep[3], direction="b", frame_id=-1, adjust_box=True) sys_cutfrom.replicate_cell(n_start=args.rep[4], n_stop=args.rep[5], direction="c", frame_id=-1, adjust_box=True) sys_cutfrom.fetch_molecules_by_bonds() sys_cutfrom.mols_to_grps() # shift sys_cutfrom by given vector if args.shft is not None: args.shft = np.array(args.shft) M_shft = cgt.translation_matrix(args.shft) atm_idxs = list(range(len(sys_cutfrom.atoms)))
else: print("***Quenching-Info: Quenching done!") # after 20 failed attempts, end run if quench_attempts > 20 and quench_success is False: exit(101) #del quench_attempts #======================================================================# # 3. ANNEALING #======================================================================# if os.path.isfile(lmpsettings_anneal.output_lmprst) is False: if rank == 0: agk.create_folder(anneal_dir) solvate_sys = aglmp.read_lmpdat(lmpsettings_quench.input_lmpdat, dcd=lmpsettings_quench.output_dcd) solvate_sys_natoms = len(solvate_sys.atoms) atm_idxs_solvate = list(range(solvate_sys_natoms)) # change box size according to the coordinates from # quenching in order to save space solvate_sys.def_boxes_by_coords(addition=(20, 20, 20), boxtype="lammps") else: solvate_sys = None atm_idxs_solvate = None solvate_sys_natoms = None solvate_sys = comm.bcast(solvate_sys, 0) atm_idxs_solvate = comm.bcast(atm_idxs_solvate, 0) solvate_sys_natoms = comm.bcast(solvate_sys_natoms, 0)
def create_voids(lmpcuts, lmpdat_solvate, dcd_solvate=None, dcd_solvent=None): """ """ # solvate with molecule radii and cogs solvate_sys = aglmp.read_lmpdat(lmpdat_solvate, dcd_solvate, frame_idx_start=-2, frame_idx_stop=-1) radii_mol, cogs_mol = _molecules_radii(solvate_sys) indent_strs = _fix_indent_ids(radii_mol, cogs_mol, "molecule", scale_start=10, scale_stop=15) # load solution system (last frame only) solvent_sys = aglmp.read_lmpdat(lmpcuts.input_lmpdat, dcd_solvent, frame_idx_start=-2, frame_idx_stop=-1) solution_sys = mdu.merge_systems([solvate_sys, solvent_sys]) solution_sys.reset_cells() # check solvate atoms with too close contacts to solvent atoms close_atoms = _check_clashes(solution_sys, solvate_sys, solvent_sys) cogs_atoms = [solvate_sys.ts_coords[-1][i] for i in close_atoms] radii_atoms = [mde.elements_mass_radii[round(solvate_sys.atm_types[solvate_sys.atoms[i].atm_key].weigh, 1)] for i in close_atoms] # gather close atoms and remember which were close all_close_atoms = [] all_radii_atoms = [] all_cogs_atoms = [] all_close_atoms.extend(close_atoms) all_radii_atoms.extend(radii_atoms) all_cogs_atoms.extend(cogs_atoms) # load lammps and lammps settings lmp = lammps() pylmp = PyLammps(ptr=lmp) lmp.command("log {}".format(lmpcuts.output_lmplog)) if lmpcuts.gpu is True: lmpcuts.use_gpu(lmp) lmp.file(lmpcuts.settings_file) # change dielectric if lmpcuts.dielectric is not None: lmp.command("dielectric {}".format(lmpcuts.dielectric)) lmpcuts.load_system(lmp) lmpcuts.thermo(lmp) lmp.command("fix ic_prevention all momentum 100 linear 1 1 1 angular rescale") lmpcuts.dump(lmp, unwrap=True) if lmpcuts.pc_file is not None: lmp.file(lmpcuts.pc_file) #lmpcuts.fix_berendsen(lmp, group="all", ensemble="nve", keyword="iso") lmpcuts.fix_berendsen(lmp, group="all", ensemble="npt", keyword="iso", integrator="nve/limit 0.2") #lmp.command("unfix integrator") #lmp.command("fix limit_movement all nve/limit 0.05") _lmp_indent(lmp, indent_strs, lmpcuts.runsteps, keep_last_fixes=True) factor_start = 10 factor_stop = factor_start + 1 if close_atoms != []: # move solvent molecules away from close solvate atoms for _ in range(5): indent_strs = _fix_indent_ids(all_radii_atoms, all_cogs_atoms, "atom", scale_start=factor_start, scale_stop=factor_stop) _lmp_indent(lmp, indent_strs, lmpcuts.runsteps, keep_last_fixes=False) close_atoms = _check_clashes(solution_sys, solvate_sys, solvent_sys, lmpcuts.output_dcd) # add new close atoms to present ones or stop indenting if close_atoms == []: break # add further close atoms to present ones for atm_idx in close_atoms: #print(close_atoms) if atm_idx not in all_close_atoms: all_close_atoms.append(atm_idx) all_radii_atoms.append(mde.elements_mass_radii[round(solvate_sys.atm_types[solvate_sys.atoms[i].atm_key].weigh, 1)]) all_cogs_atoms.append(solvate_sys.ts_coords[-1][atm_idx]) # dynamically grow sphere around atoms factor_start += 1 factor_stop = factor_start + 1 lmpcuts.unfix_undump(pylmp, lmp) lmp.command("write_restart {}".format(lmpcuts.output_lmprst)) lmp.command("clear") lmp.close() return close_atoms == []
def quench(lmpcuts, lmpdat_main, runs=20, split=None): """ """ # check how many cores are used, leave the list empty if it is only one try: other_ranks = list(range(lmpcuts.ncores))[1:] except ValueError: other_ranks = [] def _check_success(): """ Check aggregation state and close lammps instance properly. """ if rank == 0: quench_sys = aglmp.read_lmpdat(lmpcuts.input_lmpdat, dcd=lmpcuts.output_dcd) succeeded = quench_sys.check_aggregate() # send data to the other ranks for other_rank in other_ranks: comm.send(succeeded, dest=other_rank) else: succeeded = comm.recv(source=0) #print(succeeded) #succeeded = comm.bcast(succeeded, 0) # stop trying if it was if succeeded is True: # write restart file lmpcuts.unfix_undump(pylmp, lmp) lmp.command("reset_timestep 0") lmp.command("write_restart {}".format(lmpcuts.output_lmprst)) lmp.command("clear") lmp.close() return succeeded def _run(steps): """ Helper function for running and catching an exception when anything goes wrong. """ try: lmp.command("run {}".format(steps)) except: # prevent deadlock by not nicely ending the whole program if more # than one rank is used if size > 1: MPI.COMM_WORLD.Abort() natoms_main_sys = get_natms(lmpdat_main) lmp = lammps(comm=split) pylmp = PyLammps(ptr=lmp) lmp.command("log {} append".format(lmpcuts.output_lmplog)) if lmpcuts.gpu is True: lmpcuts.use_gpu(lmp, neigh=False) lmp.file(lmpcuts.settings_file) # change dielectric if lmpcuts.dielectric is not None: lmp.command("dielectric {}".format(lmpcuts.dielectric)) lmpcuts.load_system(lmp) #lmp.command("velocity all create {} {} mom yes rot yes dist gaussian".format(lmpcuts.tstart, np.random.randint(29847587))) lmp.command("fix ic_prevention all momentum 100 linear 1 1 1 angular rescale") lmpcuts.dump(lmp, unwrap=True) lmpcuts.thermo(lmp) if lmpcuts.pc_file is not None: lmp.file(lmpcuts.pc_file) # distribute the available cores if we have lots of vacuum in our box lmp.command("comm_style tiled") lmp.command("balance 1.0 rcb") # define the atoms that may move during the simulation lmp.command("group grp_add_sys id > {}".format(natoms_main_sys)) #lmp.command("group grp_main_sys id <= {}".format(natoms_main_sys)) #lmp.command("fix freeze grp_main_sys setforce {0} {0} {0}".format(0.0)) # pre-optimization lmp.command("min_style cg") lmp.command("min_modify dmax 0.5") lmp.command("minimize 1.0e-5 1.0e-8 10000 100000") # set an additional push to the added atoms that should be docked # towards the origin at (0/0/0) # (prevents losing atoms due to being localized outside the cutoff) if rank == 0: prep_sys = aglmp.read_lmpdat(lmpcuts.input_lmpdat) cog = agm.get_cog(prep_sys.ts_coords[-1][natoms_main_sys + 1:]) cog /= np.linalg.norm(cog, axis=0) # unit vector # make vector show towards the center (0/0/0) cog_force = cog * -1 for other_rank in other_ranks: comm.send(cog_force, dest=other_rank) else: cog_force = comm.recv(source=0) #cog_force = comm.bcast(cog_force, 0) # barostatting, thermostatting only for atoms that will be docked lmp.command("fix integrator grp_add_sys nvt temp {0} {1} 0.1".format(lmpcuts.tstart, lmpcuts.tstop)) quench_success = False # runs attempts to dock the molecule for _ in range(runs): # minimize and check if that is enough for docking lmp.command("min_style quickmin") lmp.command("minimize 1.0e-5 1.0e-8 10000 100000") lmp.command("min_style cg") lmp.command("minimize 1.0e-5 1.0e-8 10000 100000") # check aggregate, i.e. docking was a success quench_success = _check_success() if quench_success is True: break del quench_success # perform a little molecular dynamics simulation with # half of the lmpcuts.runsteps _run(int(lmpcuts.runsteps)) # check aggregate, i.e. docking was a success quench_success = _check_success() if quench_success is True: break del quench_success # give 'to-be-docked' molecules a little push if minimization was not # sufficient for aggregation addforce_cmd = "fix push grp_add_sys addforce {c[0]} {c[1]} {c[2]} every 1" addforce_cmd = addforce_cmd.format(c=cog_force) lmp.command(addforce_cmd) #import time #time.sleep(30) # set force does not work #lmp.command("fix push grp_add_sys setforce {0} {0} {0}".format(*cog)) _run(1) # remove pushing force lmp.command("unfix push") # run the 2nd half of the simulation with push 'grp_add_sys' _run(int(lmpcuts.runsteps * 0.5)) # stop to-be-docked molecules from moving #lmp.command("velocity grp_add_sys set 0.0 0.0 0.0") #lmp.command("fix freeze grp_add_sys setforce {0} {0} {0}".format(0.0)) _run(int(lmpcuts.runsteps * 0.25)) return quench_success
def sysprep(lmpdat_out, lmpdat_main, lmpdat_add, dcd_main=None, dcd_add=None, frame_idx_main=-1, frame_idx_add=-1): """ Prepare the system for the next docking step. Since the kawska-zahn approach adds an agglomerate of molecules each stage, the system must be prepared for lammps beforehand. Therefor a sphere with radius r1 is created around the main system as well as a sphere with radius r2 around the agglomerate to add. Both systems are combined, checked for clashes and eventually a new lammps data file is written which can further be utilized. If Parameters ---------- lmpdat_out : str Name of merged lammps data file to write lmpdat_main : str Name of the lammps data file to add another system to lmpdat_add : str Name of the lammps data file which is added to the main molecular system dcd_main : str (optional, default: None) dcd file to load on top of lmpdat_main dcd_add : str (optional, default: None) dcd file to load on top of lmpdat_add frame_idx_main : int frame index of frame to add from dcd_main to lmpdat_main frame_idx_add : int frame index of frame to add from dcd_add to lmpdat_add Returns ------- success : bool True if successful, False otherwise. Writes a new lammps data file called sysprep_out_index """ # read and transpose the main sys to the origin main_sys = aglmp.read_lmpdat(lmpdat_main, dcd_main, frame_idx_main) main_sys.transpose_by_cog(-1, [0, 0, 0], copy=False) _natoms = len(main_sys.atoms) # read and transpose the add sys to the origin add_sys = aglmp.read_lmpdat(lmpdat_add, dcd_add, frame_idx_add) add_sys.transpose_by_cog(-1, [0, 0, 0], copy=False) # rotate add sys _rotate_sys(add_sys) # shift add sys to sphere around main sys main_sys_radius = main_sys.get_system_radius(-1) add_sys_radius = add_sys.get_system_radius(-1) kwz_radius = main_sys_radius + add_sys_radius _shift_sys(add_sys, kwz_radius) # merge both systems main_sys.extend_universe(add_sys, mode="merge") _create_new_box(main_sys) # group atoms by bonds main_sys.fetch_molecules_by_bonds() main_sys.mols_to_grps() success = _check_sys(main_sys, _natoms) # write an output lammps data only if everything worked out if success is True: # write new data file main_sys.change_indices(incr=1, mode="increase") main_sys.write_lmpdat(lmpdat_out, frame_id=0, title="System ready" + "for docking", cgcmm=True) return success
def anneal_productive(lmpcuts, atm_idxs_solvate, percentage_to_check, ensemble, group="all", keyword=None, attempts=500, output=None): """ Carry out a productive run for the annealing step of the Kawska-Zahn approach. Check regularly if the simulation is equilibrated (i.e. PotEng of the system is normally distributed). If that criteria is fulfilled, stop and check if the aggregate of the last frame is still intact (what is happening in between is not of our concern and will be checked later when the best conformation of the complex is chosen). Parameters ---------- lmpcuts : ag_lammps_sim.LmpSim The simulation settings. atm_idxs_solvate : list or tuple Indices of the solvate atoms. percentage_to_check : int or float, float will be converted to int The percentage of all frames (starting from the last frame to the first) to check the equilibration state from. ensemble : str The ensemble to run the simulation with group : str, optional The group of atoms that will be integrated. Uses lammps syntax for grouping. The default value is 'all' keyword : str, optional The keyword for the box relaxation. Allowed keywords are the same as in the lammps manual for barostatting: iso, aniso, tri. Default is 'None', which means no barostatting is done (i.e. nvt). output : str, optional Prefix for all files which were/are written by the run. Returns ------- aggregate_ok : boolean The status of the aggregate. 'True' if aggregate did not dissolve, during the run, 'False' if it did. dcd_files : list A list of all DCD files that were written during the run. For each sub- run, an int starting from '0' is prepended to the filename until the whole simulation (formed by all sub-runs) shows convergence. log_files : list A list of all lammps log files that were written during the run. For each sub- run, an int starting from '0' is prepended to the filename until the whole simulation (formed by all sub-runs) shows convergence. Log-files are always in accordance to the current DCD file. """ all_data = [] solvate_sys_natoms = len(atm_idxs_solvate) dcd_files = [] log_files = [] # renaming the current found files independently of their original name automatically # sorts them in the right order for run_idx in range(attempts): # get just the base name of the files dcd_path, dcd_filename = os.path.split(lmpcuts.output_dcd) log_path, log_filename = os.path.split(lmpcuts.output_lmplog) # create a filename having 'run_idx' and check if this file already exists run_idx_pattern = re.compile(r'^[0-9]+') # check if filename starts with an integer if run_idx_pattern.match(dcd_filename) is not None: # split dcd-file by '_' split_dcd_filename = dcd_filename.split("_") dcd_filename = "{}_{}_{}".format(run_idx, split_dcd_filename[1], split_dcd_filename[2]) del split_dcd_filename else: dcd_filename = str(run_idx) + "_" + dcd_filename if run_idx_pattern.match(log_filename) is not None: split_log_filename = log_filename.split("_") log_filename = "{}_{}_{}".format(run_idx, split_log_filename[1], split_log_filename[2]) del split_log_filename else: log_filename = str(run_idx) + "_" + log_filename lmpcuts.output_dcd = "{}/{}".format(dcd_path, dcd_filename) lmpcuts.output_lmplog = "{}/{}".format(log_path, log_filename) # read previous log- and dcd-files if they exist already if os.path.isfile(lmpcuts.output_dcd) and os.path.isfile(lmpcuts.output_lmplog): dcd_files.append(lmpcuts.output_dcd) log_files.append(lmpcuts.output_lmplog) # read potential energy of all coordinates if rank == 0: # if this fails, then a lmplog was written but no simulation # was carried out try: _append_data(all_data, lmpcuts.output_lmplog) except IndexError: os.remove(lmpcuts.output_dcd) os.remove(lmpcuts.output_lmplog) dcd_files.pop(-1) log_files.pop(-1) # skip the rest as often as there is no new file continue else: # carry out annealing run _anneal(lmpcuts, atm_idxs_solvate, ensemble, group, keyword) dcd_files.append(lmpcuts.output_dcd) log_files.append(lmpcuts.output_lmplog) # append data of last run if rank == 0: _append_data(all_data, lmpcuts.output_lmplog) # test given data so far (test applies to each newly carried out run) if rank == 0: # caveat: each first frame of output_lmplog is omitted since # it is not part of the dcd file # check last N % of all frames num_frames_to_check = int(percentage_to_check / 100 * len(all_data)) # last X % of all frames (from end to start) normally_dstributed = _test_anneal_equil(all_data[-num_frames_to_check:], xlabel="Potential Energy / eV", output=output) # check if aggregate is still fine after the last run (only if we have a normal distribution) solution_sys = aglmp.read_lmpdat(lmpcuts.input_lmpdat, lmpcuts.output_dcd) solution_sys_atoms_idxs = list(range(len(solution_sys.atoms))) aggregate_ok = solution_sys.check_aggregate(frame_id=-1, excluded_atm_idxs=solution_sys_atoms_idxs[solvate_sys_natoms:]) del (num_frames_to_check, solution_sys, solution_sys_atoms_idxs) else: aggregate_ok = False normally_dstributed = False aggregate_ok = comm.bcast(aggregate_ok) normally_dstributed = comm.bcast(normally_dstributed) # stop further runs if the aggregate is not ok or if the aggregate # is ok and the run is equilibrated (i.e. normal distribution of the # potential energy of the whole system) if (aggregate_ok is True and normally_dstributed is True) or aggregate_ok is False: break # the following prevents the 'else' condition (from for loop above) to execute #if run_idx == (attempts - 1): # break # this only applies if all attempts already exist, but the # 'lmpcuts.output_lmprst' file was never written (e.g. due to aborted runs) else: aggregate_ok = False if rank == 0: num_frames_to_check = int(percentage_to_check / 100 * len(all_data)) normally_dstributed = _test_anneal_equil(all_data[-num_frames_to_check:], xlabel="Potential Energy / eV", output=output) if normally_dstributed is True: solution_sys = aglmp.read_lmpdat(lmpcuts.input_lmpdat, lmpcuts.output_dcd) solution_sys_atoms_idxs = list(range(len(solution_sys.atoms))) aggregate_ok = solution_sys.check_aggregate(frame_id=-1, excluded_atm_idxs=solution_sys_atoms_idxs[solvate_sys_natoms:]) else: normally_dstributed = False aggregate_ok = False aggregate_ok = comm.bcast(aggregate_ok, root=0) normally_dstributed = comm.bcast(normally_dstributed, root=0) #if aggregate_ok is True and normally_dstributed is True: # sl.copy(lmpcuts.inter_lmprst, lmpcuts.output_lmprst) # if everything worked, name intermediate restart file as final output file if aggregate_ok is True and normally_dstributed is True: sl.copy(lmpcuts.inter_lmprst, lmpcuts.output_lmprst) return aggregate_ok and normally_dstributed
) args = parser.parse_args() # Modeling --------------------------------------------------------------------- sys_all = [] for idx, lmpdat in enumerate(args.lmpdats): try: curdcd = args.dcds[idx] except (TypeError, IndexError): # args.dcds is None or list is too short curdcd = None cursys = ag_lammps.read_lmpdat(lmpdat, dcd=curdcd, frame_idx_start=-1, frame_idx_stop=-1) # resetting the pair types cursys.pair_types = [] cursys.fetch_molecules_by_bonds() cursys.mols_to_grps() sys_all.append(cursys) # show all cell vectors of each loaded system in lattice form if args.show_lattice_cells is True: cursys.ts_boxes[-1].box_lmp2lat() print("System {}".format(idx)) print(cursys.ts_boxes[-1].ltc_a) print(cursys.ts_boxes[-1].ltc_b)