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
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]