Beispiel #1
0
    def _parse_errors(self):
        # Q-Chem somehow failed or didn't produce a gradient file
        # Requires analysis of the Q-Chem output file
        if read_pattern(self.text, {
                "key":
                r"FileNotFoundError: \[Errno 2\] No such file or directory: '.*GRAD'"
        },
                        terminate_on_match=True).get("key") == [[]]:
            self.data["errors"].append("qchem_failure_nograd")

        # Not sure why this error arises
        # It has something to do with the constraints formed
        # Might have been fixed by recent work; keeping it for now
        if read_pattern(self.text, {
                "key":
                r"if \(C\[:\]==0\.\)\.all\(\):\nAttributeError: 'bool' object has no attribute 'all'"
        },
                        terminate_on_match=True).get("key") == [[]]:
            self.data["errors"].append("coord_constraint_bool")

        # This is a bug that has been identified by the lead developer
        # Might have been fixed in the most recent release
        if read_pattern(self.text, {
                "key": r"NameError: name 'fp' is not defined"
        },
                        terminate_on_match=True).get("key") == [[]]:
            self.data["errors"].append("product_geom_not_fixed_bug")
Beispiel #2
0
 def _check_completion_errors(self):
     """
     Parses four potential errors that can cause jobs to crash: inability to transform
     coordinates due to a bad symmetric specification, an input file that fails to pass
     inspection, and errors reading and writing files.
     """
     if read_pattern(
             self.text, {
                 "key":
                 r"Coordinates do not transform within specified threshold"
             },
             terminate_on_match=True).get('key') == [[]]:
         self.data["errors"] += ["failed_to_transform_coords"]
     elif read_pattern(
             self.text,
         {
             "key": r"The Q\-Chem input file has failed to pass inspection"
         },
             terminate_on_match=True).get('key') == [[]]:
         self.data["errors"] += ["input_file_error"]
     elif read_pattern(
             self.text, {
                 "key": r"Error opening input stream"
             },
             terminate_on_match=True).get('key') == [[]]:
         self.data["errors"] += ["failed_to_read_input"]
     elif read_pattern(
             self.text, {
                 "key": r"FileMan error: End of file reached prematurely"
             },
             terminate_on_match=True).get('key') == [[]]:
         self.data["errors"] += ["IO_error"]
     else:
         self.data["errors"] += ["unknown_error"]
Beispiel #3
0
    def _parse_initial_energies(self):

        if self.data["inputs"]["gsm_type"] == "SE_GSM":
            temp_init_energy = read_pattern(
                self.text, {
                    "single": r"\s*Initial energy is ([\-\.0-9]+)"
                },
                terminate_on_match=True).get("single")
            self.data["initial_energy"] = float(temp_init_energy[0][0])

        elif self.data["inputs"]["gsm_type"] == "DE_GSM":
            temp_init_energy = read_pattern(self.text, {
                "double":
                r"\s*Energy of the end points are ([\-\.0-9]+), ([\-\.0-9]+)",
                "double_relative":
                r"\s*relative E ([\-\.0-9]+), ([\-\.0-9]+)"
            },
                                            terminate_on_match=True)
            if temp_init_energy.get("double"):
                self.data["initial_energy_rct"] = float(
                    temp_init_energy.get("double")[0][0])
                self.data["initial_energy_pro"] = float(
                    temp_init_energy.get("double")[0][1])
                self.data["initial_relative_energy_rct"] = float(
                    temp_init_energy.get("double_relative")[0][0])
                self.data["initial_relative_energy_pro"] = float(
                    temp_init_energy.get("double_relative")[0][1])
Beispiel #4
0
    def __init__(self, filename):
        self.filename = filename
        self.data = dict()
        self.data["errors"] = list()
        self.data["warnings"] = list()
        self.text = ""
        with zopen(filename, "rt") as f:
            self.text = f.read()

        completion = read_pattern(self.text, {
            "key": r"Finished GSM!"
        },
                                  terminate_on_match=True).get("key")
        if completion is None:
            self.data["completion"] = False
        else:
            self.data["completion"] = True

        self._parse_input_values()
        self._parse_initial_energies()
        self._parse_node_opt_trajectory()

        if self.data["inputs"]["gsm_type"] == "SE_GSM":
            self._parse_driving_coordinates()
            self._parse_coordinate_trajectory()

        self._parse_opt_summary()

        if self.data["completion"]:
            self._parse_summary_info()

        self._parse_warnings()
        self._parse_errors()
Beispiel #5
0
 def read_molecule(string):
     charge = None
     spin_mult = None
     patterns = {
         "read": r"^\s*\$molecule\n\s*(read)",
         "charge": r"^\s*\$molecule\n\s*(\d+)\s+\d",
         "spin_mult": r"^\s*\$molecule\n\s*\d+\s*(\d)"
     }
     matches = read_pattern(string, patterns)
     if "read" in matches.keys():
         return "read"
     if "charge" in matches.keys():
         charge = float(matches["charge"][0][0])
     if "spin_mult" in matches.keys():
         spin_mult = int(matches["spin_mult"][0][0])
     header = r"^\s*\$molecule\n\s*\d\s*\d"
     row = r"\s*((?i)[a-z]+)\s+([\d\-\.]+)\s+([\d\-\.]+)\s+([\d\-\.]+)"
     footer = r"^\$end"
     mol_table = read_table_pattern(string,
                                    header_pattern=header,
                                    row_pattern=row,
                                    footer_pattern=footer)
     species = [val[0] for val in mol_table[0]]
     coords = [[float(val[1]), float(val[2]),
                float(val[3])] for val in mol_table[0]]
     mol = Molecule(species=species,
                    coords=coords,
                    charge=charge,
                    spin_multiplicity=spin_mult)
     return mol
Beispiel #6
0
 def _parse_warnings(self):
     temp_warnings = read_pattern(self.text, {
         "syn_addition":
         r"Warning: Not performing syn\-addition correction",
         "ff_typing":
         r"Warning: FF typing failed, cannot add VDW in path optimization",
         "complexes":
         r"Warning: Unable to optimize initial complexes",
         "canonical":
         (r"Warning: Exception raised while locating transition states:" +
          r" cannot determine how many canonical orbitals to take"),
         "lewis":
         r"mmlewis warning"
     },
                                  terminate_on_match=True)
     if temp_warnings.get("syn_addition"):
         self.data["warnings"]["syn_addition"] = True
     if temp_warnings.get("ff_typing"):
         self.data["warnings"]["ff_typing"] = True
     if temp_warnings.get("complexes"):
         self.data["warnings"]["complexes"] = True
     if temp_warnings.get("canonical"):
         self.data["warnings"]["canonical"] = True
     if temp_warnings.get("lewis"):
         self.data["warnings"]["lewis"] = True
Beispiel #7
0
    def _parse_warnings(self):
        temp_warnings = read_pattern(
            self.text, {
                "charged_molecule":
                r"\s*Warning: charge is not implemented for all level of theories\. Make sure this is correct for your package\.",
                "out_of_plane_ordering":
                r"\s*Warning: OutOfPlane atoms are the same, ordering is different",
                "last_node_not_fully_optimized":
                r"\s*Warning last node still not optimized fully",
                "possible_memory_leak":
                r"Warning: more than 100 B-matrices stored, memory leaks likely",
                "svd_failure_perturb":
                r"SVD fails, perturbing coordinates and trying again",
                "no_networkx":
                r"NetworkX cannot be imported \(topology tools won't work\)\.  Most functionality should still work though\.",
                "too_many_atoms":
                r"Warning: Large number of atoms [0-9]+, topology building may take a long time",
                "topology_broken_mol":
                r"Warning: Topology building will not work with broken molecules in nonorthogonal cells\.",
                "failed_constraint":
                r"Warning: Failed to apply Constraint",
                "redundant_constraint":
                r"Constraint [0-9]+ is almost redundant; after projection norm is [\.\-0-9]+ of original",
                "cartesian_different_weights":
                r"Warning: Cartesian[XYZ] same atoms, different weights \([0-9\.\-]+ [0-9\.\-]+\)",
                "translation_different_weights":
                r"Warning: Translation[XYZ] same atoms, different weights",
                "rotator_different_reference_positions":
                r"Warning: Rotator same atoms, different reference positions"
            })

        if temp_warnings.get("charged_molecule"):
            self.data["warnings"].append("charged_molecule")
        if temp_warnings.get("out_of_plane_ordering"):
            self.data["warnings"].append("out_of_plane_ordering")
        if temp_warnings.get("last_node_not_fully_optimized"):
            self.data["warnings"].append("last_node_not_fully_optimized")
        if temp_warnings.get("possible_memory_leak"):
            self.data["warnings"].append("possible_memory_leak")
        if temp_warnings.get("svd_failure_perturb"):
            self.data["warnings"].append("svd_failure_perturb")
        if temp_warnings.get("no_networkx"):
            self.data["warnings"].append("no_networkx")
        if temp_warnings.get("too_many_atoms"):
            self.data["warnings"].append("too_many_atoms")
        if temp_warnings.get("topology_broken_mol"):
            self.data["warnings"].append("topology_broken_mol")
        if temp_warnings.get("failed_constraint"):
            self.data["warnings"].append("failed_constraint")
        if temp_warnings.get("redundant_constraint"):
            self.data["warnings"].append("redundant_constraint")
        if temp_warnings.get("cartesian_different_weights"):
            self.data["warnings"].append("cartesian_different_weights")
        if temp_warnings.get("translation_different_weights"):
            self.data["warnings"].append("translation_different_weights")
        if temp_warnings.get("rotator_different_reference_positions"):
            self.data["warnings"].append(
                "rotator_different_reference_positions")
Beispiel #8
0
    def __init__(self, filename: str):
        """
        Args:
            filename (str): Path to AutoTS output file.
        """

        self.filename = filename
        self.data = dict()
        self.data["warnings"] = dict()
        self.data["input"] = dict()
        self.data["output"] = dict()
        self.data["errors"] = dict()
        self.text = ""
        with zopen(filename, 'rt') as f:
            self.text = f.read()

        self._parse_input()

        self._parse_calculations()

        self._parse_warnings()
        self._parse_errors()

        calculation_summary = read_pattern(self.text, {
            "key": r"Calculation Summary"
        },
                                           terminate_on_match=True).get("key")

        time = read_pattern(self.text, {
            "key":
            r"Timer \(Total AutoTS Time\) : ([0-9\.]+) secs \([0-9A-Za-z,\. ]+\)"
        },
                            terminate_on_match=True).get("key")
        if time is not None:
            self.data["walltime"] = float(time[0][0])
        else:
            self.data["walltime"] = None

        if calculation_summary is None:
            self.data["complete"] = False
        else:
            self.data["complete"] = True
            self._parse_calculation_summary()
Beispiel #9
0
    def _read_frequency_data(self):
        """
        Parses frequencies, enthalpy, entropy, and mode vectors.
        """
        temp_dict = read_pattern(
            self.text, {
                "frequencies":
                r"\s*Frequency:\s+([\d\-\.]+)(?:\s+([\d\-\.]+)(?:\s+([\d\-\.]+))*)*",
                "enthalpy":
                r"\s*Total Enthalpy:\s+([\d\-\.]+)\s+kcal/mol",
                "entropy":
                r"\s*Total Entropy:\s+([\d\-\.]+)\s+cal/mol\.K"
            })

        if temp_dict.get('enthalpy') == None:
            self.data['enthalpy'] = []
        else:
            self.data['enthalpy'] = float(temp_dict.get('enthalpy')[0][0])

        if temp_dict.get('entropy') == None:
            self.data['entropy'] = None
        else:
            self.data['entropy'] = float(temp_dict.get('entropy')[0][0])

        if temp_dict.get('frequencies') == None:
            self.data['frequencies'] = None
        else:
            temp_freqs = [
                value for entry in temp_dict.get('frequencies')
                for value in entry
            ]
            freqs = np.zeros(len(temp_freqs) - temp_freqs.count('None'))
            for ii, entry in enumerate(temp_freqs):
                if entry != 'None':
                    freqs[ii] = float(entry)
            self.data['frequencies'] = freqs

            header_pattern = r"\s*Raman Active:\s+[YESNO]+\s+(?:[YESNO]+\s+)*X\s+Y\s+Z\s+(?:X\s+Y\s+Z\s+)*"
            table_pattern = r"\s*[a-zA-Z][a-zA-Z\s]\s*([\d\-\.]+)\s*([\d\-\.]+)\s*([\d\-\.]+)\s*(?:([\d\-\.]+)\s*([\d\-\.]+)\s*([\d\-\.]+)\s*(?:([\d\-\.]+)\s*([\d\-\.]+)\s*([\d\-\.]+))*)*"
            footer_pattern = r"TransDip\s+[\d\-\.]+\s*[\d\-\.]+\s*[\d\-\.]+\s*(?:[\d\-\.]+\s*[\d\-\.]+\s*[\d\-\.]+\s*)*"
            temp_freq_mode_vecs = read_table_pattern(
                self.text, header_pattern, table_pattern, footer_pattern)
            freq_mode_vecs = np.zeros(
                shape=(len(freqs), len(temp_freq_mode_vecs[0]), 3))

            for ii, triple_FMV in enumerate(temp_freq_mode_vecs):
                for jj, line in enumerate(triple_FMV):
                    for kk, entry in enumerate(line):
                        if entry != 'None':
                            freq_mode_vecs[int(ii * 3 + math.floor(kk / 3)),
                                           jj, kk % 3] = float(entry)

            self.data["frequency_mode_vectors"] = freq_mode_vecs
Beispiel #10
0
    def _parse_calculations(self):
        temp_calcs = read_pattern(
            self.text, {
                "key": r"\([0-9]+\) jaguar run ([A-Za-z0-9_\.\-]+) -TPP [0-9]+"
            }).get("key")

        if temp_calcs is None or len(temp_calcs) == 0:
            self.data["calculations"] = None
        else:
            self.data["calculations"] = list()
            for calc in temp_calcs:
                self.data["calculations"].append(calc[0].replace(".in", ""))
Beispiel #11
0
    def _read_charge_and_multiplicity(self):
        """
        Parses charge and multiplicity.
        """
        temp_charge = read_pattern(
            self.text, {
                "key": r"\$molecule\s+([\-\d]+)\s+\d"
            },
            terminate_on_match=True).get('key')
        if temp_charge != None:
            self.data["charge"] = int(temp_charge[0][0])
        else:
            temp_charge = read_pattern(
                self.text, {
                    "key": r"Sum of atomic charges \=\s+([\d\-\.\+]+)"
                },
                terminate_on_match=True).get('key')
            if temp_charge == None:
                self.data["charge"] = None
            else:
                self.data["charge"] = int(float(temp_charge[0][0]))

        temp_multiplicity = read_pattern(
            self.text, {
                "key": r"\$molecule\s+[\-\d]+\s+(\d)"
            },
            terminate_on_match=True).get('key')
        if temp_multiplicity != None:
            self.data["multiplicity"] = int(temp_multiplicity[0][0])
        else:
            temp_multiplicity = read_pattern(
                self.text, {
                    "key": r"Sum of spin\s+charges \=\s+([\d\-\.\+]+)"
                },
                terminate_on_match=True).get('key')
            if temp_multiplicity == None:
                self.data["multiplicity"] = 1
            else:
                self.data["multiplicity"] = int(
                    float(temp_multiplicity[0][0])) + 1
Beispiel #12
0
    def _parse_errors(self):
        temp_errors = read_pattern(self.text, {
            "lewis":
            r"FATAL mmlewis error: Problems remain with the following atoms:",
            "canonical":
            (r"A fatal error occurred: cannot determine how many canonical " +
             r"orbitals to take")
        },
                                   terminate_on_match=True)

        if temp_errors.get("lewis"):
            self.data["errors"]["lewis"] = True
        if temp_errors.get("canonical"):
            self.data["errors"]["canonical"] = True

        failed_jobs = read_pattern(
            self.text,
            {"key": r"Job failure\(s\)\nJobname: ([A-Za-z0-9\-\._]+)"})
        if failed_jobs.get("key") is not None:
            self.data["failed_jobs"] = list()
            for failed_job in failed_jobs.get("key"):
                self.data["failed_jobs"].append(failed_job[0])
Beispiel #13
0
    def _read_single_point_data(self):
        """
        Parses final free energy information from single-point calculations.
        """
        temp_dict = read_pattern(
            self.text, {
                "final_energy":
                    r"\s*SCF\s+energy in the final basis set\s+=\s*([\d\-\.]+)"
            })

        if temp_dict.get('final_energy') == None:
            self.data['final_energy_sp'] = None
        else:
            self.data['final_energy_sp'] = float(temp_dict.get('final_energy')[-1][0])
Beispiel #14
0
 def _check_optimization_errors(self):
     """
     Parses three potential optimization errors: failing to converge within the allowed number
     of optimization cycles, failure to determine the lamda needed to continue, and inconsistent
     size of MO files due to a linear dependence in the AO basis.
     """
     if read_pattern(
             self.text, {
                 "key": r"MAXIMUM OPTIMIZATION CYCLES REACHED"
             },
             terminate_on_match=True).get('key') == [[]]:
         self.data["errors"] += ["out_of_opt_cycles"]
     elif read_pattern(
             self.text, {
                 "key": r"UNABLE TO DETERMINE Lamda IN FormD"
             },
             terminate_on_match=True).get('key') == [[]]:
         self.data["errors"] += ["unable_to_determine_lamda"]
     elif read_pattern(
             self.text, {
                 "key": r"Inconsistent size for SCF MO coefficient file"
             },
             terminate_on_match=True).get('key') == [[]]:
         self.data["errors"] += ["linear_dependent_basis"]
Beispiel #15
0
 def read_opt(string):
     patterns = {
         "CONSTRAINT": r"^\s*CONSTRAINT",
         "FIXED": r"^\s*FIXED",
         "DUMMY": r"^\s*DUMMY",
         "CONNECT": r"^\s*CONNECT"
     }
     opt_matches = read_pattern(string, patterns)
     opt_sections = [key for key in opt_matches.keys()]
     opt = {}
     if "CONSTRAINT" in opt_sections:
         c_header = r"^\s*CONSTRAINT\n"
         c_row = r"(\w.*)\n"
         c_footer = r"^\s*ENDCONSTRAINT\n"
         c_table = read_table_pattern(string,
                                      header_pattern=c_header,
                                      row_pattern=c_row,
                                      footer_pattern=c_footer)
         opt["CONSTRAINT"] = [val[0] for val in c_table[0]]
     if "FIXED" in opt_sections:
         f_header = r"^\s*FIXED\n"
         f_row = r"(\w.*)\n"
         f_footer = r"^\s*ENDFIXED\n"
         f_table = read_table_pattern(string,
                                      header_pattern=f_header,
                                      row_pattern=f_row,
                                      footer_pattern=f_footer)
         opt["FIXED"] = [val[0] for val in f_table[0]]
     if "DUMMY" in opt_sections:
         d_header = r"^\s*DUMMY\n"
         d_row = r"(\w.*)\n"
         d_footer = r"^\s*ENDDUMMY\n"
         d_table = read_table_pattern(string,
                                      header_pattern=d_header,
                                      row_pattern=d_row,
                                      footer_pattern=d_footer)
         opt["DUMMY"] = [val[0] for val in d_table[0]]
     if "CONNECT" in opt_sections:
         cc_header = r"^\s*CONNECT\n"
         cc_row = r"(\w.*)\n"
         cc_footer = r"^\s*ENDCONNECT\n"
         cc_table = read_table_pattern(string,
                                       header_pattern=cc_header,
                                       row_pattern=cc_row,
                                       footer_pattern=cc_footer)
         opt["CONNECT"] = [val[0] for val in cc_table[0]]
     return opt
Beispiel #16
0
 def find_sections(string):
     patterns = {"sections": r"^\s*?\$([a-z]+)", "multiple_jobs": r"(@@@)"}
     matches = read_pattern(string, patterns)
     # list of the sections present
     sections = [val[0] for val in matches["sections"]]
     # remove end from sections
     sections = [sec for sec in sections if sec != 'end']
     # this error should be replaced by a multi job read function when it is added
     if "multiple_jobs" in matches.keys():
         raise ValueError(
             "Output file contains multiple qchem jobs please parse separately"
         )
     if "molecule" not in sections:
         raise ValueError("Output file does not contain a molecule section")
     if "rem" not in sections:
         raise ValueError("Output file does not contain a rem section")
     return sections
Beispiel #17
0
    def _read_pcm_information(self):
        """
        Parses information from PCM solvent calculations.
        """

        temp_dict = read_pattern(
            self.text, {
                "g_electrostatic": r"\s*G_electrostatic\s+=\s+([\d\-\.]+)\s+hartree\s+=\s+([\d\-\.]+)\s+kcal/mol\s*",
                "g_cavitation": r"\s*G_cavitation\s+=\s+([\d\-\.]+)\s+hartree\s+=\s+([\d\-\.]+)\s+kcal/mol\s*",
                "g_dispersion": r"\s*G_dispersion\s+=\s+([\d\-\.]+)\s+hartree\s+=\s+([\d\-\.]+)\s+kcal/mol\s*",
                "g_repulsion": r"\s*G_repulsion\s+=\s+([\d\-\.]+)\s+hartree\s+=\s+([\d\-\.]+)\s+kcal/mol\s*",
                "total_contribution_pcm": r"\s*Total\s+=\s+([\d\-\.]+)\s+hartree\s+([\d\-\.]+)\s+kcal/mol\s*",
                "total_free_energy_pcm": r"\s*Total Free Energy \(H0 \+ V/2 \+ non-elec\)\s+=\s+([\d\-\.]+)\s+hartree\s*\n\s+=\s+([\d\-\.]+)\s+kcal/mol\s*"
            }
        )

        if temp_dict.get("g_electrostatic") is None:
            self.data["g_electrostatic"] = []
        else:
            self.data["g_electrostatic"] = float(temp_dict.get("g_electrostatic")[0][0])

        if temp_dict.get("g_cavitation") is None:
            self.data["g_cavitation"] = []
        else:
            self.data["g_cavitation"] = float(temp_dict.get("g_cavitation")[0][0])

        if temp_dict.get("g_dispersion") is None:
            self.data["g_dispersion"] = []
        else:
            self.data["g_dispersion"] = float(temp_dict.get("g_dispersion")[0][0])

        if temp_dict.get("g_repulsion") is None:
            self.data["g_repulsion"] = []
        else:
            self.data["g_repulsion"] = float(temp_dict.get("g_repulsion")[0][0])

        if temp_dict.get("total_contribution_pcm") is None:
            self.data["total_contribution_pcm"] = []
        else:
            self.data["total_contribution_pcm"] = float(temp_dict.get("total_contribution_pcm")[0][0])

        if temp_dict.get("total_free_energy_pcm") is None:
            self.data["total_free_energy_pcm"] = []
        else:
            self.data["total_free_energy_pcm"] = float(temp_dict.get("total_free_energy_pcm")[0][0])
Beispiel #18
0
    def _parse_driving_coordinates(self):
        temp_coords = read_pattern(self.text, {
            "key":
            r"driving coordinates \[((\['(ADD|BREAK|ANGLE|TORSION|OOP)', ([0-9]+,? ?)+\],? ?)+)\]"
        },
                                   terminate_on_match=True).get("key")

        self.data["driving_coords"] = dict()
        self.data["driving_coords"]["add"] = list()
        self.data["driving_coords"]["break"] = list()
        self.data["driving_coords"]["angle"] = list()
        self.data["driving_coords"]["torsion"] = list()
        self.data["driving_coords"]["out_of_plane"] = list()

        coord_sets = temp_coords[0][0].split("], [")
        for coord_set in coord_sets:
            tokens = coord_set.strip("[]").split(", ")
            self.data["driving_coords"][tokens[0].strip("'").lower()].append(
                tuple([int(e) for e in tokens[1:]]))
Beispiel #19
0
    def _parse_summary_info(self):
        temp_summary = read_pattern(
            self.text, {
                "ts_energy": r"\s*TS energy: ([\.\-0-9]+)",
                "absolute_ts_energy":
                r"\s*absolute energy TS node ([\.\-0-9]+)",
                "nodes":
                r"\s*min reactant node: ([0-9]+) min product node ([0-9]+) TS node is ([0-9]+)",
                "delta_e": r"\s*Delta E is ([\.\-0-9]+)"
            })

        temp_ts_energy = temp_summary.get("ts_energy")
        if temp_ts_energy is None:
            self.data["ts_energy"] = None
        else:
            self.data["ts_energy"] = float(temp_ts_energy[0][0])

        temp_absolute_ts_energy = temp_summary.get("absolute_ts_energy")
        if temp_absolute_ts_energy is None:
            self.data["absolute_ts_energy"] = None
        else:
            self.data["absolute_ts_energy"] = float(
                temp_absolute_ts_energy[0][0])

        temp_nodes = temp_summary.get("nodes")
        if temp_nodes is None:
            self.data["min_rct_node"] = None
            self.data["min_pro_node"] = None
            self.data["ts_node"] = None
        else:
            self.data["min_rct_node"] = int(temp_nodes[0][0])
            self.data["min_pro_node"] = int(temp_nodes[0][1])
            self.data["ts_node"] = int(temp_nodes[0][2])

        temp_delta_e = temp_summary.get("delta_e")
        if temp_delta_e is None:
            self.data["delta_e"] = None
        else:
            self.data["delta_e"] = float(temp_delta_e[0][0])
Beispiel #20
0
    def _parse_input(self):
        version = read_pattern(self.text, {
            "key": r"\s+Version: ([0-9\-]+)"
        },
                               terminate_on_match=True).get('key')
        self.data["input"]["version"] = version[0][0]

        schro = read_pattern(self.text, {
            "key": r"\s+\$SCHRODINGER: ([A-Za-z0-9_\.\-/]+)"
        },
                             terminate_on_match=True).get("key")
        self.data["input"]["schrodinger_path"] = schro[0][0]

        launch_dir = read_pattern(
            self.text, {
                "key": r"\s+Launch Directory: ([A-Za-z0-9_\.\-/]+)"
            },
            terminate_on_match=True).get("key")
        self.data["input"]["launch_directory"] = launch_dir[0][0]
        run_dir = read_pattern(self.text, {
            "key": r"\s+Run Directory: ([A-Za-z0-9_\.\-/]+)"
        },
                               terminate_on_match=True).get("key")
        self.data["input"]["run_directory"] = run_dir[0][0]

        lot = read_pattern(
            self.text, {
                "key": r"\s+Level of Theory: ([A-Za-z0-9\-]+)/([A-Za-z0-9\-]+)"
            },
            terminate_on_match=True).get("key")
        self.data["input"]["functional"] = lot[0][0]
        self.data["input"]["basis"] = lot[0][1]
        solution = read_pattern(self.text, {
            "key": r"\sLevel of Theory: .*, Solution Phase"
        },
                                terminate_on_match=True).get("key")
        if solution is None:
            self.data["input"]["solution_phase"] = False
        else:
            self.data["input"]["solution_phase"] = True
Beispiel #21
0
    def _parse_coordinate_trajectory(self):
        #TODO: Hack pyGSM so that all of these return the indices associated with the coordinate
        #TODO: Also use consistent units?

        temp_coord_trajectory = read_pattern(
            self.text, {
                "add":
                r"\s*bond \(([0-9]+), ([0-9]+)\) target \(greater than\): ([\.0-9]+), current d: ([\.0-9]+) diff: [\-\.0-9]+",
                "break":
                r"s*bond \(([0-9]+), ([0-9]+)\) target \(greater than\): ([\.0-9]+), current d: ([\.0-9]+) diff: [\-\.0-9]+",
                "angle":
                r"s*anglev: ([\-\.0-9]+) align to ([\-\.0-9]+) diff(rad): [\-\.0-9]+",
                "torsion":
                r"s*current torv: ([\-\.0-9]+) align to ([\-\.0-9]+) diff(deg): [\-\.0-9]+"
            })

        # Initialize dictionary for driving coordinate trajectories
        self.data["driving_coord_trajectories"] = {
            "add": dict(),
            "break": dict(),
            "angle": dict(),
            "torsion": dict()
        }

        self.data["driving_coord_goals"] = {
            "add": dict(),
            "break": dict(),
            "angle": dict(),
            "torsion": dict()
        }

        for coord_type, coords in self.data["driving_coords"].items():
            for coord in coords:
                self.data["driving_coord_trajectories"][coord_type][
                    coord] = list()

        for add_coord in temp_coord_trajectory.get("add", list()):
            bond = (int(add_coord[0]), int(add_coord[1]))
            if bond in self.data["driving_coords"]["add"]:
                if bond not in self.data["driving_coord_goals"]["add"]:
                    self.data["driving_coord_goals"]["add"][bond] = float(
                        add_coord[2])
                self.data["driving_coord_trajectories"]["add"][bond].append(
                    float(add_coord[3]))

        for break_coord in temp_coord_trajectory.get("break", list()):
            bond = (int(break_coord[0]), int(break_coord[1]))
            if bond in self.data["driving_coords"]["break"]:
                if bond not in self.data["driving_coord_goals"]["break"]:
                    self.data["driving_coord_goals"]["break"][bond] = float(
                        break_coord[2])
                self.data["driving_coord_trajectories"]["break"][bond].append(
                    float(break_coord[3]))

        for e, ang_coord in enumerate(
                temp_coord_trajectory.get("angle", list())):
            #TODO: Fix this hack once the indices are printed for angles
            angle_ind = e % len(self.data["driving_coords"]["angle"])
            angle = self.data["driving_coords"]["angle"][angle_ind]
            if angle not in self.data["driving_coord_goals"]["angle"]:
                self.data["driving_coord_goals"]["angle"][angle] = float(
                    ang_coord[1])
            self.data["driving_coord_trajectories"]["angle"][angle].append(
                float(ang_coord[0]))

        for e, tors_coord in enumerate(
                temp_coord_trajectory.get("torsion", list())):
            #TODO: Fix this hack once the indices are printed for angles
            tors_ind = e % len(self.data["driving_coords"]["torsion"])
            tors = self.data["driving_coords"]["torsion"][tors_ind]
            if tors not in self.data["driving_coord_goals"]["torsion"]:
                self.data["driving_coord_goals"]["torsion"][tors] = float(
                    tors_coord[1])
            self.data["driving_coord_trajectories"]["torsion"][tors].append(
                float(tors_coord[0]))
Beispiel #22
0
    def __init__(self, filename):
        self.filename = filename
        self.data = dict()
        self.text = ""
        with zopen(self.filename, "rt") as f:
            self.text = f.read()

        self.data["rct"] = {
            "translation": list(),
            "rotation": list(),
            "distance": list(),
            "angle": list(),
            "torsion": list(),
            "out_of_plane": list()
        }

        self.data["ts"] = {
            "translation": list(),
            "rotation": list(),
            "distance": list(),
            "angle": list(),
            "torsion": list(),
            "out_of_plane": list()
        }

        self.data["pro"] = {
            "translation": list(),
            "rotation": list(),
            "distance": list(),
            "angle": list(),
            "torsion": list(),
            "out_of_plane": list()
        }

        # Parse for node numbers
        temp_node_numbers = read_pattern(self.text, {
            "key":
            r"Internals\s+minnodeR: ([0-9]+)\s+TSnode: ([0-9]+)\s+minnodeP: ([0-9]+)"
        },
                                         terminate_on_match=True).get("key")
        if temp_node_numbers is None:
            raise ValueError("Could not parse first line; problem with file?")
        else:
            self.data["rct_node"] = int(temp_node_numbers[0][0])
            self.data["ts_node"] = int(temp_node_numbers[0][1])
            self.data["pro_node"] = int(temp_node_numbers[0][2])

        # Parse translations
        temp_translation = read_pattern(
            self.text, {
                "key":
                r"Translation-([XYZ]) ([0-9]+)\-([0-9]+)\s+([\.\-0-9]+)\s+([\.\-0-9]+)\s+([\.\-0-9]+)"
            })
        for trans in temp_translation.get("key", []):
            direction = trans[0]
            atom_1 = int(trans[1])
            atom_2 = int(trans[2])

            self.data["rct"]["translation"].append(
                (direction, atom_1, atom_2, float(trans[3])))
            self.data["ts"]["translation"].append(
                (direction, atom_1, atom_2, float(trans[4])))
            self.data["pro"]["translation"].append(
                (direction, atom_1, atom_2, float(trans[5])))

        # Parse rotations
        temp_rotations = read_pattern(
            self.text, {
                "key":
                r"Rotation-([ABC]) ([0-9]+)\-([0-9]+)\s+([\.\-0-9]+)\s+([\.\-0-9]+)\s+([\.\-0-9]+)"
            })
        for rot in temp_rotations.get("key", []):
            direction = rot[0]
            atom_1 = int(rot[1])
            atom_2 = int(rot[2])

            self.data["rct"]["rotation"].append(
                (direction, atom_1, atom_2, float(rot[3])))
            self.data["ts"]["rotation"].append(
                (direction, atom_1, atom_2, float(rot[4])))
            self.data["pro"]["rotation"].append(
                (direction, atom_1, atom_2, float(rot[5])))

        # Parse bonds
        temp_distance = read_pattern(
            self.text, {
                "key":
                r"Distance ([0-9]+)\-([0-9]+)\s+([\.\-0-9]+)\s+([\.\-0-9]+)\s+([\.\-0-9]+)"
            })
        for dist in temp_distance.get("key", []):
            atom_1 = int(dist[0])
            atom_2 = int(dist[1])

            self.data["rct"]["distance"].append(
                (atom_1, atom_2, float(dist[2])))
            self.data["ts"]["distance"].append(
                (atom_1, atom_2, float(dist[3])))
            self.data["pro"]["distance"].append(
                (atom_1, atom_2, float(dist[4])))

        # Parse angles
        temp_angle = read_pattern(
            self.text, {
                "key":
                r"Angle ([0-9]+)\-([0-9]+)\-([0-9]+)\s+([\.\-0-9]+)\s+([\.\-0-9]+)\s+([\.\-0-9]+)"
            })
        for ang in temp_angle.get("key", []):
            atom_1 = int(ang[0])
            atom_2 = int(ang[1])
            atom_3 = int(ang[2])

            self.data["rct"]["angle"].append(
                (atom_1, atom_2, atom_3, float(ang[3])))
            self.data["ts"]["angle"].append(
                (atom_1, atom_2, atom_3, float(ang[4])))
            self.data["pro"]["angle"].append(
                (atom_1, atom_2, atom_3, float(ang[5])))

        # Parse torsions
        temp_dihedral = read_pattern(
            self.text, {
                "key":
                r"Dihedral ([0-9]+)\-([0-9]+)\-([0-9]+)\-([0-9]+)\s+([\.\-0-9]+)\s+([\.\-0-9]+)\s+([\.\-0-9]+)"
            })
        for tors in temp_dihedral.get("key", []):
            atom_1 = int(tors[0])
            atom_2 = int(tors[1])
            atom_3 = int(tors[2])
            atom_4 = int(tors[3])

            self.data["rct"]["torsion"].append(
                (atom_1, atom_2, atom_3, atom_4, float(tors[4])))
            self.data["ts"]["torsion"].append(
                (atom_1, atom_2, atom_3, atom_4, float(tors[5])))
            self.data["pro"]["torsion"].append(
                (atom_1, atom_2, atom_3, atom_4, float(tors[6])))

        # Parse out-of-plane angles
        temp_oop = read_pattern(
            self.text, {
                "key":
                r"Out\-of\-Plane ([0-9]+)\-([0-9]+)\s+([\.\-0-9]+)\s+([\.\-0-9]+)\s+([\.\-0-9]+)"
            })
        for oop in temp_oop.get("key", []):
            atom_1 = int(oop[0])
            atom_2 = int(oop[1])
            atom_3 = int(oop[2])
            atom_4 = int(oop[3])

            self.data["rct"]["torsion"].append(
                (atom_1, atom_2, atom_3, atom_4, float(oop[4])))
            self.data["ts"]["torsion"].append(
                (atom_1, atom_2, atom_3, atom_4, float(oop[5])))
            self.data["pro"]["torsion"].append(
                (atom_1, atom_2, atom_3, atom_4, float(oop[6])))
Beispiel #23
0
    def _parse_opt_summary(self):
        temp_opt_summary = read_pattern(
            self.text, {
                "v_profile":
                r"\s*V_profile:((\s+[\.\-0-9]+)+)",
                "v_profile_re":
                r"s*V_profile \(after reparam\):((\s+[\.\-0-9]+)+)",
                "all_uphill":
                r"\s*all uphill\?\s+(True|False)",
                "dissociative":
                r"\s*dissociative\?\s+(True|False)",
                "min_nodes":
                r"\s*min nodes\s+\[(([0-9]+,? ?)+)\]",
                "max_nodes":
                r"\s*max nodes\s+\[(([0-9]+,? ?)+)\]",
                "emax_nmax":
                r"\s*emax and nmax in find peaks ([\.\-0-9]+),([0-9]+)"
            })

        self.data["energy_profiles"] = list()
        self.data["reparameterized_energy_profiles"] = list()
        self.data["path_uphill"] = list()
        self.data["path_dissociative"] = list()
        self.data["path_min_nodes"] = list()
        self.data["path_max_nodes"] = list()
        self.data["max_nodes"] = list()
        self.data["max_energies"] = list()

        for v_profile in temp_opt_summary.get("v_profile", []):
            this_profile = list()
            for entry in v_profile[0].split(" "):
                try:
                    this_profile.append(float(entry))
                except ValueError:
                    continue
            self.data["energy_profiles"].append(this_profile)

        for v_profile in temp_opt_summary.get("v_profile_re", []):
            this_profile = list()
            for entry in v_profile[0].split(" "):
                try:
                    this_profile.append(float(entry))
                except ValueError:
                    continue
            self.data["reparameterized_energy_profiles"].append(this_profile)

        for uphill in temp_opt_summary.get("all_uphill", []):
            if uphill[0] == "True":
                self.data["path_uphill"].append(True)
            elif uphill[0] == "False":
                self.data["path_uphill"].append(False)
            else:
                # Don't know how this would happen
                self.data["path_uphill"].append(None)

        for dissoc in temp_opt_summary.get("dissociative", []):
            if dissoc[0] == "True":
                self.data["path_dissociative"].append(True)
            elif dissoc[0] == "False":
                self.data["path_dissociative"].append(False)
            else:
                # Don't know how this would happen
                self.data["path_dissociative"].append(None)

        for min_node_set in temp_opt_summary.get("min_nodes", []):
            nodes = [int(n) for n in min_node_set[0].split(", ")]
            self.data["path_min_nodes"].append(nodes)

        for max_node_set in temp_opt_summary.get("max_nodes", []):
            nodes = [int(n) for n in max_node_set[0].split(", ")]
            self.data["path_max_nodes"].append(nodes)

        if len(self.data["path_min_nodes"]) == 0 and len(
                self.data["path_max_nodes"]) != 0:
            for i in range(len(self.data["path_max_nodes"])):
                self.data["path_min_nodes"].append([])

        if len(self.data["path_max_nodes"]) == 0 and len(
                self.data["path_min_nodes"]) != 0:
            for i in range(len(self.data["path_min_nodes"])):
                self.data["path_max_nodes"].append([])

        for maxes in temp_opt_summary.get("emax_nmax", []):
            self.data["max_nodes"].append(int(maxes[1]))
            self.data["max_energies"].append(float(maxes[0]))

        self.data["final_energy_profile"] = self.data["energy_profiles"][-1]
        self.data["final_path_uphill"] = self.data["path_uphill"][-1]
        self.data["final_path_dissociative"] = self.data["path_dissociative"][
            -1]
        self.data["final_min_nodes"] = self.data["path_min_nodes"][-1]
        self.data["final_max_nodes"] = self.data["path_max_nodes"][-1]
        self.data["final_max_node"] = self.data["max_nodes"][-1]
        self.data["final_max_energy"] = self.data["max_energies"][-1]
Beispiel #24
0
    def __init__(self, filename):
        """
        Args:
            filename (str): Filename to parse
        """
        self.filename = filename
        self.data = {}
        self.data["errors"] = []
        self.text = ""
        with zopen(filename, 'rt') as f:
            self.text = f.read()

        # Check if output file contains multiple output files. If so, print an error message and exit
        self.data["multiple_outputs"] = read_pattern(
            self.text, {
                "key": r"Job\s+\d+\s+of\s+(\d+)\s+"
            },
            terminate_on_match=True).get('key')
        if not (self.data.get('multiple_outputs') == None
                or self.data.get('multiple_outputs') == [['1']]):
            print(
                "ERROR: multiple calculation outputs found in file " +
                filename +
                ". Please instead call QCOutput.mulitple_outputs_from_file(QCOutput,'"
                + filename + "')")
            print("Exiting...")
            exit()

        # Parse the molecular details: charge, multiplicity,
        # species, and initial geometry.
        self._read_charge_and_multiplicity()
        if self.data.get('charge') != None:
            self._read_species_and_inital_geometry()

        # Check if calculation finished
        self.data["completion"] = read_pattern(
            self.text, {
                "key":
                r"Thank you very much for using Q-Chem.\s+Have a nice day."
            },
            terminate_on_match=True).get('key')

        # If the calculation finished, parse the job time.
        if self.data.get('completion', []):
            temp_timings = read_pattern(
                self.text, {
                    "key":
                    r"Total job time\:\s*([\d\-\.]+)s\(wall\)\,\s*([\d\-\.]+)s\(cpu\)"
                }).get('key')
            if temp_timings != None:
                self.data["walltime"] = float(temp_timings[0][0])
                self.data["cputime"] = float(temp_timings[0][1])
            else:
                self.data["walltime"] = 'nan'
                self.data["cputime"] = 'nan'

        # Check if calculation is unrestricted
        self.data["unrestricted"] = read_pattern(
            self.text, {
                "key":
                r"A(?:n)*\sunrestricted[\s\w\-]+SCF\scalculation\swill\sbe"
            },
            terminate_on_match=True).get('key')

        # Check if calculation uses GEN_SCFMAN, multiple potential output formats
        self.data["using_GEN_SCFMAN"] = read_pattern(
            self.text, {
                "key": r"\s+GEN_SCFMAN: A general SCF calculation manager"
            },
            terminate_on_match=True).get('key')
        if not self.data["using_GEN_SCFMAN"]:
            self.data["using_GEN_SCFMAN"] = read_pattern(
                self.text, {
                    "key": r"\s+General SCF calculation program by"
                },
                terminate_on_match=True).get('key')

        # Check if the SCF failed to converge
        if read_pattern(
                self.text, {
                    "key": r"SCF failed to converge"
                },
                terminate_on_match=True).get('key') == [[]]:
            self.data["errors"] += ["SCF_failed_to_converge"]

        # Parse the SCF
        self._read_SCF()

        # Parse the Mulliken charges
        self._read_mulliken()

        # Parse the final energy
        temp_final_energy = read_pattern(
            self.text, {
                "key": r"Final\senergy\sis\s+([\d\-\.]+)"
            }).get('key')
        if temp_final_energy == None:
            self.data["final_energy"] = None
        else:
            self.data["final_energy"] = float(temp_final_energy[0][0])

        # Parse the S2 values in the case of an unrestricted calculation
        if self.data.get('unrestricted', []):
            temp_S2 = read_pattern(self.text, {
                "key": r"<S\^2>\s=\s+([\d\-\.]+)"
            }).get('key')
            if temp_S2 == None:
                self.data["S2"] = None
            elif len(temp_S2) == 1:
                self.data["S2"] = float(temp_S2[0][0])
            else:
                real_S2 = np.zeros(len(temp_S2))
                for ii, entry in enumerate(temp_S2):
                    real_S2[ii] = float(entry[0])
                self.data["S2"] = real_S2

        # Check if the calculation is a geometry optimization. If so, parse the relevant output
        self.data["optimization"] = read_pattern(
            self.text, {
                "key": r"(?i)\s*job(?:_)*type\s*(?:=)*\s*opt"
            }).get('key')
        if self.data.get('optimization', []):
            temp_energy_trajectory = read_pattern(
                self.text, {
                    "key": r"\sEnergy\sis\s+([\d\-\.]+)"
                }).get('key')
            if temp_energy_trajectory == None:
                self.data["energy_trajectory"] = []
            else:
                real_energy_trajectory = np.zeros(len(temp_energy_trajectory))
                for ii, entry in enumerate(temp_energy_trajectory):
                    real_energy_trajectory[ii] = float(entry[0])
                self.data["energy_trajectory"] = real_energy_trajectory
                self._read_optimized_geometry()
                # Then, if no optimized geometry or z-matrix is found, and no errors have been previously
                # idenfied, check to see if the optimization failed to converge or if Lambda wasn't able
                # to be determined. Also, if there is an energy trajectory, read the last geometry in the
                # optimization trajectory for use in the next input file.
                if len(self.data.get("errors")) == 0 and len(
                        self.data.get('optimized_geometry')) == 0 and len(
                            self.data.get('optimized_zmat')) == 0:
                    self._check_optimization_errors()
                    self._read_last_geometry()

        # Check if the calculation contains a constraint in an $opt section.
        self.data["opt_constraint"] = read_pattern(self.text, {
            "key": r"\$opt\s+CONSTRAINT"
        }).get('key')
        if self.data.get('opt_constraint'):
            temp_constraint = read_pattern(
                self.text, {
                    "key":
                    r"Constraints and their Current Values\s+Value\s+Constraint\s+(\w+)\:\s+([\d\-\.]+)\s+([\d\-\.]+)\s+([\d\-\.]+)\s+([\d\-\.]+)\s+([\d\-\.]+)\s+([\d\-\.]+)"
                }).get('key')
            if temp_constraint != None:
                self.data["opt_constraint"] = temp_constraint[0]
                if float(self.data.get('opt_constraint')[5]) != float(
                        self.data.get('opt_constraint')[6]):
                    if abs(float(self.data.get('opt_constraint')[5])) != abs(
                            float(self.data.get('opt_constraint')[6])):
                        raise ValueError(
                            "ERROR: Opt section value and constraint should be the same!"
                        )
                    elif abs(float(
                            self.data.get('opt_constraint')[5])) not in [
                                0.0, 180.0
                            ]:
                        raise ValueError(
                            "ERROR: Opt section value and constraint can only differ by a sign at 0.0 and 180.0!"
                        )

        # Check if the calculation is a frequency analysis. If so, parse the relevant output
        self.data["frequency_job"] = read_pattern(
            self.text, {
                "key": r"(?i)\s*job(?:_)*type\s*(?:=)*\s*freq"
            },
            terminate_on_match=True).get('key')
        if self.data.get('frequency_job', []):
            self._read_frequency_data()

        # Check if the calculation is a single-point analysis. If so, parse the relevant output
        self.data["single_point_job"] = read_pattern(
            self.text, {
                "key": r"(?i)\s*job(?:_)*type\s*(?:=)*\s*sp"
            },
            terminate_on_match=True).get("key")
        if self.data.get("single_point_job", []):
            self._read_single_point_data()

        # If the calculation did not finish and no errors have been identified yet, check for other errors
        if not self.data.get('completion',
                             []) and self.data.get("errors") == []:
            self._check_completion_errors()