"""
A class for parsing of QSite output files.
This module provides a class `QSiteOutput` that holds the information from
a QSite run.
"""
# Copyright Schrodinger, LLC. All rights reserved.
from schrodinger.application.jaguar.jaguar_diff import _FLOAT_PRECISION
from schrodinger.application.jaguar.jaguar_diff import CaseInsensitiveString
# Import various classes needed for
from schrodinger.application.jaguar.output import JaguarOutput
from schrodinger.application.jaguar.results import JaguarResults
from schrodinger.application.jaguar.results import _Attribute
from schrodinger.application.jaguar.textparser import TextParser
from schrodinger.application.jaguar.textparser import callback as jcallback
[docs]class QSiteResults(JaguarResults):
    # Note: we may or may not want to use the same energy_precision
    # value as JaguarResults.
    energy_precision = 1.e-6
    _attributes = JaguarResults._attributes + [
        _Attribute("total_energy",
                   comparison=_FLOAT_PRECISION,
                   precision="energy_precision"),
        _Attribute("total_potential_energy",
                   comparison=_FLOAT_PRECISION,
                   precision="energy_precision"),
        _Attribute("total_kinetic_energy",
                   comparison=_FLOAT_PRECISION,
                   precision="energy_precision"),
        _Attribute("bond_stretch_energy",
                   comparison=_FLOAT_PRECISION,
                   precision="energy_precision"),
        _Attribute("angle_bend_energy",
                   comparison=_FLOAT_PRECISION,
                   precision="energy_precision"),
        _Attribute("torsion_energy",
                   comparison=_FLOAT_PRECISION,
                   precision="energy_precision"),
        _Attribute("lj14_energy",
                   comparison=_FLOAT_PRECISION,
                   precision="energy_precision"),
        _Attribute("electrostatic14_energy",
                   comparison=_FLOAT_PRECISION,
                   precision="energy_precision"),
        _Attribute("lj_energy",
                   comparison=_FLOAT_PRECISION,
                   precision="energy_precision"),
        _Attribute("electrostatic_energy",
                   comparison=_FLOAT_PRECISION,
                   precision="energy_precision"),
        _Attribute("hbond_energy",
                   comparison=_FLOAT_PRECISION,
                   precision="energy_precision"),
        _Attribute("qmmm_electrostatic_energy",
                   comparison=_FLOAT_PRECISION,
                   precision="energy_precision"),
        _Attribute("qmmm_stretch_energy",
                   comparison=_FLOAT_PRECISION,
                   precision="energy_precision"),
        _Attribute("qmmm_bend_energy",
                   comparison=_FLOAT_PRECISION,
                   precision="energy_precision"),
        _Attribute("qmmm_torsion_energy",
                   comparison=_FLOAT_PRECISION,
                   precision="energy_precision"),
        _Attribute("bondchg_repulsion_energy",
                   comparison=_FLOAT_PRECISION,
                   precision="energy_precision")
    ] 
[docs]class QSiteTextParser(TextParser):
    """
    A subclass of the Jaguar output text parser that adds QSite specific
    parsing.
    """
    callback = dict(TextParser.callback) 
[docs]class QSiteOutput(JaguarOutput):
    """
    A class to hold output information from a QSite run.
    """
    _results_class = QSiteResults
    _text_parser_class = QSiteTextParser
    _attributes = JaguarOutput._attributes + [
        _Attribute("ffld", "force field", "string"),
        _Attribute("nb_cutoff", "neighbor list cutoff distance", "float"),
        _Attribute("nb_update", "neighbor list update frequency", "int"),
        _Attribute("total_atoms", "total number of atoms", "int"),
        _Attribute("jaguar_atoms", "number of Jaguar atoms", "int"),
        _Attribute("qm_atoms", "number of QM atoms", "int"),
        _Attribute("nddo_atoms", "number of NDDO atoms", "int"),
        _Attribute("nhcaps", "number of hydrogen caps", "int"),
        _Attribute("nddo_hcaps", "number of NDDO hydrogen caps", "int"),
        _Attribute("ncuts", "number of frozen-orbital cuts", "int"),
        _Attribute("nconmm", "number of constrained MM atoms", "int"),
        _Attribute("nfrzmm", "number of frozen MM atoms", "int")
    ] 
#
# Below this point, add callbacks for QSite output processing.
#
# All function callbacks must have the call signature
#
# def foo(tp, qo, m, it):
#
# where the arguments are as follows:
#  tp (QSiteTextParser) : the QSiteTextParser instance
#  qo (QSiteOutput)     : the QSiteOutput object being updated
#  m  (re match object) : the re match that caused the function to be called
#  it (file iterator)   : the file iterator for the file being parsed
#
[docs]def callback(prog, regexp=None, debug=False):
    """
    A decorator based on the Jaguar output callback decorator, but that adds
    the callbacks to the QSiteTextParser instead.
    """
    return jcallback(prog, regexp, debug, parser_class=QSiteTextParser) 
[docs]@callback("impact", r" calling (\S+)\s+atomtyping")
def ffld(tp, qo, m, it):
    qo.ffld = CaseInsensitiveString(m.group(1)) 
[docs]@callback("impact", r"^ Cutoff radius:\s+(\S+)")
def nb_cutoff(tp, qo, m, it):
    qo.nb_cutoff = float(m.group(1)) 
[docs]@callback("impact", r"^ Update frequency: every\s+(\d+) ")
def nb_update(tp, qo, m, it):
    qo.nb_update = int(m.group(1)) 
[docs]@callback("impact", r"^ Total Energy of the system\.+\s+(\S+) ")
def total_energy(tp, qo, m, it):
    qo._results.total_energy = float(m.group(1)) 
[docs]@callback("impact", r"^ Total Potential Energy\.+\s+(\S+) ")
def total_potential_energy(tp, qo, m, it):
    qo._results.total_potential_energy = float(m.group(1)) 
[docs]@callback("impact", r"^ Total Kinetic Energy\.+\s+(\S+) ")
def total_kinetic_energy(tp, qo, m, it):
    qo._results.total_kinetic_energy = float(m.group(1)) 
[docs]@callback("impact", r"^ Bond Stretch Energy\.+\s+(\S+) ")
def bond_stretch_energy(tp, qo, m, it):
    qo._results.bond_stretch_energy = float(m.group(1)) 
[docs]@callback("impact", r"^ Angle Bending Energy\.+\s+(\S+) ")
def angle_bend_energy(tp, qo, m, it):
    qo._results.angle_bend_energy = float(m.group(1)) 
[docs]@callback("impact", r"^ Torsion Angle Energy\.+\s+(\S+) ")
def torsion_energy(tp, qo, m, it):
    qo._results.torsion_energy = float(m.group(1)) 
[docs]@callback("impact", r"^ 1,4 Lennard Jones Energy\.+\s+(\S+) ")
def lj14_energy(tp, qo, m, it):
    qo._results.lj14_energy = float(m.group(1)) 
[docs]@callback("impact", r"^ 1,4 Electrostatic Energy\.+\s+(\S+) ")
def electrostatic14_energy(tp, qo, m, it):
    qo._results.electrostatic14_energy = float(m.group(1)) 
[docs]@callback("impact", r"^ Lennard Jones Energy\.+\s+(\S+) ")
def lj_energy(tp, qo, m, it):
    qo._results.lj_energy = float(m.group(1)) 
[docs]@callback("impact", r"^ Electrostatic Energy\.+\s+(\S+) ")
def electrostatic_energy(tp, qo, m, it):
    qo._results.electrostatic_energy = float(m.group(1)) 
[docs]@callback("impact", r"^ H-bond Energy\.+\s+(\S+) ")
def hbond_energy(tp, qo, m, it):
    qo._results.hbond_energy = float(m.group(1)) 
[docs]@callback("impact", r"^ QM/MM Electrostatic Energy\.+\s+(\S+) ")
def qmmm_electrostatic_energy(tp, qo, m, it):
    qo._results.qmmm_electrostatic_energy = float(m.group(1)) 
[docs]@callback("impact", r"^ QM/MM Stretch Energy\.+\s+(\S+) ")
def qmmm_stretch_energy(tp, qo, m, it):
    qo._results.qmmm_stretch_energy = float(m.group(1)) 
[docs]@callback("impact", r"^ QM/MM Bend Energy\.+\s+(\S+) ")
def qmmm_bend_energy(tp, qo, m, it):
    qo._results.qmmm_bend_energy = float(m.group(1)) 
[docs]@callback("impact", r"^ QM/MM Torsion Energy\.+\s+(\S+) ")
def qmmm_torsion_energy(tp, qo, m, it):
    qo._results.qmmm_torsion_energy = float(m.group(1)) 
[docs]@callback("pre", r"^Total number of atoms:\s+(\d+)")
def total_atoms(tp, qo, m, it):
    qo.total_atoms = int(m.group(1)) 
[docs]@callback("pre", r"^Number of atoms passed to Jaguar:\s+(\d+)")
def jaguar_atoms(tp, qo, m, it):
    qo.jaguar_atoms = int(m.group(1)) 
[docs]@callback("pre", r"^Number of atoms treated by QM:\s+(\d+)")
def qm_atoms(tp, qo, m, it):
    qo.qm_atoms = int(m.group(1)) 
[docs]@callback("pre", r"^Number of atoms treated by NDDO:\s+(\d+)")
def nddo_atoms(tp, qo, m, it):
    qo.nddo_atoms = int(m.group(1)) 
[docs]@callback("pre", r"^Number of hydrogen caps:\s+(\d+)")
def nhcaps(tp, qo, m, it):
    qo.nhcaps = int(m.group(1)) 
[docs]@callback("pre", r"^Number of NDDO hydrogen caps:\s+(\d+)")
def nddo_hcaps(tp, qo, m, it):
    qo.nddo_hcaps = int(m.group(1)) 
[docs]@callback("pre", r"^Number of frozen orbital cuts:\s+(\d+)")
def ncuts(tp, qo, m, it):
    qo.ncuts = int(m.group(1)) 
[docs]@callback("pre", r"^Number of constrained MM atoms:\s+(\d+)")
def nconmm(tp, qo, m, it):
    qo.nconmm = int(m.group(1)) 
[docs]@callback("pre", r"^Number of frozen MM atoms:\s+(\d+)")
def nfrzmm(tp, qo, m, it):
    qo.nfrzmm = int(m.group(1)) 
[docs]@callback("onee", r"^  bond-charge repulsion energy\.+\s+(\S+) ")
def bondchg_repulsion_energy(tp, qo, m, it):
    qo._results.bondchg_repulsion_energy = float(m.group(1))