def geo_to_mol(coords, nums): """ Convert molecular geometry specified by atomic coordinates and atomic numbers to RMG molecule. Use Open Babel for most cases because it's better at recognizing long bonds. Use RMG for hydrogen because Open Babel can't do it for mysterious reasons. """ if list(nums) == [1, 1]: mol = Molecule() mol.fromXYZ(nums, coords) else: xyz = '{}\n\n'.format(len(nums)) xyz += '\n'.join( '{0} {1[0]: .10f} {1[1]: .10f} {1[2]: .10f}'.format(n, c) for n, c in zip(nums, coords)) mol = pybel.readstring('xyz', xyz) mol = pybel_to_rmg(mol) return mol
def check_isomorphic(conformer): """ Compares whatever is in the log file 'f' to the SMILES of the passed in 'conformer' """ starting_molecule = RMGMolecule(SMILES=conformer.smiles) starting_molecule = starting_molecule.toSingleBonds() atoms = self.read_log(os.path.join(scratch_dir, f)) test_molecule = RMGMolecule() test_molecule.fromXYZ(atoms.arrays["numbers"], atoms.arrays["positions"]) if not starting_molecule.isIsomorphic(test_molecule): logging.info( "Output geometry of {} is not isomorphic with input geometry" .format(calc.label)) return False else: logging.info("{} was successful and was validated!".format( calc.label)) return True
def verifyOutputFile(self): """ Check's that an output file exists and was successful. Returns a boolean flag that states whether a successful MOPAC simulation already exists for the molecule with the given (augmented) InChI Key. The definition of finding a successful simulation is based on these criteria: 1) finding an output file with the file name equal to the InChI Key 2) NOT finding any of the keywords that are denote a calculation failure 3) finding all the keywords that denote a calculation success. 4) finding a match between the InChI of the given molecule and the InchI found in the calculation files 5) checking that the optimized geometry, when connected by single bonds, is isomorphic with self.molecule (converted to single bonds) If any of the above criteria is not matched, False will be returned. If all succeed, then it will return True. """ if not os.path.exists(self.outputFilePath): logging.debug("Output file {0} does not (yet) exist.".format(self.outputFilePath)) return False InChIMatch=False #flag (1 or 0) indicating whether the InChI in the file matches InChIaug this can only be 1 if InChIFound is also 1 InChIFound=False #flag (1 or 0) indicating whether an InChI was found in the log file # Initialize dictionary with "False"s successKeysFound = dict([(key, False) for key in self.successKeys]) with open(self.outputFilePath) as outputFile: for line in outputFile: line = line.strip() for element in self.failureKeys: #search for failure keywords if element in line: logging.error("MOPAC output file contains the following error: {0}".format(element) ) return False for element in self.successKeys: #search for success keywords if element in line: successKeysFound[element] = True if "InChI=" in line: logFileInChI = line #output files should take up to 240 characters of the name in the input file InChIFound = True if self.uniqueIDlong in logFileInChI: InChIMatch = True elif self.uniqueIDlong.startswith(logFileInChI): logging.info("InChI too long to check, but beginning matches so assuming OK.") InChIMatch = True else: logging.warning("InChI in log file ({0}) didn't match that in geometry ({1}).".format(logFileInChI, self.uniqueIDlong)) # Use only up to first 80 characters to match due to MOPAC bug which deletes 81st character of InChI string if self.uniqueIDlong.startswith(logFileInChI[:80]): logging.warning("but the beginning matches so it's probably just a truncation problem.") InChIMatch = True # Check that ALL 'success' keywords were found in the file. if not all( successKeysFound.values() ): logging.error('Not all of the required keywords for success were found in the output file!') return False if not InChIFound: logging.error("No InChI was found in the MOPAC output file {0}".format(self.outputFilePath)) return False if not InChIMatch: #InChIs do not match (most likely due to limited name length mirrored in log file (240 characters), but possibly due to a collision) return self.checkForInChiKeyCollision(logFileInChI) # Not yet implemented! # Compare the optimized geometry to the original molecule qmData = self.parse() cclibMol = Molecule() cclibMol.fromXYZ(qmData.atomicNumbers, qmData.atomCoords.value) testMol = self.molecule.toSingleBonds() if not cclibMol.isIsomorphic(testMol): logging.info("Incorrect connectivity for optimized geometry in file {0}".format(self.outputFilePath)) return False logging.info("Successful {1} quantum result in {0}".format(self.outputFilePath, self.__class__.__name__)) return True #InChIs do not match (most likely due to limited name length mirrored in log file (240 characters), but possibly due to a collision) return self.checkForInChiKeyCollision(logFileInChI) # Not yet implemented!
def verifyOutputFile(self): """ Check's that an output file exists and was successful. Returns a boolean flag that states whether a successful MOPAC simulation already exists for the molecule with the given (augmented) InChI Key. The definition of finding a successful simulation is based on these criteria: 1) finding an output file with the file name equal to the InChI Key 2) NOT finding any of the keywords that are denote a calculation failure 3) finding all the keywords that denote a calculation success. 4) finding a match between the InChI of the given molecule and the InchI found in the calculation files 5) checking that the optimized geometry, when connected by single bonds, is isomorphic with self.molecule (converted to single bonds) If any of the above criteria is not matched, False will be returned. If all succeed, then it will return True. """ if not os.path.exists(self.outputFilePath): logging.debug("Output file {0} does not (yet) exist.".format( self.outputFilePath)) return False InChIFound = False #flag (1 or 0) indicating whether an InChI was found in the log file # Initialize dictionary with "False"s successKeysFound = dict([(key, False) for key in self.successKeys]) with open(self.outputFilePath) as outputFile: for line in outputFile: line = line.strip() for element in self.failureKeys: #search for failure keywords if element in line: logging.error( "MOPAC output file contains the following error: {0}" .format(element)) return False for element in self.successKeys: #search for success keywords if element in line: successKeysFound[element] = True if "InChI=" in line: logFileInChI = line #output files should take up to 240 characters of the name in the input file InChIFound = True if self.uniqueIDlong in logFileInChI: pass elif self.uniqueIDlong.startswith(logFileInChI): logging.info( "InChI too long to check, but beginning matches so assuming OK." ) else: logging.warning( "InChI in log file ({0}) didn't match that in geometry ({1})." .format(logFileInChI, self.uniqueIDlong)) # Use only up to first 80 characters to match due to MOPAC bug which deletes 81st character of InChI string if self.uniqueIDlong.startswith(logFileInChI[:80]): logging.warning( "but the beginning matches so it's probably just a truncation problem." ) # Check that ALL 'success' keywords were found in the file. if not all(successKeysFound.values()): logging.error( 'Not all of the required keywords for success were found in the output file!' ) return False if not InChIFound: logging.error( "No InChI was found in the MOPAC output file {0}".format( self.outputFilePath)) return False # Compare the optimized geometry to the original molecule qmData = self.parse() cclibMol = Molecule() cclibMol.fromXYZ(qmData.atomicNumbers, qmData.atomCoords.value) testMol = self.molecule.toSingleBonds() if not cclibMol.isIsomorphic(testMol): logging.info( "Incorrect connectivity for optimized geometry in file {0}". format(self.outputFilePath)) return False logging.info("Successful {1} quantum result in {0}".format( self.outputFilePath, self.__class__.__name__)) return True
def calculate_conformer(self, conformer, calculator): if isinstance(calculator, Gaussian): calc = calculator.get_conformer_calc(conformer=conformer, convergence='Tight') else: calc = calculator.get_conformer_calc(conformer=conformer) scratch = calculator.scratch scratch_dir = os.path.join(calculator.scratch, "species", conformer.smiles, "conformers") f = calc.label + ".log" if not os.path.exists(os.path.join(scratch_dir, f)): logging.info("Submitting conformer calculation for {}".format( calc.label)) label = self.submit_conformer(conformer, calc, "general") while not self.check_complete(label): time.sleep(15) else: logging.info( "It appears that we already have a complete log file for {}". format(calc.label)) complete, converged = calculator.verify_output_file( os.path.join(scratch_dir, f)) if not complete: logging.info( "It seems that the file never completed for {} completed, running it again" .format(calc.label)) label = self.submit_conformer(conformer, calc, "general") while not self.check_complete(label): time.sleep(15) complete, converged = calculator.verify_output_file( os.path.join(scratch_dir, f)) if (complete and converged): logging.info("{} was successful and was validated!".format( calc.label)) atoms = self.read_log(os.path.join(scratch_dir, f)) starting_molecule = RMGMolecule(SMILES=conformer.smiles) starting_molecule = starting_molecule.toSingleBonds() test_molecule = RMGMolecule() test_molecule.fromXYZ(atoms.arrays["numbers"], atoms.arrays["positions"]) if not starting_molecule.isIsomorphic(test_molecule): logging.info( "Output geometry of {} is not isomorphic with input geometry" .format(calc.label)) result = False else: logging.info("{} was successful and was validated!".format( calc.label)) result = True if not complete: logging.info("It appears that {} was killed prematurely".format( calc.label)) result = False elif not converged: logging.info("{} did not converge".format(calc.label)) result = False if isinstance(calculator, Gaussian): if not calc.convergence.lower() in [ "tight", "verytight", "loose" ]: logging.info("{} failed QM optimization".format( calc.label)) else: logging.info( "Resubmitting {} with default convergence criteria". format(calc.label)) atoms = self.read_log(os.path.join(scratch_dir, f)) conformer.ase_molecule = atoms conformer.update_coords_from("ase") calc = calculator.get_conformer_calc(conformer, convergence="") logging.info( "Removing the old log file that didn't converge, restarting from last geometry" ) os.remove(os.path.join(scratch_dir, f)) label = self.submit_conformer(conformer, calc, "general") while not self.check_complete(label): time.sleep(15) scratch_dir = os.path.join(calculator.scratch, "species", conformer.smiles, "conformers") f = calc.label + ".log" if not os.path.exists(os.path.join(scratch_dir, f)): logging.info( "It seems that {} was never run...".format( calc.label)) result = False complete, converged = calculator.verify_output_file( os.path.join(scratch_dir, f)) if not complete: logging.info( "It appears that {} was killed prematurely".format( calc.label)) result = False elif not converged: logging.info("{} failed second QM optimization".format( calc.label)) result = False else: atoms = self.read_log(os.path.join(scratch_dir, f)) starting_molecule = RMGMolecule( SMILES=conformer.smiles) starting_molecule = starting_molecule.toSingleBonds() test_molecule = RMGMolecule() test_molecule.fromXYZ(atoms.arrays["numbers"], atoms.arrays["positions"]) if not starting_molecule.isIsomorphic(test_molecule): logging.info( "Output geometry of {} is not isomorphic with input geometry" .format(calc.label)) result = False else: logging.info( "{} was successful and was validated!".format( calc.label)) result = True if not result: fail_dir = os.path.join(scratch_dir, "failures") try: os.makedirs(os.path.join(scratch_dir, "failures")) except OSError: logging.info("{} already exists...".format(fail_dir)) move(os.path.join(scratch_dir, f), os.path.join(scratch_dir, "failures", f)) return False return True
def verifyOutputFile(self): """ Check's that an output file exists and was successful. Returns a boolean flag that states whether a successful MOPAC simulation already exists for the molecule with the given (augmented) InChI Key. The definition of finding a successful simulation is based on these criteria: 1) finding an output file with the file name equal to the InChI Key 2) NOT finding any of the keywords that are denote a calculation failure 3) finding all the keywords that denote a calculation success. 4) finding a match between the InChI of the given molecule and the InchI found in the calculation files 5) checking that the optimized geometry, when connected by single bonds, is isomorphic with self.molecule (converted to single bonds) If any of the above criteria is not matched, False will be returned. If all succeed, then it will return True. """ if not os.path.exists(self.outputFilePath): logging.debug("Output file {0} does not (yet) exist.".format( self.outputFilePath)) return False InChIMatch = False #flag (1 or 0) indicating whether the InChI in the file matches InChIaug this can only be 1 if InChIFound is also 1 InChIFound = False #flag (1 or 0) indicating whether an InChI was found in the log file # Initialize dictionary with "False"s successKeysFound = dict([(key, False) for key in self.successKeys]) with open(self.outputFilePath) as outputFile: for line in outputFile: line = line.strip() for element in self.failureKeys: #search for failure keywords if element in line: logging.error( "MOPAC output file contains the following error: {0}" .format(element)) return False for element in self.successKeys: #search for success keywords if element in line: successKeysFound[element] = True if "InChI=" in line: logFileInChI = line #output files should take up to 240 characters of the name in the input file InChIFound = True if self.uniqueIDlong in logFileInChI: InChIMatch = True else: logging.warning( "InChI in log file ({0}) didn't match that in geometry ({1})." .format(logFileInChI, self.uniqueIDlong)) # Use only up to first 80 characters to match due to MOPAC bug which deletes 81st character of InChI string if self.uniqueIDlong.startswith(logFileInChI[:80]): logging.warning( "but the beginning matches so it's probably just a truncation problem." ) InChIMatch = True # Check that ALL 'success' keywords were found in the file. if not all(successKeysFound.values()): logging.error( 'Not all of the required keywords for success were found in the output file!' ) return False if not InChIFound: logging.error( "No InChI was found in the MOPAC output file {0}".format( self.outputFilePath)) return False if InChIMatch: # Compare the optimized geometry to the original molecule parser = cclib.parser.Mopac(self.outputFilePath) parser.logger.setLevel( logging.ERROR ) #cf. http://cclib.sourceforge.net/wiki/index.php/Using_cclib#Additional_information cclibData = parser.parse() cclibMol = Molecule() cclibMol.fromXYZ(cclibData.atomnos, cclibData.atomcoords[-1]) testMol = self.molecule.toSingleBonds() if cclibMol.isIsomorphic(testMol): logging.info( "Successful MOPAC quantum result found in {0}".format( self.outputFilePath)) # " + self.molfile.name + " ("+self.molfile.InChIAug+") has been found. This log file will be used.") return True else: logging.info( "Incorrect connectivity for optimized geometry in file {0}" .format(self.outputFilePath)) # " + self.molfile.name + " ("+self.molfile.InChIAug+") has been found. This log file will be used.") return False #InChIs do not match (most likely due to limited name length mirrored in log file (240 characters), but possibly due to a collision) return self.checkForInChiKeyCollision( logFileInChI) # Not yet implemented!
def validate_irc(self, calc=None): """ A method to verify an IRC calc """ assert "irc" in calc.label, "The calculator provided is not an IRC calculator" reaction_label = calc.label.split("_irc")[0] logging.info("Validating IRC file...") irc_path = os.path.join(calc.scratch, calc.label + ".log") if not os.path.exists(irc_path): logging.info("It seems that the IRC claculation has not been run.") return False f = open(irc_path, "r") file_lines = f.readlines()[-5:] completed = False for file_line in file_lines: if "Normal termination" in file_line: logging.info("IRC successfully ran") completed = True if not completed: logging.info("IRC failed... could not be validated...") return False pth1 = list() steps = list() with open(irc_path) as outputFile: for line in outputFile: line = line.strip() if line.startswith('Point Number:'): if int(line.split()[2]) > 0: if int(line.split()[-1]) == 1: ptNum = int(line.split()[2]) pth1.append(ptNum) else: pass elif line.startswith('# OF STEPS ='): numStp = int(line.split()[-1]) steps.append(numStp) # This indexes the coordinate to be used from the parsing if steps == []: logging.error('No steps taken in the IRC calculation!') return False else: pth1End = sum(steps[:pth1[-1]]) # Compare the reactants and products ircParse = ccread(irc_path) # cf. # http://cclib.sourceforge.net/wiki/index.php/Using_cclib#Additional_information atomcoords = ircParse.atomcoords atomnos = ircParse.atomnos # Convert the IRC geometries into RMG molecules # We don't know which is reactant or product, so take the two at the end of the # paths and compare to the reactants and products mol1 = RMGMolecule() mol1.fromXYZ(atomnos, atomcoords[pth1End]) mol2 = RMGMolecule() mol2.fromXYZ(atomnos, atomcoords[-1]) testReaction = RMGReaction( reactants=mol1.split(), products=mol2.split(), ) r, p = reaction_label.split("_") reactants = [] products = [] for react in r.split("+"): react = RMGMolecule(SMILES=react) reactants.append(react) for prod in p.split("+"): prod = RMGMolecule(SMILES=prod) products.append(prod) possible_reactants = [] possible_products = [] for reactant in reactants: possible_reactants.append( reactant.generate_resonance_structures()) for product in products: possible_products.append( product.generate_resonance_structures()) possible_reactants = list(itertools.product(*possible_reactants)) possible_products = list(itertools.product(*possible_products)) for possible_reactant in possible_reactants: reactant_list = [] for react in possible_reactant: reactant_list.append(react.toSingleBonds()) for possible_product in possible_products: product_list = [] for prod in possible_product: product_list.append(prod.toSingleBonds()) targetReaction = RMGReaction(reactants=list(reactant_list), products=list(product_list)) if targetReaction.isIsomorphic(testReaction): logging.info("IRC calculation was successful!") return True logging.info("IRC calculation failed for {} :(".format(calc.label)) return False
def verifyOutputFile(self): """ Check's that an output file exists and was successful. Returns a boolean flag that states whether a successful GAUSSIAN simulation already exists for the molecule with the given (augmented) InChI Key. The definition of finding a successful simulation is based on these criteria: 1) finding an output file with the file name equal to the InChI Key 2) NOT finding any of the keywords that are denote a calculation failure 3) finding all the keywords that denote a calculation success. 4) finding a match between the InChI of the given molecule and the InchI found in the calculation files 5) checking that the optimized geometry, when connected by single bonds, is isomorphic with self.molecule (converted to single bonds) If any of the above criteria is not matched, False will be returned. If all are satisfied, it will return True. """ if not os.path.exists(self.outputFilePath): logging.info("Output file {0} does not exist.".format( self.outputFilePath)) return False InChIMatch = False #flag (1 or 0) indicating whether the InChI in the file matches InChIaug this can only be 1 if InChIFound is also 1 InChIFound = False #flag (1 or 0) indicating whether an InChI was found in the log file # Initialize dictionary with "False"s successKeysFound = dict([(key, False) for key in self.successKeys]) with open(self.outputFilePath) as outputFile: for line in outputFile: line = line.strip() for element in self.failureKeys: #search for failure keywords if element in line: logging.error( "Gaussian output file contains the following error: {0}" .format(element)) return False for element in self.successKeys: #search for success keywords if element in line: successKeysFound[element] = True if line.startswith("InChI="): logFileInChI = line #output files should take up to 240 characters of the name in the input file InChIFound = True if logFileInChI == self.geometry.uniqueIDlong: InChIMatch = True elif self.geometry.uniqueIDlong.startswith(logFileInChI): logging.info( "InChI too long to check, but beginning matches so assuming OK." ) InChIMatch = True else: logging.warning( "InChI in log file ({0}) didn't match that in geometry ({1})." .format(logFileInChI, self.geometry.uniqueIDlong)) if self.geometry.uniqueIDlong.startswith(logFileInChI): logging.warning( "but the beginning matches so it's probably just a truncation problem." ) InChIMatch = True # Check that ALL 'success' keywords were found in the file. if not all(successKeysFound.values()): logging.error( 'Not all of the required keywords for success were found in the output file!' ) return False if not InChIFound: logging.error( "No InChI was found in the Gaussian output file {0}".format( self.outputFilePath)) return False if not InChIMatch: #InChIs do not match (most likely due to limited name length mirrored in log file (240 characters), but possibly due to a collision) return self.checkForInChiKeyCollision( logFileInChI) # Not yet implemented! # Compare the optimized geometry to the original molecule qmData = self.parse() cclibMol = Molecule() cclibMol.fromXYZ(qmData.atomicNumbers, qmData.atomCoords.value) testMol = self.molecule.toSingleBonds() if not cclibMol.isIsomorphic(testMol): logging.info( "Incorrect connectivity for optimized geometry in file {0}". format(self.outputFilePath)) return False logging.info("Successful MOPAC quantum result found in {0}".format( self.outputFilePath)) return True
def validate_irc(self): # TODO: need to add more verification here logging.info("Validating IRC file...") irc_path = os.path.join(self.irc_calc.scratch, self.irc_calc.label + ".log") if not os.path.exists(irc_path): logging.info( "It seems that the file was `fixed`, reading in the `fixed` version.") irc_path = irc_path.replace("left", "(").replace("right", ")") if not os.path.exists(irc_path): logging.info( "It seems that the IRC claculation has not been run.") return False f = open(irc_path, "r") file_lines = f.readlines()[-5:] completed = False for file_line in file_lines: if " Normal termination" in file_line: logging.info("IRC successfully ran") completed = True if completed == False: logging.info("IRC failed... could not be validated...") return False pth1 = list() steps = list() with open(irc_path) as outputFile: for line in outputFile: line = line.strip() if line.startswith('Point Number:'): if int(line.split()[2]) > 0: if int(line.split()[-1]) == 1: ptNum = int(line.split()[2]) pth1.append(ptNum) else: pass elif line.startswith('# OF STEPS ='): numStp = int(line.split()[-1]) steps.append(numStp) # This indexes the coordinate to be used from the parsing if steps == []: logging.error('No steps taken in the IRC calculation!') return False else: pth1End = sum(steps[:pth1[-1]]) # Compare the reactants and products ircParse = ccread(irc_path) # cf. http://cclib.sourceforge.net/wiki/index.php/Using_cclib#Additional_information atomcoords = ircParse.atomcoords atomnos = ircParse.atomnos # Convert the IRC geometries into RMG molecules # We don't know which is reactant or product, so take the two at the end of the # paths and compare to the reactants and products mol1 = Molecule() mol1.fromXYZ(atomnos, atomcoords[pth1End]) mol2 = Molecule() mol2.fromXYZ(atomnos, atomcoords[-1]) testReaction = Reaction( reactants=mol1.split(), products=mol2.split(), ) if isinstance(self.reaction.rmg_reaction.reactants[0], rmgpy.molecule.Molecule): targetReaction = Reaction( reactants=[reactant.toSingleBonds() for reactant in self.reaction.rmg_reaction.reactants], products=[product.toSingleBonds() for product in self.reaction.rmg_reaction.products], ) elif isinstance(self.reaction.rmg_reaction.reactants[0], rmgpy.species.Species): targetReaction = Reaction( reactants=[reactant.molecule[0].toSingleBonds() for reactant in self.reaction.rmg_reaction.reactants], products=[product.molecule[0].toSingleBonds() for product in self.reaction.rmg_reaction.products], ) if targetReaction.isIsomorphic(testReaction): return True else: return False
def validate_irc(self): """ A method to verify an IRC calc """ logging.info("Validating IRC file...") irc_path = os.path.join( self.directory, "ts", self.conformer.reaction_label, "irc", self.conformer.reaction_label + "_irc_" + self.conformer.direction + "_" + str(self.conformer.index) + ".log") complete, converged = self.verify_output_file(irc_path) if not complete: logging.info("It seems that the IRC claculation did not complete") return False if not converged: logging.info("The IRC calculation did not converge...") return False pth1 = list() steps = list() with open(irc_path) as outputFile: for line in outputFile: line = line.strip() if line.startswith('Point Number:'): if int(line.split()[2]) > 0: if int(line.split()[-1]) == 1: ptNum = int(line.split()[2]) pth1.append(ptNum) else: pass elif line.startswith('# OF STEPS ='): numStp = int(line.split()[-1]) steps.append(numStp) # This indexes the coordinate to be used from the parsing if steps == []: logging.error('No steps taken in the IRC calculation!') return False else: pth1End = sum(steps[:pth1[-1]]) # Compare the reactants and products ircParse = ccread(irc_path) atomcoords = ircParse.atomcoords atomnos = ircParse.atomnos mol1 = RMGMolecule() mol1.fromXYZ(atomnos, atomcoords[pth1End]) mol2 = RMGMolecule() mol2.fromXYZ(atomnos, atomcoords[-1]) testReaction = RMGReaction( reactants=mol1.split(), products=mol2.split(), ) r, p = self.conformer.reaction_label.split("_") reactants = [] products = [] for react in r.split("+"): react = RMGMolecule(SMILES=react) reactants.append(react) for prod in p.split("+"): prod = RMGMolecule(SMILES=prod) products.append(prod) possible_reactants = [] possible_products = [] for reactant in reactants: possible_reactants.append( reactant.generate_resonance_structures()) for product in products: possible_products.append( product.generate_resonance_structures()) possible_reactants = list(itertools.product(*possible_reactants)) possible_products = list(itertools.product(*possible_products)) for possible_reactant in possible_reactants: reactant_list = [] for react in possible_reactant: reactant_list.append(react.toSingleBonds()) for possible_product in possible_products: product_list = [] for prod in possible_product: product_list.append(prod.toSingleBonds()) targetReaction = RMGReaction(reactants=list(reactant_list), products=list(product_list)) if targetReaction.isIsomorphic(testReaction): logging.info("IRC calculation was successful!") return True logging.info("IRC calculation failed for {} :(".format(calc.label)) return False