Пример #1
0
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
Пример #2
0
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()
Пример #3
0
 def init_plams(self):
     """Init PLAMS."""
     plams.init()
     plams.config.log.stdout = -1
     plams.config.erase_workdir = True
Пример #4
0
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
Пример #5
0
    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
Пример #6
0
# 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"],
Пример #7
0
# 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 = [
Пример #8
0
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')