Example #1
0
def set_cp2k_param(settings: Settings, param_dict: dict) -> None:
    """Placeholder."""
    for block_name, block in param_dict.items():
        # Create a to-be formatted string with user-specified units
        unit = f'[{block.unit}]' + ' {}' if 'unit' in block else '{}'

        # Get the to-be update list of settings
        s = settings.get_nested(block['keys'])
        if not isinstance(s, list):
            _s = settings.get_nested(block['keys'][:-1])
            s = _s[block['keys'][-1]] = []

        for k, v in block.items():
            if k in ('keys', 'unit'):  # Skip
                continue

            value = unit.format(v)
            atom = 'atoms' if len(k.split()) > 1 else 'atom'
            atom_list = [i[atom] for i in s]

            try:  # Intersecting set
                idx = atom_list.index(k)
                s[idx].update({block_name: value})
            except ValueError:  # Disjoint set
                new_block = Settings({atom: k, block_name: value})
                s.append(new_block)
Example #2
0
    def recreate_settings(self) -> Settings:
        """Construct a |Settings| instance from ``"$JN.run"``."""
        runfile = self['$JN.run']

        # Ignore the first 2 lines
        with open(runfile, 'r') as f:
            for i in f:
                if 'MATCH.pl' in i:
                    args = next(f).split()
                    break
            else:
                raise FileError(
                    f"Failed to parse the content of ...{os.sep}{runfile!r}")

        # Delete the executable and pop the .pdb filename
        del args[0]
        pdb_file = args.pop(-1)

        s = Settings()
        for k, v in zip(args[0::2], args[1::2]):
            k = k[1:].lower()
            s.input[k] = v
        s.input.filename = pdb_file

        return s
Example #3
0
def get_surface_charge_adf(mol: Molecule, job: Type[Job],
                           s: Settings) -> Settings:
    """Perform a gas-phase ADF single point and return settings for a COSMO-ADF single point.

    The previous gas-phase calculation as moleculair fragment.

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

    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
    -------
    |plams.Settings|_
        A new Settings intance, constructed from **s**, suitable for DFT COSMO-RS calculations.

    """
    s.input.allpoints = ''
    results = mol.job_single_point(job, s, ret_results=True)
    coskf = get_coskf(results)

    for at in mol:
        at.properties.adf.fragment = 'gas'
    s.update(get_template('qd.yaml')['COSMO-ADF'])
    s.input.fragments.gas = coskf

    return s
Example #4
0
def update_adf_defaults(ams_settings: Settings) -> None:
    """Add the COSMO-RS compound defaults to *ams_settings*, returning a copy of the new settings.

    The engine block (*ams_settings.input.adf*) is soft updated
    with the following Settings:

    .. code::

        Engine ADF
            Basis
                Type TZP
                Core Small
            End
            XC
                GGA BP86
            End
            Relativity
                Level Scalar
            End
            BeckeGrid
                Quality Good
            End
        EndEngine

    """

    # Find the solvation key
    # solvation = ams_settings.input.adf.find_case('solvation')
    # solvation_block = ams_settings.input.adf[solvation]

    adf = ams_settings.input.find_case('adf')
    adf_block = ams_settings.input[adf]

    # Find all keys for within the adf block
    keys = ('basis', 'xc', 'relativity', 'BeckeGrid')
    basis, xc, relativity, BeckeGrid = [
        adf_block.find_case(item) for item in keys
    ]

    # Construct the default solvation block
    adf_defaults_block = Settings({
        basis: {
            'Type': 'TZP',
            'Core': 'Small'
        },
        xc: {
            'GGA': 'BP86'
        },
        relativity: {
            'Level': 'Scalar'
        },
        BeckeGrid: {
            'Quality': 'Good'
        }
    })
    # Copy ams_settings and perform a soft update
    ret = ams_settings.copy()
    ret.input.adf.soft_update(adf_defaults_block)
    return ret
Example #5
0
def get_template(template_name: str, from_cat_data: bool = True) -> Settings:
    """Grab a yaml template and return it as Settings object."""
    if from_cat_data:
        path = join('data/templates', template_name)
        xs = pkg.resource_string('CAT', path)
        return Settings(yaml.load(xs.decode(), Loader=yaml.FullLoader))
    with open(template_name, 'r') as file:
        return Settings(yaml.load(file, Loader=yaml.FullLoader))
Example #6
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
Example #7
0
    def copy(self, deep: bool = False) -> 'FrozenSettings':
        """Create a copy of this instance.

        The returned instance is a recursive copy, the **deep** parameter only affecting the
        function used for copying non-:class:`dict` values:
        :func:`copy.copy` if ``deep=False`` and  :func:`copy.deepcopy` if ``deep=True``.

        """
        copy_func = copy.deepcopy if deep else copy.copy
        ret = type(self)()
        for key, value in self.items():
            value_cp = copy_func(value)
            Settings.__setitem__(ret, key, value_cp)
        return ret
Example #8
0
def qd_opt(mol: Molecule,
           jobs: Tuple[Optional[Type[Job]], ...],
           settings: Tuple[Optional[Settings], ...],
           use_ff: bool = False) -> None:
    """Perform an optimization of the quantum dot.

    Performs an inplace update of **mol**.

    Parameters
    ----------
    mol : |plams.Molecule|_
        The to-be optimized molecule.

    job_recipe : |plams.Settings|_
        A Settings instance containing all jon settings.
        Expects 4 keys: ``"job1"``, ``"job2"``, ``"s1"``, ``"s2"``.

    forcefield : bool
        If ``True``, perform the job with CP2K with a user-specified forcefield.

    """
    # Prepare the job settings
    if use_ff:
        qd_opt_ff(mol, jobs, settings)
        return None

    # Expand arguments
    job1, job2 = jobs
    s1, s2 = settings

    # Extra options for AMSJob
    if job1 is AMSJob:
        s1 = Settings(s1)
        s1.input.ams.constraints.atom = mol.properties.indices
    if job2 is AMSJob:
        s2 = Settings(s2)
        s2.input.ams.constraints.atom = mol.properties.indices

    # Run the first job and fix broken angles
    mol.job_geometry_opt(job1, s1, name='QD_opt_part1')
    fix_carboxyl(mol)
    fix_h(mol)
    mol.round_coords()

    # Run the second job
    if job2 is not None:
        mol.job_geometry_opt(job2, s2, name='QD_opt_part2')
        mol.round_coords()
    return None
Example #9
0
def read_mol_folder(mol_dict: Settings) -> Optional[List[Molecule]]:
    """Read all files (.xyz, .pdb, .mol, .txt or further subfolders) within a folder."""
    try:
        mol_type = 'input_cores' if mol_dict.is_core else 'input_ligands'

        _file_list = os.listdir(mol_dict.mol)
        optional_dict = Settings(
            {k: v
             for k, v in mol_dict.items() if k not in ('mol', 'path')})
        file_list = [{i: optional_dict} for i in _file_list]

        validate_mol(file_list, mol_type, mol_dict.path)
        return read_mol(file_list)
    except Exception as ex:
        print_exception('read_mol_folder', mol_dict.name, ex)
Example #10
0
    def repr_Settings(self, obj: Settings, level: int) -> str:  # noqa: N802
        """Create a :class:`str` representation of a |plams.Settings| instance."""
        n = len(obj)
        if not obj:
            return f'{obj.__class__.__name__}()'
        elif level <= 0:
            return '\n...'

        pieces: List[str] = []
        indent = 4 * ' '
        newlevel = level - 1

        for k, v in islice(obj.items(), self.maxSettings):
            key = str(k)
            value = self.repr1(v, newlevel)
            pieces.append(f'\n{key}:')
            if type(obj) is type(value):
                pieces.append(f'{textwrap.indent(value, indent)}:')
            else:
                pieces.append(f'{textwrap.indent(value, indent)}')

        if n > self.maxSettings:
            pieces.append('\n...')

        ret = ''.join(pieces)
        if level == self.maxlevel:
            return f'{obj.__class__.__name__}(\n{textwrap.indent(ret[1:], indent)}\n)'
        return ret
Example #11
0
def set_header(s: Settings, *values: str) -> None:
    """Assign *value* to the ``["_h"]`` key in *s.input.compound*."""
    s.input.compound = []
    for item in values:
        s.input.compound.append(Settings({'_h': item}))
    s.input.compound[
        0].frac1 = 1.0  # The first item in *values should be the solvent
Example #12
0
    def _overlay_s_plams(self, lj: Iterable[Mapping],
                         sigma_dict: MutableMapping,
                         epsilon_dict: MutableMapping) -> None:
        """Extract PLAMS-style settings from **lj** and put them in **sigma_dict** and **epsilon_dict**."""  # noqa: E501
        for block in lj:
            with Settings.suppress_missing():
                atoms = tuple(block['atoms'].split())

                try:
                    unit_sigma, sigma = block['sigma'].split()
                except ValueError:
                    unit_sigma, sigma = '[angstrom]', block['sigma']
                except (TypeError, KeyError):
                    unit_sigma = sigma = None

                try:
                    unit_eps, epsilon = block['epsilon'].split()
                except ValueError:
                    unit_eps, epsilon = '[kcalmol]', block['sigma']
                except (TypeError, KeyError):
                    unit_eps = epsilon = None

            if sigma is not None:
                unit_sigma = unit_sigma[1:-1]
                unit_sigma = self.UNIT_MAPPING.get(unit_sigma, unit_sigma)
                sigma_dict[unit_sigma][atoms] = float(sigma)

            if epsilon is not None:
                unit_eps = unit_eps[1:-1]
                unit_eps = self.UNIT_MAPPING.get(unit_eps, unit_eps)
                epsilon_dict[unit_eps][atoms] = float(epsilon)
Example #13
0
def frequencies():
    s = Settings()
    s.input.ams.properties.NormalModes   = 'Yes'
    s.input.ams.Properties.PESPointCharacter     = 'No'
    s.input.ams.NormalModes.ReScanFreqRange      = '-1000 0'
    s.input.ams.PESPointCharacter.NegativeEigenvalueTolerance = -0.001
    return s
Example #14
0
def DFTB():
    s = Settings()
    s.input.ams.task            = 'GeometryOptimization'
    s.input.DFTB
    s.input.DFTB.Model          = "GFN1-xTB" 
    s.input.ams.System.Charge   = 0
    return s
Example #15
0
def get_surface_charge(mol: Molecule, job: Type[Job],
                       s: Settings) -> Optional[str]:
    """Construct the COSMO surface of the **mol**.

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

    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
    -------
    |plams.Settings|_
        Optional: The path+filename of a file containing COSMO surface charges.

    """
    s = Settings(s)
    # Special procedure for ADF jobs
    # Use the gas-phase electronic structure as a fragment for the COSMO single point
    if job is ADFJob:
        s = get_surface_charge_adf(mol, job, s)

    s.runscript.post = '$ADFBIN/cosmo2kf "mopac.cos" "mopac.coskf"'
    results = mol.job_single_point(job, s, ret_results=True)
    return get_coskf(results)
Example #16
0
def _md2opt(s: Settings) -> Settings:
    """Convert CP2K MD settings to CP2K geometry optimization settings."""
    s2 = s.copy()
    del s2.input.motion.md
    s2.input['global'].run_type = 'geometry_optimization'

    # Delete all user-specified parameters; rely on MATCH
    del s2.input.force_eval.mm.forcefield.charge
    del s2.input.force_eval.mm.forcefield.nonbonded
    return s2
Example #17
0
def read_mol_smiles(mol_dict: Settings) -> Optional[Molecule]:
    """Read a SMILES string."""
    try:
        mol = _from_smiles(mol_dict.mol)
        mol.properties.smiles = Chem.CanonSmiles(mol_dict.mol)

        if mol_dict.get('indices'):
            for i in mol_dict.indices:
                mol[i].properties.anchor = True

        canonicalize_mol(mol)
        if mol_dict.get('indices'):
            mol_dict.indices = tuple(i for i, at in enumerate(mol, 1)
                                     if at.properties.pop('anchor', False))

        if mol_dict.guess_bonds and not mol_dict.is_qd:
            mol.guess_bonds()
        return mol
    except Exception as ex:
        print_exception('read_mol_smiles', mol_dict.name, ex)
Example #18
0
    def get_recipe(self) -> Dict[Tuple[str], JobRecipe]:
        """Create a recipe for :meth:`WorkFlow.to_db`."""
        settings_names = [i[1:] for i in self.export_columns if i[0] == 'settings']
        uff_fallback = {
            'key': f'RDKit_{rdkit.__version__}', 'value': f'{UFF.__module__}.{UFF.__name__}'
        }

        ret: Dict[Tuple[str], JobRecipe] = Settings()
        for name, job, settings in zip(settings_names, self.jobs, self.settings):
            # job is None, *i.e.* it's an RDKit UFF optimziation
            if job is None:
                ret[name].update(uff_fallback)  # type: ignore
                continue

            settings = Settings(settings)
            if self.read_template:  # Update the settings using a QMFlows template
                template = qmflows.geometry['specific'][self.type_to_string(job)].copy()
                settings.soft_update(template)
            ret[name]['key'] = job
            ret[name]['value'] = settings
        return ret
Example #19
0
def read_mol_txt(mol_dict: Settings) -> Optional[List[Molecule]]:
    """Read a plain text file containing one or more SMILES strings."""
    try:
        row = 0 if 'row' not in mol_dict else mol_dict.row
        column = 0 if 'column' not in mol_dict else mol_dict.column
        mol_type = 'input_cores' if mol_dict.is_core else 'input_ligands'

        with open(mol_dict.mol, 'r') as f:
            iterator = itertools.islice(f, row, None)
            _file_list = [
                i.rstrip('\n').split()[column] for i in iterator if i
            ]
        optional_dict = Settings(
            {k: v
             for k, v in mol_dict.items() if k not in ('mol', 'path')})
        file_list = [{i: optional_dict} for i in _file_list]

        validate_mol(file_list, mol_type, mol_dict.path)
        return read_mol(file_list)
    except Exception as ex:
        print_exception('read_mol_txt', mol_dict.name, ex)
Example #20
0
def pre_process_settings(mol: Molecule, s: Settings, job_type: Type[Job],
                         template_name: str) -> Settings:
    """Update all :class:`Settings`, **s**, with those from a QMFlows template (see **job**)."""
    ret = Settings()
    type_key = type_to_string(job_type)
    ret.input = getattr(qmflows, template_name)['specific'][type_key].copy()
    ret.update(s)

    if job_type is AMSJob:
        mol.properties.pop('charge', None)
        # ret.input.ams.system.BondOrders._1 = adf_connectivity(mol)
        if 'uff' not in s.input:
            ret.input.ams.system.charge = int(
                sum(at.properties.get('charge', 0) for at in mol))

    elif job_type is ADFJob:
        mol.properties.pop('charge', None)
        if not ret.input.charge:
            ret.input.charge = int(
                sum(at.properties.get('charge', 0) for at in mol))
    return ret
Example #21
0
    def overlay_cp2k_settings(self,
                              cp2k_settings: MutableMapping,
                              psf: Optional[PSFContainer] = None) -> None:
        r"""Overlay **df** with all :math:`q`, :math:`\sigma` and :math:`\varepsilon` values from **cp2k_settings**."""  # noqa
        charge = cp2k_settings['input']['force_eval']['mm']['forcefield'][
            'charge']
        charge_dict = {
            block['atom']: float(block['charge'])
            for block in charge
        }

        if psf is not None:
            psf_charge_dict = dict(zip(psf.atom_type, psf.charge))
            for k, v in psf_charge_dict.items():
                if k not in charge_dict:
                    charge_dict[k] = v

        epsilon_s = Settings()  # type: ignore[var-annotated]
        sigma_s = Settings()  # type: ignore[var-annotated]

        # Check if the settings are qmflows-style generic settings
        lj = cp2k_settings.get('lennard-jones') or cp2k_settings.get(
            'lennard_jones')
        if lj is not None:
            self._overlay_s_qmflows(cp2k_settings, sigma_s, epsilon_s)
        else:
            lj = cp2k_settings['input']['force_eval']['mm']['forcefield'][
                'nonbonded']['lennard-jones']  # noqa
            self._overlay_s_plams(lj, sigma_s, epsilon_s)

        self.set_charge(charge_dict)
        for unit, dct in epsilon_s.items():
            self.set_epsilon_pairs(dct, unit=unit)
        for unit, dct in sigma_s.items():
            self.set_sigma_pairs(dct, unit=unit)
Example #22
0
    def overlay_cp2k_settings(self, cp2k_settings: Settings) -> None:
        """Extract forcefield information from PLAMS-style CP2K settings.

        Performs an inplace update of this instance.

        Examples
        --------
        Example input value for **cp2k_settings**.
        In the provided example the **cp2k_settings** are directly extracted from a CP2K .inp file.

        .. code:: python

            >>> import cp2kparser  # https://github.com/nlesc-nano/CP2K-Parser

            >>> filename = str(...)

            >>> cp2k_settings: dict = cp2kparser.read_input(filename)
            >>> print(cp2k_settings)
            {'force_eval': {'mm': {'forcefield': {'nonbonded': {'lennard-jones': [...]}}}}}


        Parameters
        ----------
        cp2k_settings : :class:`~collections.abc.Mapping`
            A Mapping with PLAMS-style CP2K settings.

        """
        if 'input' not in cp2k_settings:
            cp2k_settings = Settings({'input': cp2k_settings})

        # If cp2k_settings is a Settings instance enable the `suppress_missing` context manager
        # In this manner normal KeyErrors will be raised, just like with dict
        if isinstance(cp2k_settings, Settings):
            context_manager = cp2k_settings.suppress_missing
        else:
            context_manager = nullcontext

        with context_manager():
            for prm_map in self.CP2K_TO_PRM.values():
                name = prm_map['name']
                columns = list(prm_map['columns'])
                key_path = prm_map['key_path']
                key = prm_map['key']
                unit = prm_map['unit']
                default_unit = prm_map['default_unit']
                post_process = prm_map['post_process']

                self._overlay_cp2k_settings(cp2k_settings,
                                            name, columns, key_path, key, unit,
                                            default_unit, post_process)
Example #23
0
def extract_args(args: Optional[List[str]] = None) -> Settings:
    """Extract and return all arguments."""
    input_file = args.YAML[0]
    if exists(input_file):
        pass
    elif exists(join(getcwd(), input_file)):
        input_file = join(getcwd(), input_file)
    else:
        input_file2 = join(getcwd(), input_file)
        raise FileNotFoundError(
            f'No file found at {input_file} or {input_file2}')

    with open(input_file, 'r') as file:
        return Settings(yaml.load(file, Loader=yaml.FullLoader))
Example #24
0
def update_ff_jobs(s: Settings) -> None:
    """Update forcefield settings."""
    if NANO_CAT is not None:
        raise NANO_CAT

    ff = Settings()
    set_cp2k_param(ff, s.optional.forcefield)

    optimize = s.optional.qd.optimize
    if optimize and optimize.use_ff:
        if optimize.job1 and str(optimize.job1) == str(Cp2kJob):
            optimize.s1 = Settings() if optimize.s1 is None else optimize.s1
            optimize.s1 += get_template('qd.yaml')['CP2K_CHARM_opt']
            optimize.s1 += ff

        if optimize.job2 and str(optimize.job1) == str(Cp2kJob):
            optimize.s2 = Settings() if optimize.s2 is None else optimize.s2
            optimize.s2 += get_template('qd.yaml')['CP2K_CHARM_opt']
            optimize.s2 += ff

    dissociate = s.optional.qd.dissociate
    if dissociate and dissociate.use_ff:
        if dissociate.job1 and str(dissociate.job1) == str(Cp2kJob):
            dissociate.s1 = Settings(
            ) if dissociate.s1 is None else dissociate.s1
            dissociate.s1 += get_template('qd.yaml')['CP2K_CHARM_opt']
            dissociate.s1 += ff

    activation_strain = s.optional.qd.activation_strain
    if activation_strain and activation_strain.use_ff:
        if activation_strain.job1 and str(
                activation_strain.job1) == str(Cp2kJob):
            key = 'CP2K_CHARM_singlepoint' if not activation_strain.md else 'CP2K_CHARM_md'
            activation_strain.s1 = Settings(
            ) if activation_strain.s1 is None else activation_strain.s1  # noqa
            activation_strain.s1 += get_template('qd.yaml')[key]
            activation_strain.s1 += ff
Example #25
0
def run_cdft_job(mol: Molecule, job: Type[ADFJob], s: Settings) -> pd.Series:
    """Run a conceptual DFT job and extract & return all global descriptors."""
    results = mol.job_single_point(job,
                                   s.copy(),
                                   name='CDFT',
                                   ret_results=True,
                                   read_template=False)

    if results.job.status in {'crashed', 'failed'}:
        return _BACKUP

    ret = get_global_descriptors(results)
    ret.index = pd.MultiIndex.from_product([['cdft'], ret.index],
                                           names=['index', 'sub index'])
    return ret
Example #26
0
def DFT():
    s = Settings()  
    s.input.ams.task             = 'GeometryOptimization'
    s.input.adf.basis.type       = 'TZ2P'
    s.input.adf.basis.core       = 'None'
    s.input.adf.xc.hybrid        = 'B3LYP'
    s.input.adf.xc.Dispersion    = 'GRIMME3 BJDAMP'
    s.input.adf.Relativity.Level = 'None'
    s.input.adf.NumericalQuality = 'Good'
    s.input.adf.Symmetry         = 'NOSYM'
    s.input.ams.UseSymmetry      = 'No'
    s.input.adf.Unrestricted     = 'No'
    s.input.adf.SpinPolarization = 0
    s.input.ams.System.Charge    = 0
    return s
Example #27
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
Example #28
0
def start_crs_jobs(mol_list: Iterable[Molecule], jobs: Iterable[Type[Job]],
                   settings: Iterable[Settings],
                   **kwargs: Any) -> List[pd.Series]:
    # Parse the job type
    job, *_ = jobs
    if job is not ADFJob:
        raise NotImplementedError(f"job: {job.__class__.__name__} = {job!r}")

    # Parse and update the input settings
    _s, *_ = settings
    s = Settings(_s)
    s.input += cdft.specific.adf

    ret = []
    for mol in mol_list:
        ret.append(run_cdft_job(mol, job, s))
    return ret
Example #29
0
def _get_logp(solutes: _NDArray[np.object_]) -> _NDArray[np.float64]:
    """Perform a LogP calculation."""
    ret = np.full_like(solutes, np.nan, dtype=np.float64)
    mask = solutes != None
    count = np.count_nonzero(mask)
    if count == 0:
        return ret

    s = copy.deepcopy(LOGP_SETTINGS)
    for v in s.input.compound[:2]:
        v._h = v._h.format(os.environ["AMSRESOURCES"])
    s.input.compound += [Settings({"_h": f'"{sol}"', "_1": "compkffile"}) for sol in solutes[mask]]

    ret[mask] = _run_crs(
        s, count,
        logp=lambda r: r.readkf('LOGP', 'logp')[2:],
    )
    return ret
Example #30
0
def finalize_lj(mol: Molecule, s: List[Settings]) -> None:
    """Assign UFF Lennard-Jones parameters to all missing non-bonded core/ligand interactions.

    .. _LENNARD_JONES: https://manual.cp2k.org/trunk/CP2K_INPUT/FORCE_EVAL/MM/FORCEFIELD/NONBONDED/LENNARD-JONES.html

    Parameters
    ----------
    mol : |plams.Molecule|_
        A PLAMS molecule containing a core and ligand(s).

    s : |list|_ [|plams.Settings|_]
        A list of settings constructed from the
        CP2K FORCE_EVAL/MM/FORCEFIELD/NONBONDED/`LENNARD-JONES`_ block.
        The settings are expected to contain the ``"atoms"`` keys.

    """  # noqa
    # Create a set of all core atom types
    core_at, lig_at = _gather_core_lig_symbols(mol)

    # Create a set of all user-specified core/ligand LJ pairs
    if not s:
        s = []
    elif isinstance(s, dict):
        s = [s]
    atom_pairs = {frozenset(s.atoms.split()) for s in s}

    # Check if LJ parameters are present for all atom pairs.
    # If not, supplement them with UFF parameters.
    for at1, symbol1 in core_at.items():
        for at2, symbol2 in lig_at.items():
            at1_at2 = {at1, at2}
            if at1_at2 in atom_pairs:
                continue

            s.append(
                Settings({
                    'atoms':
                    f'{at1} {at2}',
                    'epsilon':
                    f'[kcalmol] {round(combine_epsilon(symbol1, symbol2), 4)}',
                    'sigma':
                    f'[angstrom] {round(combine_sigma(symbol1, symbol2), 4)}'
                }))