def check_x_motifs(linker=None, linker_template=None): if linker is None and linker_template is not None: if not all([ motif.n_atoms == linker_template.x_motifs[0].n_atoms for motif in linker_template.x_motifs ]): logger.critical('Found x motifs in the structure that have ' 'different number of atoms') raise CgbindCritical else: return None if not all([ motif.n_atoms == linker_template.x_motifs[0].n_atoms for motif in linker.x_motifs ]): logger.warning('Found x motifs in the structure that have different ' 'number of atoms') logger.info('Stripping the motifs with the wrong number of atoms') linker.x_motifs = [ motif for motif in linker.x_motifs if motif.n_atoms == linker_template.x_motifs[0].n_atoms ] logger.info(f'Now have {len(linker.x_motifs)} motifs in the linker') if len(linker.x_motifs) == 0: raise CgbindCritical('Have 0 Xmotifs – cannot build a cage. ' 'Is the template correct?') if len(linker.x_motifs) > 0: logger.info(f'Number of atoms in the x motifs is ' f'{linker.x_motifs[0].n_atoms}') return None
def get_maximally_connected_x_motifs(x_motifs, x_atoms): """ Given a list of Xmotifs find those that are maximally connected, i.e. the ones that contain all the donor atoms but also are the largest in size :param x_motifs: (list(cgbind.x_motifs.Xmotif) :param x_atoms: (list(int)) :return: """ # X motif lengths sorted from high to low for x_motif_length in reversed(sorted(set([len(x) for x in x_motifs]))): new_x_motifs = [x for x in x_motifs if len(x) == x_motif_length] # Add all the atom ids of the xmotifs to a single list x_motifs_atoms = [] for x_motif in new_x_motifs: x_motifs_atoms += x_motif.atom_ids # All the donor (X) atoms need to be in the full list if all(x_atom in x_motifs_atoms for x_atom in x_atoms): logger.info(f'Returning {len(new_x_motifs)} Xmotifs each with ' f'{len(new_x_motifs[0])} atoms') return new_x_motifs logger.critical('Could not find a set of x motifs of the same length with' ' all the donor atoms') raise CgbindCritical
def singlepoint(molecule, method, keywords, n_cores=None): """ Run a single point energy evaluation on a molecule :param molecule: (object) :param method: (autode.ElectronicStructureMethod) :param keywords: (list(str)) Keywords to use for the electronic structure calculation e.g. ['Opt', 'PBE', 'def2-SVP'] :param n_cores: (int) Number of cores to use :return: """ logger.info('Running single point calculation') n_cores = Config.n_cores if n_cores is None else int(n_cores) try: from autode.calculation import Calculation from autode.wrappers.XTB import xtb from autode.wrappers.ORCA import orca from autode.wrappers.keywords import SinglePointKeywords except ModuleNotFoundError: logger.error('autode not found. Calculations not available') raise RequiresAutodE if keywords is None: if method == orca: keywords = SinglePointKeywords( ['SP', 'M062X', 'def2-TZVP', 'RIJCOSX', 'def2/J', 'SlowConv']) logger.warning('No keywords were set for the single point but an ' 'ORCA calculation was requested. ' f'Using {str(keywords)}') elif method == xtb: keywords = xtb.keywords.sp else: logger.critical('No keywords were set for the single-point ' 'calculation') raise Exception else: # If the keywords are specified as a list convert them to a set of # OptKeywords, required for autodE if type(keywords) is list: keywords = SinglePointKeywords(keywords) sp = Calculation(name=molecule.name + '_sp', molecule=molecule, method=method, keywords=keywords, n_cores=n_cores) sp.run() molecule.energy = sp.get_energy() return None
def _set_energy_func(self, energy_method): """ From an energy_method string get the corresponding function :param energy_method: (str) Name of the energy method to build a cage-substrate complex :return: (function) Energy function """ energy_method_names = [func.__name__ for func in energy_funcs] if energy_method not in energy_method_names: logger.critical(f'Could not generate a cage-susbtrate complex with' f' the {energy_method} method') raise CannotBuildCSComplex(f'Not a valid energy method. ' f'Available methods are ' f'{energy_method_names}') # Set the energy function to generate this cage substrate complex for func in energy_funcs: if func.__name__ == energy_method: self.energy_func = func return None
def optimise(molecule, method, keywords, n_cores=None, cartesian_constraints=None): """ Optimise a molecule :param molecule: (object) :param method: (autode.ElectronicStructureMethod) :param keywords: (list(str)) Keywords to use for the electronic structure c alculation e.g. ['Opt', 'PBE', 'def2-SVP'] :param n_cores: (int) Number of cores to use :param cartesian_constraints: (list(int)) List of atom ids to constrain :return: """ logger.info('Running an optimisation calculation') n_cores = Config.n_cores if n_cores is None else int(n_cores) try: from autode.calculation import Calculation from autode.wrappers.XTB import xtb from autode.wrappers.ORCA import orca from autode.wrappers.keywords import OptKeywords except ModuleNotFoundError: logger.error('autode not found. Calculations not available') raise RequiresAutodE if keywords is None: if method == orca: keywords = OptKeywords(['LooseOpt', 'PBE', 'D3BJ', 'def2-SVP']) logger.warning(f'No keywords were set for the optimisation but an' f' ORCA calculation was requested. ' f'Using {str(keywords)}') elif method == xtb: keywords = xtb.keywords.opt else: logger.critical('No keywords were set for the optimisation ' 'calculation') raise Exception else: # If the keywords are specified as a list convert them to a set of # OptKeywords, required for autodE if type(keywords) is list: keywords = OptKeywords(keywords) opt = Calculation(name=molecule.name + '_opt', molecule=molecule, method=method, keywords=keywords, n_cores=n_cores, cartesian_constraints=cartesian_constraints) opt.run() molecule.energy = opt.get_energy() molecule.set_atoms(atoms=opt.get_final_atoms()) return None