def genNetwork(self, mol_object, **kwargs):
        """
        Execute the automatic reaction discovery procedure.
        """
        # Database
        qm_collection = db['qm_calculate_center']
        config_collection = db['config']
        statistics_collection = db['statistics']
        targets = list(config_collection.find({'generations': 1}))
        config_collection.update_one(
            targets[0], {"$set": {
                'config_path': kwargs['config_path']
            }}, True)
        # Reactant information
        reactant_inchi_key = mol_object.write('inchiKey').strip()  # inchikey

        # Generate all possible products
        gen = Generate(mol_object, **kwargs)
        self.logger.info('Generating all possible products...')
        gen.generateProducts()
        prod_mols = gen.get_prods()
        add_bonds = gen.get_add_bonds()
        break_bonds = gen.get_break_bonds()
        prod_mols_filtered = []
        self.logger.info(f'{len(prod_mols)} possible products are generated\n')

        # Filter reactions based on standard heat of reaction  delta H
        if self.method.lower() == 'mopac':
            self.logger.info(
                f'Now use {self.method} to filter the delta H of reactions....\n'
            )
            if self.generations == 1:
                os.mkdir(path.join(path.dirname(self.ard_path), 'reactions'))
                H298_reac = self.get_mopac_H298(mol_object)
                config_collection.update_one(
                    targets[0], {
                        "$set": {
                            'reactant_energy': H298_reac,
                            'use_irc': self.use_irc,
                            'use_qmmm': self.use_qmmm
                        }
                    }, True)
                mol_object_copy = mol_object.copy()
                for prod_mol in prod_mols:
                    if self.filter_dh_mopac(
                            mol_object,
                            self.cluster_bond,
                            prod_mol,
                            add_bonds[prod_mols.index(prod_mol)],
                            break_bonds[prod_mols.index(prod_mol)],
                            len(prod_mols),
                            qm_collection,
                            refH=None):
                        prod_mols_filtered.append(prod_mol)
                    # Recovery
                    mol_object_copy = mol_object.copy()
            else:
                H298_reac = targets[0]['reactant_energy']
                mol_object_copy = mol_object.copy()
                for prod_mol in prod_mols:
                    if self.filter_dh_mopac(
                            mol_object,
                            self.cluster_bond,
                            prod_mol,
                            add_bonds[prod_mols.index(prod_mol)],
                            break_bonds[prod_mols.index(prod_mol)],
                            len(prod_mols),
                            qm_collection,
                            refH=H298_reac):
                        prod_mols_filtered.append(prod_mol)
                    # Recovery
                    mol_object_copy = mol_object.copy()
        elif self.method.lower() == 'xtb':
            self.logger.info(
                'Now use {} to filter the delta H of reactions....\n'.format(
                    self.method))
            if self.generations == 1:
                os.mkdir(path.join(path.dirname(self.ard_path), 'reactions'))
                H298_reac = self.get_xtb_H298(
                    config_path=kwargs['config_path'])
                config_collection.update_one(
                    targets[0], {
                        "$set": {
                            'reactant_energy': H298_reac,
                            'use_irc': self.use_irc,
                            'use_qmmm': self.use_qmmm
                        }
                    }, True)
                mol_object_copy = mol_object.copy()
                for prod_mol in prod_mols:
                    if self.filter_dh_xtb(
                            mol_object,
                            prod_mol,
                            self.cluster_bond,
                            add_bonds[prod_mols.index(prod_mol)],
                            break_bonds[prod_mols.index(prod_mol)],
                            len(prod_mols),
                            qm_collection,
                            config_path=kwargs['config_path'],
                            refH=None):
                        prod_mols_filtered.append(prod_mol)
                    mol_object.setCoordsFromMol(mol_object_copy)
            else:
                H298_reac = targets[0]['reactant_energy']
                mol_object_copy = mol_object.copy()
                for prod_mol in prod_mols:
                    if self.filter_dh_xtb(
                            mol_object,
                            prod_mol,
                            self.cluster_bond,
                            add_bonds[prod_mols.index(prod_mol)],
                            break_bonds[prod_mols.index(prod_mol)],
                            len(prod_mols),
                            qm_collection,
                            config_path=kwargs['config_path'],
                            refH=H298_reac):
                        prod_mols_filtered.append(prod_mol)
                    mol_object.setCoordsFromMol(mol_object_copy)
        else:
            self.logger.info(
                'Now use {} to filter the delta H of reactions....\n'.format(
                    self.method))
            # Load thermo database and choose which libraries to search
            thermo_db = ThermoDatabase()
            thermo_db.load(path.join(settings['database.directory'], 'thermo'))
            thermo_db.libraryOrder = [
                'primaryThermoLibrary',
                'NISTThermoLibrary',
                'thermo_DFT_CCSDTF12_BAC',
                'CBS_QB3_1dHR',
                'DFT_QCI_thermo',
                'BurkeH2O2',
                'GRI-Mech3.0-N',
            ]
            if self.generations == 1:
                H298_reac = mol_object.getH298(thermo_db)
                update_field = {'reactant_energy': H298_reac}
                config_collection.update_one(targets[0],
                                             {"$set": update_field}, True)
            else:
                H298_reac = targets[0]['reactant_energy']
            prod_mols_filtered = [
                mol for mol in prod_mols
                if self.filter_dh_rmg(H298_reac, mol, thermo_db)
            ]
            self.logger.info('Generate geometry........\n')
            for mol in prod_mols_filtered:
                index = prod_mols.index(mol)
                # Generate geometry and return path
                mol_object.gen3D(self.fixed_atoms,
                                 forcefield=self.forcefield,
                                 method=self.constraintff_alg,
                                 make3D=False)
                reac_mol_copy = mol_object.copy()
                dir_path = self.gen_geometry(mol_object, mol, reac_mol_copy,
                                             add_bonds[index],
                                             break_bonds[index])
                product_inchi_key = mol.write('inchiKey').strip()
                self.logger.info(
                    f"\nReactant inchi key: {reactant_inchi_key}\nProduct inchi key: {product_inchi_key}\nReactant smiles: {mol_object.write('can').split()}\nProduct smiles: {mol.write('can').split()}\nDirectory path: {dir_path}\n"
                )

                qm_collection.insert_one({
                    'reaction': [reactant_inchi_key, product_inchi_key],
                    'reactant_smiles':
                    mol_object.write('can').split()[0],
                    'reactant_inchi_key':
                    reactant_inchi_key,
                    'product_inchi_key':
                    product_inchi_key,
                    'product_smiles':
                    mol.write('can').split()[0],
                    'path':
                    dir_path,
                    'ssm_status':
                    'job_unrun',
                    'generations':
                    self.generations,
                })

        self.logger.info('After delta H filter {} product remain.\n'.format(
            len(prod_mols_filtered)))
        # Generate geometry and insert to database
        statistics_collection.insert_one({
            'reactant_smiles':
            mol_object.write('can').split()[0],
            'reactant_inchi_key':
            reactant_inchi_key,
            'add how many products':
            len(prod_mols_filtered),
            'generations':
            self.generations
        })
Exemplo n.º 2
0
    def execute(self, **kwargs):
        """
        Execute the automatic reaction discovery procedure.
        """
        start_time = time.time()
        reac_mol = self.initialize()
        # self.optimizeReactant(reac_mol, **kwargs)

        gen = Generate(reac_mol)
        self.logger.info('Generating all possible products...')
        gen.generateProducts(nbreak=self.nbreak, nform=self.nform)
        prod_mols = gen.prod_mols
        self.logger.info('{} possible products generated\n'.format(
            len(prod_mols)))

        # Load thermo database and choose which libraries to search
        thermo_db = ThermoDatabase()
        thermo_db.load(os.path.join(settings['database.directory'], 'thermo'))
        thermo_db.libraryOrder = [
            'primaryThermoLibrary',
            'NISTThermoLibrary',
            'thermo_DFT_CCSDTF12_BAC',
            'CBS_QB3_1dHR',
            'DFT_QCI_thermo',
            'KlippensteinH2O2',
            'GRI-Mech3.0-N',
        ]

        # Filter reactions based on standard heat of reaction
        H298_reac = reac_mol.getH298(thermo_db)
        self.logger.info('Filtering reactions...')
        prod_mols_filtered = [
            mol for mol in prod_mols
            if self.filterThreshold(H298_reac, mol, thermo_db, **kwargs)
        ]
        self.logger.info('{} products remaining\n'.format(
            len(prod_mols_filtered)))

        # Generate 3D geometries
        if prod_mols_filtered:
            self.logger.info('Feasible products:\n')
            rxn_dir = util.makeOutputSubdirectory(self.output_dir, 'reactions')

            # These two lines are required so that new coordinates are
            # generated for each new product. Otherwise, Open Babel tries to
            # use the coordinates of the previous molecule if it is isomorphic
            # to the current one, even if it has different atom indices
            # participating in the bonds. a hydrogen atom is chosen
            # arbitrarily, since it will never be the same as any of the
            # product structures.
            Hatom = gen3D.readstring('smi', '[H]')
            ff = pybel.ob.OBForceField.FindForceField(self.forcefield)

            reac_mol_copy = reac_mol.copy()
            for rxn, mol in enumerate(prod_mols_filtered):
                mol.gen3D(forcefield=self.forcefield, make3D=False)
                arrange3D = gen3D.Arrange3D(reac_mol, mol)
                msg = arrange3D.arrangeIn3D()
                if msg != '':
                    self.logger.info(msg)

                ff.Setup(
                    Hatom.OBMol
                )  # Ensures that new coordinates are generated for next molecule (see above)
                reac_mol.gen3D(make3D=False)
                ff.Setup(Hatom.OBMol)
                mol.gen3D(make3D=False)
                ff.Setup(Hatom.OBMol)

                reactant = reac_mol.toNode()
                product = mol.toNode()

                rxn_num = '{:04d}'.format(rxn)
                output_dir = util.makeOutputSubdirectory(rxn_dir, rxn_num)
                kwargs['output_dir'] = output_dir
                kwargs['name'] = rxn_num

                self.logger.info('Product {}: {}\n{}\n****\n{}\n'.format(
                    rxn, product.toSMILES(), reactant, product))
                self.makeInputFile(reactant, product, **kwargs)

                reac_mol.setCoordsFromMol(reac_mol_copy)
        else:
            self.logger.info('No feasible products found')

        # Finalize
        self.finalize(start_time)