def test_trc_with_boxes_traj(self): c = Cnf(self.in_file_w_genbox_cnf_path) t_origin = self.class_name(traj_path=self.in_file_w_genbox_path, in_cnf=self.in_file_w_genbox_cnf_path) # CNF was the last frame: testing.assert_allclose(actual=t_origin._unitcell_lengths[-1], desired=c.GENBOX.length) # these should not be equal! as the box changes in NPT over time assert t_origin._unitcell_lengths[0][0] != c.GENBOX.length[0] assert t_origin._unitcell_lengths[0][1] != c.GENBOX.length[1] assert t_origin._unitcell_lengths[0][2] != c.GENBOX.length[2]
def to_cnf(self, frame_id: int = None, base_cnf: Cnf = None): from pygromos.files.blocks import coords if frame_id is None: frame_id = 0 content_str = ("THIS IS THE FRAME AT TIMESTEP: " + str(self.time[frame_id]) + " OF THE TRAJECTORY WITH TITLE: \n" + "\n".join(self.TITLE.content)) if base_cnf is None: new_Cnf = self.get_dummy_cnf(self.xyz) else: if type(base_cnf) is Cnf: new_Cnf = base_cnf else: new_Cnf = Cnf(base_cnf) new_Cnf.TITLE = TITLE(content_str) new_Cnf.POSITION = POSITION([ coords.atomP( resID=new_Cnf.POSITION.content[i].resID, resName=new_Cnf.POSITION.content[i].resName, atomType=new_Cnf.POSITION.content[i].atomType, atomID=i, xp=coord[0], yp=coord[1], zp=coord[2], ) for i, coord in enumerate(self.xyz[frame_id]) ]) if hasattr(new_Cnf, "GENBOX"): new_Cnf.GENBOX.length = list(self.unitcell_lengths[frame_id]) new_Cnf.GENBOX.angles = list(self.unitcell_angles[frame_id]) new_Cnf.GENBOX.euler = [0.0, 0.0, 0.0] new_Cnf.GENBOX.origin = [0.0, 0.0, 0.0] else: from pygromos.files.blocks.coord_blocks import GENBOX box_block = GENBOX(pbc=1, length=list(self.unitcell_lengths[frame_id]), angles=list(self.unitcell_angles[frame_id])) new_Cnf.add_block(block=box_block) if hasattr(new_Cnf, "TIMESTEP"): new_Cnf.TIMESTEP.t = self.time[frame_id] new_Cnf.TIMESTEP.step = self.step[frame_id] return new_Cnf
def get_dummy_cnf(self, xyz: np.array) -> Cnf: from pygromos.files.blocks import coords new_Cnf = Cnf(None) new_Cnf.add_block( blocktitle="TITLE", content="THis is a dummy top depending on the first Frame.") new_Cnf.add_block( blocktitle="POSITION", content=[ coords.atomP(resID=1, resName="DUM", atomType="C", atomID=i, xp=coord[0], yp=coord[1], zp=coord[2]) for i, coord in enumerate(xyz[0]) ], ) return new_Cnf
def create_cnf(self, mol: str, in_cnf: Cnf = None, **kwargs) -> Cnf: return Cnf(in_value=mol)
def ran_box( in_top_path: str, in_cnf_path: str, out_cnf_path: str = "", periodic_boundary_condition: str = "r", nmolecule: int = 1, dens: float = 1.0, threshold: float = None, layer: bool = False, boxsize: float = None, fixfirst: bool = False, seed: float = None, _binary_name: str = "ran_box", verbose: bool = True, return_command_only: bool = False, ) -> str: top = Top(in_value=in_top_path) cnf = Cnf(in_value=in_cnf_path) cog = np.array(cnf.center_of_geometry()) if sum([len(cnf.residues[x]) for x in cnf.residues]) > 1: raise Exception("ran_box works only with one residue in the .cnf file!\nFound: " + str(cnf.get_residues())) # get volume and box length minwall = 0.12 # saftey distance of a bond length to box edge mol_mass = top.get_mass() volume = 1.66056 * nmolecule * mol_mass / dens box_length = volume ** (1.0 / 3.0) divider = int(np.ceil(nmolecule ** (1.0 / 3.0))) distance = (box_length - 2 * minwall) / float(divider) # calculate maxRandShift scale = 0.5 # scale can be manually decreased maxDist = 0 for atom in copy.deepcopy(cnf).POSITION.content: pos = np.array([atom.xp, atom.yp, atom.zp]) dis = np.linalg.norm(pos - cog) if dis > maxDist: maxDist = dis maxRandShift = (scale * distance) - maxDist if maxRandShift < 0: maxRandShift = 0 if verbose: warnings.warn("Molecules might overlap! Check cnf manually or decrease the density") # create new cnf for return and set some attributes ret_cnf = copy.deepcopy(cnf) ret_cnf.POSITION.content = [] if hasattr(ret_cnf, "LATTICESHIFTS"): delattr(ret_cnf, "LATTICESHIFTS") if hasattr(ret_cnf, "VELOCITY"): delattr(ret_cnf, "VELOCITY") if hasattr(ret_cnf, "STOCHINT"): delattr(ret_cnf, "STOCHINT") ret_cnf.GENBOX.pbc = 1 ret_cnf.GENBOX.length = [box_length, box_length, box_length] ret_cnf.GENBOX.angles = [90, 90, 90] ret_cnf.TITLE.content = str(nmolecule) + " * " + cnf.POSITION.content[0].resName # add positions points = list(it.product(range(divider), range(divider), range(divider))) for ind, (xi, yi, zi) in enumerate(random.sample(points, nmolecule)): shift = np.array( [(xi + 0.5) * distance + minwall, (yi + 0.5) * distance + minwall, (zi + 0.5) * distance + minwall] ) cnf.rotate(alpha=random.uniform(0, 360), beta=random.uniform(0, 360), gamma=random.uniform(0, 360)) randomShift = np.array( [ random.uniform(-maxRandShift, maxRandShift), random.uniform(-maxRandShift, maxRandShift), random.uniform(-maxRandShift, maxRandShift), ] ) for atom in copy.deepcopy(cnf).POSITION.content: pos = np.array([atom.xp, atom.yp, atom.zp]) atom.xp, atom.yp, atom.zp = pos - cog + shift + randomShift atom.resID = ind + 1 atom.atomID += ind * cnf.POSITION.content[-1].atomID ret_cnf.POSITION.content.append(atom) ret_cnf.write(out_path=out_cnf_path) return out_cnf_path
def chain_submission( simSystem: Gromos_System, out_dir_path: str, out_prefix: str, chain_job_repetitions: int, worker_script: str, job_submission_system: _SubmissionSystem, jobname: str, run_analysis_script_every_x_runs: int = 0, in_analysis_script_path: str = "", start_run_index: int = 1, prefix_command: str = "", previous_job_ID: int = None, work_dir: str = None, initialize_first_run: bool = True, reinitialize_every_run: bool = False, verbose: bool = False, verbose_lvl: int = 1, ) -> Tuple[int, str, Gromos_System]: """ this function submits a chain of simulation steps to the queuing system and does the file managment. Parameters ---------- simSystem : Gromos_System simulation system out_dir_path : str out directory path out_prefix : str out prefix for simulation files chain_job_repetitions : int how often, should the simulation be repeated (in continuation) worker_script : str worker, that should be submitted. This script will be executed at each scheduled job. job_submission_system : _SubmissionSystem submission system, what type of submission? jobname : str name of the simulation job run_analysis_script_every_x_runs : int, optional run analysis in between - (careful will not be overwritten, make sure final analysis is correct.), by default 0 in_analysis_script_path : str, optional analysis script for simulation, that should be applied (will at least be applied after the full simulation chain.), by default "" start_run_index : int, optional start index of the job chain., by default 1 prefix_command : str, optional any bash prefix commands, before submitting?, by default "" previous_job_ID : int, optional ID of the prefious job, to be chained to. , by default None work_dir : str, optional dir to wich the work in progress will be written. if None a tmp-srcatch dir will be used with LSF!, by default None initialize_first_run : bool, optional should the velocities for the first run be initialized?, by default True reinitialize_every_run : bool, optional should in every run, the velocities be reinitialized?, by default False verbose : bool, optional more bla bla, by default False verbose_lvl : int, optional nicely define ammount of bla bla, by default 1 Returns ------- Tuple[int, str, Gromos_System] Tuple[previous_job_ID, tmp_jobname, simSystem] will return the last job_ID, the last tmp_jobname and the final gromosSystem. Raises ------ ValueError if submission fails. This can habe various reasons, always check also the present files! (*omd etc.) """ if verbose: print("\nChainSubmission - " + out_prefix + "\n" + "=" * 30 + "\n") if (verbose) and verbose_lvl >= 2: print("start_run_index " + str(start_run_index)) if (verbose) and verbose_lvl >= 2: print("job reptitions " + str(chain_job_repetitions)) if job_submission_system is not LOCAL: simSystem._future_promise = True ana_id = None job_submission_system.job_duration = job_submission_system.job_duration for runID in range(start_run_index, chain_job_repetitions + 1): if verbose: print("\n submit " + jobname + "_" + str(runID) + "\n" + spacer3) tmp_outprefix = out_prefix + "_" + str(runID) tmp_jobname = jobname + "_" + str(runID) tmp_outdir = out_dir_path + "/" + tmp_outprefix tmp_out_cnf = tmp_outdir + "/" + tmp_outprefix + ".cnf" # Checks if run should be skipped! do_skip, previous_job_ID = do_skip_job( tmp_out_cnf=tmp_out_cnf, simSystem=simSystem, tmp_jobname=tmp_jobname, job_submission_system=job_submission_system, previous_job=previous_job_ID, verbose=verbose, ) if not do_skip: bash.make_folder(tmp_outdir) # build COMMANDS: if len(prefix_command) > 1: prefix_command += " && " # We will write the arguments to the python script in a bash array # to make it simpler to read in our input files. md_args = "md_args=(\n" md_args += "-out_dir " + tmp_outdir + "\n" md_args += "-in_cnf_path " + simSystem.cnf.path + "\n" md_args += "-in_imd_path " + simSystem.imd.path + "\n" md_args += "-in_top_path " + simSystem.top.path + "\n" md_args += "-runID " + str(runID) + "\n" # OPTIONAL ARGS if simSystem.disres is not None: md_args += "-in_disres_path " + simSystem.disres.path + "\n" if simSystem.ptp is not None: md_args += "-in_perttopo_path " + simSystem.ptp.path + "\n" if simSystem.refpos is not None: md_args += "-in_refpos_path " + simSystem.refpos.path + "\n" if simSystem.qmmm is not None: md_args += "-in_qmmm_path " + simSystem.qmmm.path + " " if simSystem.posres is not None: md_args += "-in_posres_path " + simSystem.posres.path + "\n" md_args += "-nmpi " + str(job_submission_system.nmpi) + "\n" md_args += "-nomp " + str(job_submission_system.nomp) + "\n" md_args += "-initialize_first_run " + str( initialize_first_run) + "\n" md_args += "-reinitialize_every_run " + str( reinitialize_every_run) + "\n" md_args += "-gromosXX_bin_dir " + str( simSystem.gromosXX.bin) + "\n" md_args += "-gromosXX_check_binary_paths " + str( simSystem.gromosXX._check_binary_paths) + "\n" if work_dir is not None: md_args += "-work_dir " + str(work_dir) + "\n" if hasattr(simSystem.imd, "WRITETRAJ"): if simSystem.imd.WRITETRAJ.NTWX > 0: md_args += "-out_trc " + str(True) + "\n" if simSystem.imd.WRITETRAJ.NTWE > 0: md_args += "-out_tre " + str(True) + "\n" if simSystem.imd.WRITETRAJ.NTWV > 0: md_args += "-out_trv " + str(True) + "\n" if simSystem.imd.WRITETRAJ.NTWF > 0: md_args += "-out_trf " + str(True) + "\n" if simSystem.imd.WRITETRAJ.NTWG > 0: md_args += "-out_trg " + str(True) + "\n" md_args += "-zip_trajectories " + str( job_submission_system.zip_trajectories) + "\n" md_args += ")\n" # closing the bash array which stores all arguments. # add zip option here # MAIN commands md_script_command = prefix_command + "\n\n" + md_args + "\n" md_script_command += "python3 " + worker_script + ' "${md_args[@]}" \n' if verbose: print("PREVIOUS ID: ", previous_job_ID) if verbose_lvl >= 2: print("COMMAND: ", md_script_command) # SCHEDULE THE COMMANDS try: if verbose: print("\tSIMULATION") os.chdir(tmp_outdir) sub_job = Submission_job( command=md_script_command, jobName=tmp_jobname, submit_from_dir=tmp_outdir, queue_after_jobID=previous_job_ID, outLog=tmp_outdir + "/" + out_prefix + "_md.out", errLog=tmp_outdir + "/" + out_prefix + "_md.err", sumbit_from_file=True, ) previous_job_ID = job_submission_system.submit_to_queue( sub_job) if verbose: print("SIMULATION ID: ", previous_job_ID) except ValueError as err: # job already in the queue raise ValueError("ERROR during submission of main job " + str(tmp_jobname) + ":\n" + "\n".join(err.args)) # OPTIONAL schedule - analysis inbetween. if (runID > 1 and run_analysis_script_every_x_runs != 0 and runID % run_analysis_script_every_x_runs == 0 and runID < chain_job_repetitions): if (verbose) and verbose_lvl >= 2: print("\tINBETWEEN ANALYSIS") sub_job = Submission_job( command=in_analysis_script_path, jobName=jobname + "_intermediate_ana_run_" + str(runID), outLog=tmp_outdir + "/" + out_prefix + "_inbetweenAna.out", errLog=tmp_outdir + "/" + out_prefix + "_inbetweenAna.err", queue_after_jobID=previous_job_ID, ) try: ana_id = job_submission_system.submit_to_queue(sub_job) if (verbose) and verbose_lvl >= 2: print("\n") except ValueError as err: # job already in the queue print("ERROR during submission of analysis command of " + sub_job.jobName + ":\n") print("\n".join(err.args)) else: if (verbose) and verbose_lvl >= 2: print("Did not submit!") if (verbose) and verbose_lvl >= 2: print("\n") if (verbose) and verbose_lvl >= 2: print("job_postprocess ") prefix_command = "" # Resulting cnf is provided to use it in further approaches. simSystem.cnf = Cnf(tmp_out_cnf, _future_file=True) if ana_id is not None: previous_job_ID = ana_id return previous_job_ID, tmp_jobname, simSystem
def __init__( self, xyz=None, topology=None, time=None, unitcell_lengths=None, unitcell_angles=None, traj_path=None, in_cnf: [str, Cnf] = None, timestep_duration: float = 0.002, _future_file: bool = False, ): self._future_file = _future_file if xyz is None and topology is None and traj_path is None and in_cnf is None: self._future_file = None if traj_path is not None and (traj_path.endswith(".h5") or traj_path.endswith(".hf5")): trj = self.load(traj_path) self.__dict__.update(vars(trj)) elif traj_path is not None and (traj_path.endswith(".trc") or traj_path.endswith(".trc.gz")): # Parse TRC compress = False if traj_path.endswith(".gz"): traj_path = bash.compress_gzip(in_path=traj_path, extract=True) compress = True unitcell_angles = None unitcell_lengths = None if isinstance(traj_path, str): xyz, step, time, unitcell_lengths, unitcell_angles = self.parse_trc_efficiently( traj_path) if compress: traj_path = bash.compress_gzip(in_path=traj_path) # Topology from Cnf if isinstance(in_cnf, str): in_cnf = Cnf(in_cnf) elif isinstance(in_cnf, Cnf) and hasattr(in_cnf, "POSITION"): pass else: in_cnf = self.get_dummy_cnf(xyz) # get cnf boxDims if hasattr(in_cnf, "GENBOX") and (unitcell_lengths is None and unitcell_angles is None): unitcell_angles = np.array( list(in_cnf.GENBOX.angles) * len(xyz)).reshape( len(xyz), len(in_cnf.GENBOX.length)) unitcell_lengths = np.array( list(in_cnf.GENBOX.length) * len(xyz)).reshape( len(xyz), len(in_cnf.GENBOX.length)) # Topo tmp file tmpFile = tempfile.NamedTemporaryFile(suffix="_tmp.pdb") in_cnf.write_pdb(tmpFile.name) single = mdtraj.load_pdb(tmpFile.name) tmpFile.close() super().__init__( xyz=xyz, topology=single.topology, time=time, unitcell_lengths=unitcell_lengths, unitcell_angles=unitcell_angles, ) self._step = step elif not (xyz is None and topology is None): super().__init__( xyz=xyz, topology=topology, time=time, unitcell_lengths=unitcell_lengths, unitcell_angles=unitcell_angles, ) self._step = np.array(np.round(self._time / timestep_duration), dtype=int) self.TITLE = TITLE( content=" Generic Title... to be changed by YOU!") else: self._unitcell_lengths = [] self._unitcell_angles = [] self._xyz = np.array([], ndmin=2) self._topology = None self._future_file = True self.path = traj_path
def TI_sampling( in_gromos_system: Gromos_System, project_dir: str = None, step_name="lambda_sampling", lambda_values: List[float] = np.arange(0, 1.1, 0.1), subSystem: _SubmissionSystem = LOCAL(), n_productions: int = 3, n_equilibrations: int = 1, randomize: bool = False, dual_cnf: List[str] = None, verbose: bool = True, ): """ This function will automatically submit N independent (different lambda) MD simulations with a lambda dependent potential energy. Parameters ---------- in_gromos_system: Gromos_System input gromos system project_dir: str directory in which simulation input files are found step_name: str subdirectory of project_dir, in which we will write the output important: allows to run multiple random seeds with a different "step_name" lambda_values: List [float] List of lambda values for each independent simulation subSystem: _SubmissionSystem where will the calculation run n_productions: int number of chunks each independent simulation is broken down into n_equilibrations: int number of chunks of equilibration preceding the production for each independent simulation randomize: bool Choose a random number for the initial random seed (same for all lambda values) dual_cnf: List [str], optional If provided, should be the path to two conformations (matching end states A and B) which can be used as initial conformations Simulations with a lambda value between 0 and 0.5 will use the first as starting conformation Returns -------- lam_system: Gromos_System Gromos system of the simulation submitted last """ if project_dir is None: project_dir = in_gromos_system.work_folder work_dir = bash.make_folder(project_dir + "/" + step_name) # Select a random seed here so all lambda windows have the same if randomize: in_gromos_system.imd.randomize_seed() in_gromos_system.save(work_dir) general_system_name_prefix = in_gromos_system.name lam_systems = [] for lam in lambda_values: lam = np.round(lam, 4) lam_system = deepcopy(in_gromos_system) lam_system.name = general_system_name_prefix + "_l_" + str(lam) lam_system.work_folder = work_dir # Choose different conformations depending on lambda point. # e.g. this allows to use RE-EDS SSM conformations. # dual_cnf[i] contains the path of the cnf to use if dual_cnf is not None and lam <= 0.5: lam_system.cnf = Cnf(dual_cnf[0]) elif dual_cnf is not None: lam_system.cnf = Cnf(dual_cnf[1]) # IMD # Pertubation # Pertubation of system. pert_block = PERTURBATION(NTG=1, NRDGL=0, RLAM=lam, DLAMT=0, ALPHC=0.5, ALPHLJ=0.5, NLAM=2, NSCALE=0) lam_system.imd.add_block(block=pert_block) # Calculate additional lambda points if not hasattr(lam_system, "PRECALCLAM"): # Note: This assumes uniformely distributed lambda values precalc_lam_block = PRECALCLAM(NRLAM=len(lambda_values), MINLAM=0, MAXLAM=1) lam_system.imd.add_block(block=precalc_lam_block) # Submit out_gromos_system = _TI_lam_step( in_gromos_system=lam_system, project_dir=work_dir, step_name=lam_system.name, submission_system=subSystem, in_imd_path=None, simulation_runs=n_productions, equilibration_runs=n_equilibrations, verbose=verbose, ) out_gromos_system.save(out_gromos_system.work_folder + "/sd_out_system.obj") lam_systems.append(out_gromos_system) return lam_system
class test_trc(unittest.TestCase): class_name = trc.Trc help_class = Cnf(in_test_file_path + "/trc/in_test.cnf") in_file_path = in_test_file_path + "/trc/in_test.trc" in_file_path_h5 = in_test_file_path + "/trc/in_test_trc.h5" in_file_w_genbox_path = in_test_file_path + "/trc/in_test_genbox.trc" in_file_w_genbox_cnf_path = in_test_file_path + "/trc/in_test_genbox.cnf" outpath = root_out + "/out_trc1.h5" trc_outpath = root_out + "/out_.trc.gz" # Constructors def test_constructor_empty(self): t = self.class_name() assert isinstance(t, self.class_name) # print(t) def test_constructor_trc_file_path(self): t = self.class_name(traj_path=self.in_file_path, in_cnf=self.help_class) assert isinstance(t, self.class_name) # print(t) def test_constructor_trc_file_noTop_path(self): t = self.class_name(traj_path=self.in_file_path) assert isinstance(t, self.class_name) # print(t) def test_constructor_trc_h5_file_path(self): t = self.class_name(traj_path=self.in_file_path_h5) assert isinstance(t, self.class_name) # print(t) def test_write(self): t = self.class_name(traj_path=self.in_file_path, in_cnf=self.help_class) t.save(self.outpath) def test_trc_with_boxes_traj(self): c = Cnf(self.in_file_w_genbox_cnf_path) t_origin = self.class_name(traj_path=self.in_file_w_genbox_path, in_cnf=self.in_file_w_genbox_cnf_path) # CNF was the last frame: testing.assert_allclose(actual=t_origin._unitcell_lengths[-1], desired=c.GENBOX.length) # these should not be equal! as the box changes in NPT over time assert t_origin._unitcell_lengths[0][0] != c.GENBOX.length[0] assert t_origin._unitcell_lengths[0][1] != c.GENBOX.length[1] assert t_origin._unitcell_lengths[0][2] != c.GENBOX.length[2] def test_to_trc_file(self): # Read in trc t_origin = self.class_name(traj_path=self.in_file_path, in_cnf=self.help_class) # take a subset of frames t = t_origin[[5, 7, 12]] # write trc t.write_trc(self.trc_outpath) # read in new trc t_new = self.class_name(traj_path=self.trc_outpath, in_cnf=self.help_class) # test if new trc coordinates have correct shapes assert t_new.xyz.shape[0] == 3 assert t_new.xyz.shape[1] == t_origin.xyz.shape[1] assert t_new.xyz.shape[2] == t_origin.xyz.shape[2] def test_to_conf(self): t = self.class_name(traj_path=self.in_file_path, in_cnf=self.help_class) # TEST DUMMY conf_60 = t.to_cnf(60) conf_60_None = t[60].to_cnf() assert conf_60 == conf_60_None # TEST with base conf_60 = t.to_cnf(60, base_cnf=self.help_class) conf_60_None = t[60].to_cnf(base_cnf=self.help_class) assert conf_60 == conf_60_None