Exemplo n.º 1
0
def create_csv(path: Union[str, PathLike], database: Union[Ligand, QD] = 'ligand') -> str:
    """Create a ligand or qd database (csv format) if it does not yet exist.

    Parameters
    ----------
    path : str
        The path (without filename) of the database.

    database : |str|_
        The type of database, accepted values are ``"ligand"`` and ``"qd"``.

    Returns
    -------
    |str|_
        The absolute path to the ligand or qd database.

    """
    filename = join(path, f'{database}_database.csv')

    # Check if the database exists and has the proper keys; create it if it does not
    if not isfile(filename):
        if database == 'ligand':
            _create_csv_lig(filename)
        elif database == 'qd':
            _create_csv_qd(filename)
        else:
            raise ValueError(f"{database!r} is not an accepated value for the 'database' argument")
        logger.info(f'{database}_database.csv not found in {path}, creating {database} database')
    return filename
Exemplo n.º 2
0
def _crs_run(job: CRSJob,
             name: str,
             calc_type: str = 'activity coefficient') -> CRSResults:
    """Call the :meth:`CRSJob.run` on **job**, returning a :class:`CRSResults` instance."""
    _name = _get_name(job.name)
    logger.info(f'{job.__class__.__name__}: {name} {calc_type} calculation '
                f'({_name}) has started')
    return job.run(jobrunner=JobRunner(parallel=True))
Exemplo n.º 3
0
def _update_index_dset(group: h5py.Group, name: str, logger: Optional[Logger] = None) -> None:
    """Check for and update pre dataCAT 0.4 style databases."""
    if 'index' in group:
        return None
    elif logger is not None:
        logger.info(f'Updating h5py Dataset to data-CAT >= 0.4 style: {name!r}')

    dtype = IDX_DTYPE[name]
    i = len(group['atoms'])
    _set_index(PDBContainer, group, dtype, i, compression='gzip')
Exemplo n.º 4
0
def get_pka(mol: Molecule, coskf_mol: Optional[str],
            coskf_mol_conj: Optional[str], water: str, hydronium: str,
            job: Type[Job], s: Settings) -> List[float]:
    if coskf_mol is None:
        return 5 * [np.nan]
    elif coskf_mol_conj is None:
        return 5 * [np.nan]

    s = Settings(s)
    s.input.compound[1]._h = water
    s.ignore_molecule = True

    s_dict = {}
    for name, coskf in _iter_coskf(coskf_mol_conj, coskf_mol, water,
                                   hydronium):
        _s = s.copy()
        _s.name = name
        _s.input.compound[0]._h = coskf
        s_dict[name] = _s

    # Run the job
    mol_name = mol.properties.name
    job_list = [CRSJob(settings=s, name=name) for name, s in s_dict.items()]
    results_list = [_crs_run(job, mol_name) for job in job_list]

    # Extract solvation energies and activity coefficients
    E_solv = {}
    for name, results in zip(("acid", "base", "solvent", "solvent_conj"),
                             results_list):
        results.wait()
        try:
            E_solv[name] = _E = results.get_energy()
            assert _E is not None
            logger.info(f'{results.job.__class__.__name__}: {mol_name} pKa '
                        f'calculation ({results.job.name}) is successful')
        except Exception:
            logger.error(f'{results.job.__class__.__name__}: {mol_name} pKa '
                         f'calculation ({results.job.name}) has failed')
            E_solv[name] = np.nan

    try:
        mol.properties.job_path += [
            join(job.path, job.name + '.in') for job in job_list
        ]
    except IndexError:  # The 'job_path' key is not available
        mol.properties.job_path = [
            join(job.path, job.name + '.in') for job in job_list
        ]

    ret = [E_solv[k] for k in ("acid", "base", "solvent", "solvent_conj")]
    ret.append(_get_pka(**E_solv))
    return ret
Exemplo n.º 5
0
def _get_logp(s: Settings, name: str, logger: logging.Logger) -> float:
    logp_s = s.copy()
    logp_s.update(get_template('qd.yaml')['COSMO-RS logp'])
    for v in logp_s.input.compound:
        v._h = v._h.format(os.environ["ADFRESOURCES"])

    logp_job = CRSJob(settings=logp_s, name='LogP')
    results = _crs_run(logp_job, name)
    try:
        logp = results.readkf('LOGP', 'logp')[0]
        logger.info(f'{results.job.__class__.__name__}: {name} LogP '
                    f'calculation ({results.job.name}) is successful')
    except Exception:
        logger.error(f'{results.job.__class__.__name__}: {name} LogP '
                     f'calculation ({results.job.name}) has failed')
        logp = np.nan
    return logp
Exemplo n.º 6
0
def _update_pdb_dsets(file: h5py.File, name: str,
                      logger: Optional[Logger] = None) -> Optional[PDBContainer]:
    """Check for and update pre dataCAT 0.3 style databases."""
    if not isinstance(file.get(name), h5py.Dataset):
        return None
    elif logger is not None:
        logger.info(f'Updating h5py Dataset to data-CAT >= 0.3 style: {name!r}')

    mol_list = [from_pdb_array(pdb, rdmol=False, warn=False) for pdb in file[name]]
    m = len(mol_list)
    del file[name]

    dtype = IDX_DTYPE[name]
    scale = np.rec.array(None, dtype=dtype, shape=(m,))
    if dtype.fields is not None and scale.size:
        # Ensure that the sentinal value for vlen strings is an empty string, not `None`
        elem = list(scale.item(0))
        iterator = (v for v, *_ in dtype.fields.values())
        for i, sub_dt in enumerate(iterator):
            if h5py.check_string_dtype(sub_dt) is not None:
                elem[i] = ''
        scale[:] = tuple(elem)
    return PDBContainer.from_molecules(mol_list, scale=scale)
Exemplo n.º 7
0
def get_solv(mol: Molecule, solvent_list: Iterable[str], coskf: Optional[str],
             job: Type[Job], s: Settings) -> List[float]:
    """Calculate the solvation energy of *mol* in various *solvents*.

    Parameters
    ----------
    mol : |plams.Molecule|_
        A PLAMS Molecule.

    solvent_list : |List|_ [|str|_]
        A list of solvent molecules (*i.e.* .coskf files).

    coskf : str, optional
        The path+filename of the .coskf file of **mol**.

    job : |Callable|_
        A type Callable of a class derived from :class:`Job`, e.g. :class:`AMSJob`
        or :class:`Cp2kJob`.

    s : |plams.Settings|_
        The settings for **job**.

    Returns
    -------
    |list|_ [|float|_] & |list|_ [|float|_]
        A list of solvation energies and gammas.

    """
    # Return 3x np.nan if no coskf is None (i.e. the COSMO-surface construction failed)
    if coskf is None:
        i = 1 + 2 * len(solvent_list)
        return i * [np.nan]

    # Prepare a list of job settings
    s = Settings(s)
    s.input.compound[0]._h = coskf
    s.ignore_molecule = True
    s_list = []
    for solv in solvent_list:
        _s = s.copy()
        _s.name = solv.rsplit('.', 1)[0].rsplit(os.sep, 1)[-1]
        _s.input.compound[1]._h = solv
        s_list.append(_s)

    # Run the job
    mol_name = mol.properties.name
    job_list = [CRSJob(settings=s, name=s.name) for s in s_list]
    results_list = [
        _crs_run(job, mol_name, calc_type="pKa") for job in job_list
    ]

    # Extract solvation energies and activity coefficients
    E_solv = []
    Gamma = []
    for results in results_list:
        results.wait()
        try:
            E_solv.append(results.get_energy())
            Gamma.append(results.get_activity_coefficient())
            logger.info(
                f'{results.job.__class__.__name__}: {mol_name} activity coefficient '
                f'calculation ({results.job.name}) is successful')
        except Exception:
            logger.error(
                f'{results.job.__class__.__name__}: {mol_name} activity coefficient '
                f'calculation ({results.job.name}) has failed')
            E_solv.append(np.nan)
            Gamma.append(np.nan)

    try:
        mol.properties.job_path += [
            join(job.path, job.name + '.in') for job in job_list
        ]
    except IndexError:  # The 'job_path' key is not available
        mol.properties.job_path = [
            join(job.path, job.name + '.in') for job in job_list
        ]

    logp = _get_logp(s_list[0], name=mol_name, logger=logger)
    return E_solv + Gamma + [logp]
Exemplo n.º 8
0
def run_match_job(mol: Molecule,
                  s: Settings,
                  job_type: Type[Job] = MatchJob,
                  action: str = 'warn') -> None:
    """Assign atom types and charges to **mol** based on the results of MATCH_.

    Performs an inplace update of :attr:`Atom.properties` ``["symbol"]``,
    :attr:`Atom.properties` ``["charge"]`` and :attr:`Molecule.properties` ``["prm"]``.

    .. _MATCH: http://brooks.chem.lsa.umich.edu/index.php?page=match&subdir=articles/resources/software

    Parameters
    ----------
    mol : |plams.Molecule|
        A PLAMS molecule.

    s : |plams.Settings|
        Job settings for the to-be constructed :class:`.MatchJob` instance.

    job_type : :class:`type` [|plams.Job|]
        The type of Job.

    action : :class:`str`
        The to-be undertaken action when the Job crashes.
        Accepted values are ``"raise"``, ``"warn"`` and ``"ignore"``.

    See Also
    --------
    :class:`.MatchJob`
        A :class:`Job` subclass for interfacing with MATCH_: Multipurpose Atom-Typer for CHARMM.

    """  # noqa
    job = job_type(molecule=mol, settings=s, name='ff_assignment')

    # Run the job
    try:
        results = job.run()
        if job.status != 'successful':
            raise _get_results_error(results)

        symbol_list = results.get_atom_types()
        charge_list = results.get_atom_charges()
        logger.info(
            f'{job.__class__.__name__}: {mol.properties.name} parameter assignment '
            f'({job.name}) is successful')
    except Exception as ex:
        if action == 'raise':
            raise ex
        elif 'action' == 'warm':
            logger.info(
                f'{job.__class__.__name__}: {mol.properties.name} parameter assignment '
                f'({job.name}) has failed')
            logger.debug(f'{ex.__class__.__name__}: {ex}', exc_info=True)
            return None

    # Update properties with new symbols, charges and the consntructed parameter (.prm) file
    mol.properties.prm = prm = results['$JN.prm']
    for at, symbol, charge in zip(mol, symbol_list, charge_list):
        at.properties.symbol = symbol
        at.properties.charge_float = charge

    post_proccess_prm(prm)
    return None