def run(job, runner=None, path=None, folder=None, **kwargs): """ Pickup a runner and initialize it. :params job: computation to run :type job: Promise Object :param runner: Type of runner to use :type runner: String """ plams.init(path=path, folder=folder) plams.config.log.stdout = 0 if runner is None: ret = call_default(job, kwargs.get('n_processes', 1)) else: raise "Don't know runner: {}".format(runner) plams.finish() return ret
def main(): """ Main interface that reads the file and retrieve all useful geoms etc. Then rewrite geometries in a usable formatter_class Prep all NBO computations Run ADF on each computation """ # Retrieve command line values args = get_input_arguments() input_file = args['input_file'] output_file = args['output_file'] # Init PLAMS, Setting up a plams.$PID directory in the working dir init() # Retrieve settings from input file settings = get_settings(args) geometries = IRC_coordinates_from_t21(input_file) natoms = number_of_atoms(input_file) # Prep a bunch of NBO computations NBO_jobs = [prepare_NBO_computation(geom, settings) for geom in geometries] # Run each job in parallel as managed by plams for job in NBO_jobs: job.run() # NBO_values is a list of list of charges NBO_values = [ extract_NBO_charges(job._filenames.get('out'), natoms) for job in NBO_jobs ] # Write NBO data print_NBO_charges_to_file(NBO_values, output_file) # Close plams session finish()
def init_plams(self): """Init PLAMS.""" plams.init() plams.config.log.stdout = -1 plams.config.erase_workdir = True
def restart_init(path: Union[str, 'os.PathLike[str]'], folder: Union[str, 'os.PathLike[str]'], hashing: str = 'input') -> None: """Wrapper around the plams.init_ function; used for importing one or more previous jobs. All pickled .dill files in **path**/**folder**/ will be loaded into the :class:`GenJobManager` instance initiated by :func:`init()<scm.plams.core.functions.init>`. .. _plams.init: https://www.scm.com/doc/plams/components/functions.html#scm.plams.core.functions.init Note ---- Previous jobs are stored in a more generator-esque manner in :attr:`GenJobManager.hashes` and :class:`Job` instances are thus created on demand rather than permanently storing them in memory. Paramaters ---------- path : str The path to the PLAMS workdir. folder : str The name of the PLAMS workdir. hashing : str Optional: The type of hashing used by the PLAMS :class:`JobManager`. Accepted values are: ``"input"``, ``"runscript"``, ``"input+runscript"`` and ``None``. """ # noqa # Create a job manager settings = Settings({'counter_len': 3, 'hashing': hashing, 'remove_empty_directories': True}) manager = GenJobManager(settings, path, folder, hashing) # Change the default job manager with open(os.devnull, 'w') as f_, redirect_stdout(f_): init() rmtree(config.default_jobmanager.workdir) config.default_jobmanager = manager config.log.file = 3 config.log.stdout = 0 workdir = manager.workdir if not isdir(workdir): # workdir does not exist, dont bother trying to load previous jobs os.mkdir(workdir) return None # Update the default job manager with previous Jobs for f in os.listdir(workdir): job_dir = join(workdir, f) if not isdir(job_dir): # Not a directory; move along continue hash_file = join(job_dir, f + '.hash') if isfile(hash_file): # Update JobManager.hashes manager.load_job(hash_file) # Grab the job name try: name, _num = f.rsplit('.', 1) num = int(_num) except ValueError: # Jobname is not appended with a number name = f num = 1 # Update JobManager.names try: manager.names[name] = max(manager.names[name], num) except KeyError: manager.names[name] = num return None
def run(self): """Run the calculation Raises: ValueError: [description] Returns: np.ndarray -- molecular orbital matrix """ wd = ''.join(self.atoms) + '_' + self.basis_name t21_name = wd + '.t21' plams_wd = './plams_workdir' t21_path = os.path.join(plams_wd, os.path.join(wd, t21_name)) if os.path.isfile(t21_name): print('Reusing previous calculation from ', t21_name) kf = plams.KFFile(t21_name) e = kf.read('Total Energy', 'Total energy') else: # init PLAMS plams.init() plams.config.log.stdout = -1 plams.config.erase_workdir = True # create the molecule mol = plams.Molecule() for at, xyz in zip(self.atoms, self.atom_coords): mol.add_atom(plams.Atom(symbol=at, coords=tuple(xyz))) # settings in PLAMS sett = plams.Settings() sett.input.basis.type = self.basis_name.upper() sett.input.basis.core = 'None' sett.input.symmetry = 'nosym' sett.input.XC.HartreeFock = '' # correct unit if self.units == 'angs': sett.input.units.length = 'Angstrom' elif self.units == 'bohr': sett.input.units.length = 'Bohr' # total energy sett.input.totalenergy = True # run the ADF job job = plams.ADFJob(molecule=mol, settings=sett, name=wd) job.run() # read the energy from the t21 file e = job.results.readkf('Total Energy', 'Total energy') # make a copy of the t21 file shutil.copyfile(t21_path, t21_name) shutil.rmtree(plams_wd) # print energy print('== SCF Energy : ', e) self.out_file = t21_name
# Default imports from qmflows import Settings, templates, run, molkit from qmflows.draw_workflow import draw_workflow from noodles import gather # User Defined imports from qmflows.packages.SCM import dftb from qmflows.packages.SCM import dftb as adf # This is for testing purposes from qmflows.components import Distance, PES, select_max from scm import plams # ========== ============= plams.init() config.log.stdout = -1000 # noqa hartree2kcal = 627.5095 # List of reactions, defined by name, reactants and products (as smiles strings) reactions = [ ["et01", "C=C", "[CH]#[N+][CH2-]", "C1C=NCC1"], ["et02", "C=C", "[CH]#[N+][NH-]", "C1C=NNC1"], ["et03", "C=C", "[CH]#[N+][O-]", "C1C=NOC1"], ["et04", "C=C", "[N]#[N+][CH2-]", "C1N=NCC1"], ["et05", "C=C", "[N]#[N+][NH-]", "C1N=NNC1"], ["et06", "C=C", "[N]#[N+][O-]", "C1N=NOC1"], ["et07", "C=C", "[CH2]=[NH+][CH2-]", "C1CNCC1"], ["et08", "C=C", "[CH2]=[NH+][NH-]", "C1CNNC1"], ["et09", "C=C", "[CH2]=[NH+][O-]", "C1CNOC1"], ["et10", "C=C", "[NH]=[NH+][NH-]", "C1NNNC1"], ["et11", "C=C", "[NH]=[NH+][O-]", "C1NNOC1"],
# mol_dirs = os.listdir(dataset_dir) # mol_names = [d + '_' + p.strip('.xyz') for d in mol_dirs for p in os.listdir(dataset_dir + '/' + d)] # mol_paths = [dataset_dir + '/' + d + '/' + p for d in mol_dirs for p in os.listdir(dataset_dir + '/' + d)] # print(f'Starting singlepoint DFT and DFTB vibration calculations for {len(mol_names)} molecules from the {dataset_name} dataset:') # print('Molecules:') # [print('\t'+i+1,n) for i,n in enumerate(mol_names)] # for n, p in zip(mol_names, mol_paths): # kf_DFT = jobs.DFTJob(p, job_name=f'{n}_DFT', geo_opt=True).run(init=False) # shutil.copy2(kf_DFT, f'{kf_dir}/{n}_DFT.t21') # kf_DFTB = jobs.DFTBJob(p, job_name=f'{n}_DFTB', geo_opt=True).run(init=False) # shutil.copy2(kf_DFTB, f'{kf_dir}/{n}_DFTB.rkf') plams.init(path=os.getcwd() + r'/RUNS', folder=time.strftime("[%H-%M](%d-%m-%Y)", time.localtime())) kf_dir = os.getcwd( ) + f'/RUNS/#KFFiles/{time.strftime("[%H-%M](%d-%m-%Y)", time.localtime())}' try: os.mkdir(kf_dir) except: pass dataset_name = 'second_set' dataset_dir = os.getcwd() + f'/structures/{dataset_name}' mol_dirs = os.listdir(dataset_dir) mol_names = [ d + '_' + p.strip('.xyz') for d in mol_dirs for p in os.listdir(dataset_dir + '/' + d) ] mol_paths = [
def get_lig_charge(ligand: Molecule, desired_charge: float, ligand_idx: Union[None, int, Iterable[int], slice] = None, invert_idx: bool = False, settings: Optional[Settings] = None, path: Union[None, str, PathLike] = None, folder: Union[None, str, PathLike] = None) -> pd.Series: """Calculate and rescale the **ligand** charges using MATCH_. The atomic charges in **ligand_idx** wil be altered such that the molecular charge of **ligand** is equal to **desired_charge**. .. _MATCH: http://brooks.chem.lsa.umich.edu/index.php?page=match&subdir=articles/resources/software Examples -------- .. code:: python >>> import pandas as pd >>> from scm.plams import Molecule >>> from CAT.recipes import get_lig_charge >>> ligand = Molecule(...) >>> desired_charge = 0.66 >>> ligand_idx = 0, 1, 2, 3, 4 >>> charge_series: pd.Series = get_lig_charge( ... ligand, desired_charge, ligand_idx ... ) >>> charge_series.sum() == desired_charge True Parameters ---------- ligand : :class:`~scm.plams.core.mol.molecule.Molecule` The input ligand. desired_charge : :class:`float` The desired molecular charge of the ligand. ligand_idx : :class:`int` or :class:`~collections.abc.Iterable` [:class:`int`], optional An integer or iterable of integers representing atomic indices. The charges of these atoms will be rescaled; all others will be frozen with respect to the MATCH output. Setting this value to ``None`` means that *all* atomic charges are considered variable. Indices should be 0-based. invert_idx : :class:`bool` If ``True`` invert **ligand_idx**, *i.e.* all atoms specified therein are now threated as constants and the rest as variables, rather than the other way around. settings : :class:`~scm.plams.core.settings.Settings`, optional The input settings for :class:`~nanoCAT.ff.match_job.MatchJob`. Will default to the ``"top_all36_cgenff_new"`` forcefield if not specified. path : :class:`str` or :class:`~os.PathLike`, optional The path to the PLAMS workdir as passed to :func:`~scm.plams.core.functions.init`. Will default to the current working directory if ``None``. folder : :class:`str` or :class:`~os.PathLike`, optional The name of the to-be created to the PLAMS working directory as passed to :func:`~scm.plams.core.functions.init`. Will default to ``"plams_workdir"`` if ``None``. Returns ------- :class:`pd.Series` [:class:`str`, :class:`float`] A Series with the atom types of **ligand** as keys and atomic charges as values. See Also -------- :class:`MatchJob` A :class:`~scm.plams.core.basejob.Job` subclass for interfacing with MATCH_: Multipurpose Atom-Typer for CHARMM. """ # noqa if settings is None: settings = Settings() settings.input.forcefield = 'top_all36_cgenff_new' # Run the MATCH Job init(path, folder) ligand = ligand.copy() run_match_job(ligand, settings, action='raise') finish() # Extract the charges and new atom types count = len(ligand) charge = np.fromiter((at.properties.charge_float for at in ligand), count=count, dtype=float) symbol = np.fromiter((at.properties.symbol for at in ligand), count=count, dtype='<U4') # Identify the atom subset idx = _parse_ligand_idx(ligand_idx) if invert_idx: idx = _invert_idx(idx, count) try: idx_len = len(idx) # type: ignore except TypeError: # idx is a slice object idx_len = len(charge[idx]) # Correct the charges and return charge[idx] -= (charge.sum() - desired_charge) / idx_len return pd.Series(charge, index=symbol, name='charge')