diff --git a/CAT/__init__.py b/CAT/__init__.py index 52ff3720..348b9f54 100644 --- a/CAT/__init__.py +++ b/CAT/__init__.py @@ -17,7 +17,7 @@ from .data_handling import ( Database, mol_to_file, - read_mol, set_prop, + read_mol, set_mol_prop, sanitize_optional, sanitize_input_mol, sanitize_path ) @@ -32,7 +32,7 @@ 'init_qd_opt', 'init_ligand_opt', 'init_qd_construction', 'init_ligand_anchoring', 'Database', 'mol_to_file', - 'read_mol', 'set_prop', + 'read_mol', 'set_mol_prop', 'sanitize_optional', 'sanitize_input_mol', 'sanitize_path', 'prep', diff --git a/CAT/__version__.py b/CAT/__version__.py index f0ede3d3..a9873473 100644 --- a/CAT/__version__.py +++ b/CAT/__version__.py @@ -1 +1 @@ -__version__ = '0.4.1' +__version__ = '0.4.2' diff --git a/CAT/analysis/ligand_bde.py b/CAT/analysis/ligand_bde.py index c935d8d1..5c41b533 100644 --- a/CAT/analysis/ligand_bde.py +++ b/CAT/analysis/ligand_bde.py @@ -564,12 +564,10 @@ def get_lig_core_combinations(xy, res_list, lig_count=2): :parameter int lig_count: The number of ligand (*n*) in XYn. :return: """ - ret = {} + dict_ = {} for core, lig in xy.T: try: - ret[res_list[0][core].id].append([at.id for at in res_list[lig]]) + dict_[res_list[0][core].id].append([at.id for at in res_list[lig]]) except KeyError: - ret[res_list[0][core].id] = [[at.id for at in res_list[lig]]] - for i in ret: - ret[i] = combinations(ret[i], lig_count) - return ret + dict_[res_list[0][core].id] = [[at.id for at in res_list[lig]]] + return {k: combinations(v, lig_count) for k, v in dict_.items()} diff --git a/CAT/attachment/ligand_attach.py b/CAT/attachment/ligand_attach.py index f4a78401..0a0ff44d 100644 --- a/CAT/attachment/ligand_attach.py +++ b/CAT/attachment/ligand_attach.py @@ -96,10 +96,10 @@ def _get_indices(mol, index): break except ValueError: pass - k += i + k += i - 1 # Append and return - ref_name = mol[k].properties.pdb_info.Name + ref_name = mol[k+1].properties.pdb_info.Name for i, at in enumerate(mol.atoms[k:], k+1): if at.properties.pdb_info.Name == ref_name: at.properties.anchor = True diff --git a/CAT/attachment/ligand_opt.py b/CAT/attachment/ligand_opt.py index ffe6921e..c8dfb322 100644 --- a/CAT/attachment/ligand_opt.py +++ b/CAT/attachment/ligand_opt.py @@ -67,9 +67,33 @@ def init_ligand_opt(ligand_df, arg): # Print messages print(get_time() + ligand.properties.name + message) if lig_new: - ligand_df.loc[idx, 'mol'] = lig_new + if len(lig_new) == 1: # pd.DataFrame.loc has serious issues when assigning 1 molecue + idx, _ = next(ligand_df[idx].iterrows()) + ligand_df.at[idx, ('mol', '')] = lig_new[0] + else: + ligand_df.loc[idx, 'mol'] = lig_new print('') + remove_duplicates(ligand_df) + + # Write newly optimized structures to the database + if 'ligand' in arg.optional.database.write and arg.optional.ligand.optimize: + recipe = Settings() + recipe['1'] = {'key': 'RDKit_' + rdkit.__version__, 'value': 'UFF'} + columns = [('formula', ''), ('hdf5 index', ''), ('settings', '1')] + database.update_csv( + ligand_df, columns=columns, job_recipe=recipe, database='ligand', overwrite=overwrite + ) + path = arg.optional.ligand.dirname + mol_to_file(ligand_df['mol'], path, overwrite, arg.optional.database.mol_format) + + +def remove_duplicates(ligand_df): + """Remove duplicate rows from a dataframe. + + Duplicates are identified based on their index. + Performs an inplace update of **ligand_df**. + """ # Remove duplicate ligands and sort if ligand_df.index.duplicated().any(): idx_name = ligand_df.index.names @@ -80,16 +104,6 @@ def init_ligand_opt(ligand_df, arg): ligand_df.index.names = idx_name ligand_df.sort_index(inplace=True) - # Write newly optimized structures to the database - if 'ligand' in arg.optional.database.write and arg.optional.ligand.optimize: - recipe = Settings() - recipe['1'] = {'key': 'RDKit_' + rdkit.__version__, 'value': 'UFF'} - columns = [('formula', ''), ('hdf5 index', ''), ('settings', '1')] - database.update_csv(ligand_df, columns=columns, - job_recipe=recipe, database='ligand', overwrite=overwrite) - path = arg.optional.ligand.dirname - mol_to_file(ligand_df['mol'], path, overwrite, arg.optional.database.mol_format) - @add_to_class(Molecule) def split_bond(self, bond, atom_type='H', bond_length=1.1): diff --git a/CAT/data_handling/CAT_database.py b/CAT/data_handling/CAT_database.py index a6f86992..c314e134 100644 --- a/CAT/data_handling/CAT_database.py +++ b/CAT/data_handling/CAT_database.py @@ -254,6 +254,36 @@ def _create_yaml(path, name='job_settings.yaml'): return path +def even_index(df1: pd.DataFrame, + df2: pd.DataFrame) -> pd.DataFrame: + """Ensure that ``df2.index`` is a subset of ``df1.index``. + + Parameters + ---------- + df1 : |pd.DataFrame|_ + A DataFrame whose index is to-be a superset of ``df2.index``. + + df2 : |pd.DataFrame|_ + A DataFrame whose index is to-be a subset of ``df1.index``. + + Returns + ------- + |pd.DataFrame|_ + A new + + """ + # Figure out if ``df1.index`` is a subset of ``df2.index`` + bool_ar = df2.index.isin(df1.index) + if bool_ar.all(): + return df1 + + # Make ``df1.index`` a subset of ``df2.index`` + nan_row = get_nan_row(df1) + idx = df2.index[~bool_ar] + df_tmp = pd.DataFrame(len(idx) * [nan_row], index=idx, columns=df1.columns) + return df1.append(df_tmp, sort=True) + + class Database(): """ The Database class. @@ -298,6 +328,7 @@ class open_yaml(): :param bool write: Whether or not the database file should be updated after closing **self**. """ + def __init__(self, path=None, write=True): self.path = path or getcwd() self.write = write @@ -330,6 +361,7 @@ class open_csv_lig(): :param bool write: Whether or not the database file should be updated after closing **self**. """ + def __init__(self, path=None, write=True): self.path = path or getcwd() self.write = write @@ -338,7 +370,9 @@ def __init__(self, path=None, write=True): def __enter__(self): # Open the .csv file dtype = {'hdf5 index': int, 'formula': str, 'settings': str} - self.df = pd.read_csv(self.path, index_col=[0, 1], header=[0, 1], dtype=dtype) + self.df = Database.DF( + pd.read_csv(self.path, index_col=[0, 1], header=[0, 1], dtype=dtype) + ) # Fix the columns idx_tups = [(i, '') if 'Unnamed' in j else (i, j) for i, j in self.df.columns] @@ -358,6 +392,7 @@ class open_csv_qd(): :param bool write: Whether or not the database file should be updated after closing **self**. """ + def __init__(self, path=None, write=True): self.path = path or getcwd() self.write = write @@ -365,8 +400,10 @@ def __init__(self, path=None, write=True): def __enter__(self): # Open the .csv file - dtype = {'hdf5 index': int, 'ligand count': np.int64, 'settings': str} - self.df = pd.read_csv(self.path, index_col=[0, 1, 2, 3], header=[0, 1], dtype=dtype) + dtype = {'hdf5 index': int, 'ligand count': int, 'settings': str} + self.df = Database.DF( + pd.read_csv(self.path, index_col=[0, 1, 2, 3], header=[0, 1], dtype=dtype) + ) # Fix the columns idx_tups = [(i, '') if 'Unnamed' in j else (i, j) for i, j in self.df.columns] @@ -379,6 +416,43 @@ def __exit__(self, type, value, traceback): self.df.to_csv(self.path) self.df = None + class DF(dict): + """A mutable container for holding dataframes.""" + + def __init__(self, df: pd.DataFrame) -> None: + super().__init__() + super().__setitem__('df', df) + + def __getattribute__(self, key): + if key == 'update_df' or (key.startswith('__') and key.endswith('__')): + return super().__getattribute__(key) + return self['df'].__getattribute__(key) + + def __setattr__(self, key, value): + self['df'].__setattr__(key, value) + + def __setitem__(self, key, value): + if key == 'df' and not isinstance(value, pd.DataFrame): + try: + value = value['df'] + if not isinstance(value, pd.DataFrame): + raise KeyError + super().__setitem__('df', value) + except KeyError: + err = ("Instance of 'pandas.DataFrame' or 'CAT.Database.DF' expected;" + " observed type: '{}'") + raise TypeError(err.format(value.__class__.__name__)) + elif key == 'df': + super().__setitem__('df', value) + else: + self['df'].__setitem__(key, value) + + def __getitem__(self, key): + df = super().__getitem__('df') + if key == 'df': + return df + return df.__getitem__(key) + """ ################################# Updating the database ############################## """ def update_csv(self, df, database='ligand', columns=None, overwrite=False, job_recipe=None): @@ -406,30 +480,26 @@ def update_csv(self, df, database='ligand', columns=None, overwrite=False, job_r # Update **self.yaml** if job_recipe is not None: job_settings = self.update_yaml(job_recipe) - for key in job_settings: - df[('settings', key)] = job_settings[key] + for key, value in job_settings.items(): + df[('settings', key)] = value with open_csv(path, write=True) as db: # Update **db.index** - nan_row = get_nan_row(db) - for i in df.index: - if i not in db.index: - db.at[i, :] = nan_row - db['hdf5 index'] = db['hdf5 index'].astype(int, copy=False) # Fix the data type + db['df'] = even_index(db['df'], df) # Filter columns if not columns: df_columns = df.columns else: - df_columns = columns + [i for i in df.columns if i[0] == 'settings'] + df_columns = pd.Index(columns + [i for i in df.columns if i[0] == 'settings']) # Update **db.columns** - for i in df_columns: - if i not in db.columns: - try: - db[i] = np.array((None), dtype=df[i].dtype) - except TypeError: # e.g. if csv[i] consists of the datatype np.int64 - db[i] = -1 + bool_ar = df_columns.isin(db.columns) + for i in df_columns[~bool_ar]: + try: + db[i] = np.array((None), dtype=df[i].dtype) + except TypeError: # e.g. if csv[i] consists of the datatype np.int64 + db[i] = -1 # Update **self.hdf5**; returns a new series of indices hdf5_series = self.update_hdf5(df, database=database, overwrite=overwrite) @@ -536,7 +606,7 @@ def from_csv(self, df, database='ligand', get_mol=True, inplace=True): # Update the *hdf5 index* column in **df** with open_csv(path, write=False) as db: - df.update(db, overwrite=True) + df.update(db['df'], overwrite=True) df['hdf5 index'] = df['hdf5 index'].astype(int, copy=False) # **df** has been updated and **get_mol** = *False* diff --git a/CAT/data_handling/__init__.py b/CAT/data_handling/__init__.py index cdc9bad8..dc3f179a 100644 --- a/CAT/data_handling/__init__.py +++ b/CAT/data_handling/__init__.py @@ -1,12 +1,12 @@ """ Modules related to the importing, exporting and general handling of data. """ from .CAT_database import (Database, mol_to_file) -from .mol_import import (read_mol, set_prop) +from .mol_import import (read_mol, set_mol_prop) from .input_sanitizer import (sanitize_optional, sanitize_input_mol, sanitize_path) __all__ = [ 'Database', 'mol_to_file', - 'read_mol', 'set_prop', + 'read_mol', 'set_mol_prop', 'sanitize_optional', 'sanitize_input_mol', 'sanitize_path' ] diff --git a/CAT/data_handling/input_sanitizer.py b/CAT/data_handling/input_sanitizer.py index 5126c0a1..c3745958 100644 --- a/CAT/data_handling/input_sanitizer.py +++ b/CAT/data_handling/input_sanitizer.py @@ -50,17 +50,15 @@ def sanitize_path(arg): elif isinstance(arg.path, str): if arg.path.lower() in ('none', '.', 'pwd', '$pwd', 'cwd'): arg.path = os.getcwd() - else: - if not os.path.exists(arg.path): - raise FileNotFoundError(get_time() + 'path ' + arg.path + ' not found') - elif os.path.isfile(arg.path): - raise TypeError(get_time() + 'path ' + arg.path + ' is a file, not a directory') + elif not os.path.exists(arg.path): + raise FileNotFoundError(get_time() + "path '{}' not found".format(arg.path)) + elif os.path.isfile(arg.path): + raise OSError(get_time() + "path '{}' is a file, not a directory".format(arg.path)) return arg else: - error = 'arg.path should be None or a string, ' + str(type(arg.path)) - error += ' is not a valid type' - raise TypeError(error) + error = "arg.path should be None or a string, '{}' is not a valid type" + raise TypeError(error.format(arg.path.__class__.__name__)) """ ########################## Sanitize input_ligands & input_cores ######################## """ @@ -99,16 +97,19 @@ def get_mol_defaults(mol_list, path=None, core=False): tmp.path = path tmp.is_core = core - if isinstance(mol, dict): - for key1 in mol: - tmp.mol = key1 - for key2 in mol[key1]: - try: - tmp[key2] = key_dict[key2](mol[key1][key2]) - except KeyError: - raise KeyError(str(key2) + ' is not a valid argument for ' + str(key1)) - if key2 == 'guess_bonds': - tmp.tmp_guess = True + if not isinstance(mol, dict): + ret.append(tmp) + continue + + for k1, v1 in mol.items(): + tmp.mol = k1 + for k2, v2 in v1.items(): + try: + tmp[k2] = key_dict[k2](v2) + except KeyError: + raise KeyError("'{}' is not a valid argument for '{}'".format(str(k2), str(k1))) + if k2 == 'guess_bonds': + tmp.tmp_guess = True ret.append(tmp) return ret diff --git a/CAT/data_handling/mol_import.py b/CAT/data_handling/mol_import.py index 41d6d302..21cac0a9 100644 --- a/CAT/data_handling/mol_import.py +++ b/CAT/data_handling/mol_import.py @@ -1,9 +1,11 @@ """ A module related to the importing of molecules. """ -__all__ = ['read_mol', 'set_prop'] +__all__ = ['read_mol', 'set_mol_prop'] import os import itertools +from typing import Dict +from string import ascii_letters from scm.plams.mol.molecule import Molecule from scm.plams.core.errors import PlamsError @@ -21,14 +23,16 @@ def read_mol(input_mol): returns a list of plams molecules. """ # Creates a dictionary of file extensions - extension_dict = {'xyz': read_mol_xyz, - 'pdb': read_mol_pdb, - 'mol': read_mol_mol, - 'smiles': read_mol_smiles, - 'folder': read_mol_folder, - 'txt': read_mol_txt, - 'plams_mol': read_mol_plams, - 'rdmol': read_mol_rdkit} + extension_dict = { + 'xyz': read_mol_xyz, + 'pdb': read_mol_pdb, + 'mol': read_mol_mol, + 'smiles': read_mol_smiles, + 'folder': read_mol_folder, + 'txt': read_mol_txt, + 'plams_mol': read_mol_plams, + 'rdmol': read_mol_rdkit + } # Create a list of PLAMS molecules mol_list = [] @@ -36,22 +40,23 @@ def read_mol(input_mol): try: read_mol = extension_dict[mol_dict.type] except KeyError as ex: - print(get_time() + str(type(ex).__name__) + ':\t' + str(ex) + '\n') - - # Convert mol into either a list or PLAMS molecule - if read_mol: - mol = read_mol(mol_dict) - if mol: - # if mol is a list - if isinstance(mol, list): - mol_list += mol - - # if mol is a PLAMS molecule - else: - if mol_dict.guess_bonds: - mol.guess_bonds() - set_prop(mol, mol_dict) - mol_list.append(mol) + print(get_time() + ex.__class__.__name__ + ':\t' + str(ex) + '\n') + read_mol = False + + if not read_mol: # Unrecognized input type + continue + + mol = read_mol(mol_dict) + if not mol: # Failed to import any molecules + continue + + if isinstance(mol, list): # if mol is a list of molecules + mol_list += mol + else: # if mol is a PLAMS molecule + if mol_dict.guess_bonds: + mol.guess_bonds() + set_mol_prop(mol, mol_dict) + mol_list.append(mol) return mol_list @@ -116,7 +121,7 @@ def read_mol_folder(mol): def read_mol_txt(mol): - """ Read a plain text file containing one or more SMILES strings """ + """Read a plain text file containing one or more SMILES strings.""" try: with open(mol.mol, 'r') as file: file_list = file.read().splitlines() @@ -128,10 +133,32 @@ def read_mol_txt(mol): print_exception(read_mol_txt.__code__, ex, mol.mol) -def set_prop(mol, mol_dict): - """ - Set molecular and atomic properties - """ +def get_charge_dict(): + """Create a dictionary of elements and their formal atomic charge.""" + # Create a list of atomic charges and elements + charges = (1, 2, -3, -2, -1, 2) + elements = ( + ('Li', 'Na', 'K', 'Rb', 'Cs'), # Group 1: Alkali metals + ('Be', 'Mg', 'Ca', 'Sr', 'Ba'), # Group 2: Alkaline earth metals + ('N', 'P', 'As', 'Sb', 'Bi'), # Group 15: pnictogens + ('O', 'S', 'Se', 'Te', 'Po'), # Group 16: Chalcogens + ('H', 'F', 'Cl', 'Br', 'I', 'At'), # Group 17: Halogens + ('Cd', 'Pb') # Misc + ) + + # Combine the elements and atomic charges into a dictionary + values = itertools.chain.from_iterable([i] * len(j) for i, j in zip(charges, elements)) + keys = itertools.chain(*elements) + + return dict(zip(keys, values)) + + +# Create a dictionary of elements and their formal atomic charge +charge_dict: Dict[str, int] = get_charge_dict() + + +def set_mol_prop(mol, mol_dict): + """Set molecular and atomic properties.""" if mol_dict.is_core: residue_name = 'COR' mol.properties.name = mol.get_formula() @@ -142,34 +169,28 @@ def set_prop(mol, mol_dict): mol.properties.dummies = mol_dict.indices mol.properties.path = mol_dict.path - # Prepare a list of letters for pdb_info.Name - alphabet = list('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') - alphabet = [i + j for i in alphabet for j in alphabet] - - # Create a dictionary of elements and their formal atomic charge - elements_dict = set_prop_dict() + # Prepare a generator of letters for pdb_info.Name + alphabet = itertools.combinations(ascii_letters, 2) # Set the atomic properties - for i, atom in enumerate(mol): - set_prop_atom(atom, alphabet[i], residue_name, elements_dict) + for atom, i in zip(mol, alphabet): + set_atom_prop(atom, i, residue_name) if not mol.properties.smiles: - mol.properties.smiles = Chem.MolToSmiles(Chem.RemoveHs(molkit.to_rdmol(mol))) - mol.properties.smiles = Chem.CanonSmiles(mol.properties.smiles) + tmp = Chem.MolToSmiles(Chem.RemoveHs(molkit.to_rdmol(mol))) + mol.properties.smiles = Chem.CanonSmiles(tmp) -def set_prop_atom(atom, alphabet, residue_name, elements_dict): - """ - Set atomic properties. - """ - symbol = atom.symbol + alphabet + ' ' +def set_atom_prop(atom, i, residue_name): + """Set atomic properties.""" + symbol = '{:4}'.format(atom.symbol + ''.join(i)) # Add a number of properties to atom atom.properties.pdb_info.ResidueName = residue_name atom.properties.pdb_info.Occupancy = 1.0 atom.properties.pdb_info.TempFactor = 0.0 atom.properties.pdb_info.ResidueNumber = 1 - atom.properties.pdb_info.Name = symbol[:4] + atom.properties.pdb_info.Name = symbol atom.properties.pdb_info.ChainId = 'A' # Changes hydrogen and carbon from heteroatom to atom @@ -179,53 +200,27 @@ def set_prop_atom(atom, alphabet, residue_name, elements_dict): atom.properties.pdb_info.IsHeteroAtom = True # Sets the formal atomic charge - if atom.properties.charge: - return - - if atom.symbol in elements_dict: - total_bonds = int(sum([bond.order for bond in atom.bonds])) - default_charge = elements_dict[atom.symbol] - sign = int(-1 * default_charge / abs(default_charge)) - atom.properties.charge = default_charge + sign*total_bonds - - # Update formal atomic charges for hypervalent atoms - abs_charge = abs(default_charge) - if total_bonds > abs_charge: - if total_bonds is abs_charge + 2: - atom.properties.charge -= sign*2 - elif total_bonds is abs_charge + 4: - atom.properties.charge -= sign*4 - elif total_bonds >= abs_charge + 6: - atom.properties.charge -= sign*6 - else: - atom.properties.charge = 0 - - -def set_prop_dict(): - """ - Create a dictionary of elements and their formal atomic charge. - """ - # Create a list of atomic charges and elements - charges = [1, 2, -3, -2, -1, 2] - group01 = ['Li', 'Na', 'K', 'Rb', 'Cs'] # Alkaline metals - group02 = ['Be', 'Mg', 'Ca', 'Sr', 'Ba'] # Alkaline earth metals - group15 = ['N', 'P', 'As', 'Sb', 'Bi'] # Pnictogens - group16 = ['O', 'S', 'Se', 'Te', 'Po'] # Chalcogens - group17 = ['H', 'F', 'Cl', 'Br', 'I', 'At'] # Halogens - misc = ['Cd', 'Pb'] # Misc - - # Combine the elements and atomic charges into a dictionary - elements = [group01, group02, group15, group16, group17, misc] - charges = [charges[i] for i, column in enumerate(elements) for element in column] - elements = list(itertools.chain(*elements)) - - return dict(zip(elements, charges)) + if not atom.properties.charge: + if atom.symbol in charge_dict: + total_bonds = int(sum([bond.order for bond in atom.bonds])) + default_charge = charge_dict[atom.symbol] + sign = int(-1 * default_charge / abs(default_charge)) + atom.properties.charge = default_charge + sign*total_bonds + + # Update formal atomic charges for hypervalent atoms + if total_bonds > abs(default_charge): + if total_bonds is abs(default_charge) + 2: + atom.properties.charge += sign*2 + elif total_bonds is abs(default_charge) + 4: + atom.properties.charge += sign*4 + elif total_bonds >= abs(default_charge) + 6: + atom.properties.charge += sign*6 + else: + atom.properties.charge = 0 def print_exception(func, ex, name): - """ - Manages the printing of exceptions upon failing to import a molecule. - """ + """Manages the printing of exceptions upon failing to import a molecule.""" extension_dict = {'read_mol_xyz': '.xyz file', 'read_mol_pdb': '.pdb file', 'read_mol_mol': '.mol file', 'read_mol_smiles': 'SMILES string', 'read_mol_folder': 'folder', 'read_mol_txt': '.txt file', diff --git a/CAT/utils.py b/CAT/utils.py index 24f258e7..56e05dd0 100644 --- a/CAT/utils.py +++ b/CAT/utils.py @@ -31,7 +31,7 @@ def type_to_string(job): def get_time(): """Return the current time as string.""" - return '[{}]'.format(time.strftime('%H:%M:%S')) + return '[{}] '.format(time.strftime('%H:%M:%S')) def check_sys_var(): diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bf994ccd..c6beef6a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,8 +5,16 @@ Change Log All notable changes to this project will be documented in this file. This project adheres to `Semantic Versioning `_. +0.4.2 +***** + +* Numerous bug fixes +* A couple of code-style changes + + 0.4.1 ***** + * COSMO-RS calculations now allow for COSMO-surface construction at the DFT level diff --git a/README.rst b/README.rst index 2083c8a3..08179933 100644 --- a/README.rst +++ b/README.rst @@ -7,7 +7,7 @@ :target: https://www.python.org ####################################### -Compound Attachment/Analysis Tool 0.4.1 +Compound Attachment/Analysis Tool 0.4.2 ####################################### **CAT** is a collection of tools designed for the construction, diff --git a/docs/conf.py b/docs/conf.py index 0faedb88..f0941353 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -65,7 +65,7 @@ # The short X.Y version. version = '0.4' # The full version, including alpha/beta/rc tags. -release = '0.4.1' +release = '0.4.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/examples/input_settings.yaml b/examples/input_settings.yaml index 1bc80dcb..1a5a34d8 100644 --- a/examples/input_settings.yaml +++ b/examples/input_settings.yaml @@ -1,4 +1,4 @@ -path: /Users/bvanbeek/Documents/CdSe/Week_5 +path: /Users/basvanbeek/Documents/CdSe/Week_5 input_cores: - Cd68Se55.xyz: @@ -25,9 +25,12 @@ optional: dirname: ligand optimize: True split: True - cosmo-rs: True + cosmo-rs: False qd: dirname: QD - optimize: False - dissociate: False + optimize: True + dissociate: + core_index: [60, 62, 64, 71, 74, 78] + job1: True + job2: False diff --git a/test/test_cat.py b/test/test_cat.py index c7becedc..a9779394 100644 --- a/test/test_cat.py +++ b/test/test_cat.py @@ -1,4 +1,4 @@ -""" A module for CAT-related tests. """ +"""A module for CAT-related tests.""" import contextlib import io @@ -6,7 +6,6 @@ import shutil import yaml -import pytest import pandas as pd from scm.plams.core.settings import Settings