Ejemplo n.º 1
0
    def q_mapsingle(self, path):
        # creates the input for qfep5 from the template and runs qfep5

        try:
            en_files = open(os.path.join(path, self._en_list_fn)).read()
        except IOError as e:
            raise QMappingError(
                "Error when reading the file containing the energy filenames '%s': %s."
                % (self._en_list_fn, str(e)))

        if not en_files:
            raise QMappingError("q_enfiles.list is empty!")
        enfiles = [
            en_file for en_file in en_files.split("\n")
            if en_file.strip() != ""
        ]

        frames = len(enfiles)
        if self._frames == None:
            self._frames = frames
        elif self._frames != frames:  # this should never happen, but in case it does, something bad has happened...
            raise QMappingError(
                "Not all replicas have the same number of frames! %d vs %d" %
                (self._frames, frames))

        for enf in enfiles:
            if not os.path.lexists(os.path.join(path, enf)):
                raise QMappingError("Energy file '%s' missing" % enf)

        s = mapfile_template.substitute(en_files=en_files,
                                        frames=frames,
                                        **self._map_parms)

        # create input and output files and open them readwrite
        inpfn = os.path.join(path, QScfg.get("files", "qfep_inp"))
        outfn = os.path.join(path, QScfg.get("files", "qfep_out"))
        with open(inpfn, 'w+') as inpf:
            with open(outfn, 'w+') as outf:
                inpf.write(s)
                inpf.seek(0)
                try:
                    p = subprocess.Popen(QScfg.get("qexec", "qfep"),
                                         stdin=inpf,
                                         stdout=outf,
                                         stderr=subprocess.PIPE,
                                         cwd=path)
                except OSError as e:
                    raise QMappingError("Problem when running qfep5: %s" % e)
                p.wait()
                err = p.stderr.read()
                if err:
                    raise QMappingError("qfep5 printed this to stderr: %s" %
                                        err)

        return outfn
Ejemplo n.º 2
0
    def __init__(
        self,
        hij,
        gas_shift,
        mapdirectories=[],  # all subdirs OR cwd in case of no subdirs
        en_list_fn=QScfg.get("files", "en_list_fn"),
        bins=QScfg.get("mapping", "bin"),
        skip=QScfg.get("mapping", "skip"),
        minpts_per_bin=QScfg.get("mapping", "minpts_per_bin"),
        temperature=QScfg.get("mapping", "temp"),
        verbose=False,
        nthreads=QScfg.get("mapping", "nthread")):

        if (subprocess.call("type " + QScfg.get("qexec", "qfep"),
                            shell=True,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE) != 0):
            raise QMappingError("\nFatal! Executable '%s' not found." %
                                QScfg.get("qexec", "qfep"))

        self._en_list_fn = en_list_fn
        self._frames = None  # set later in q_mapsingle
        self._verbose = verbose
        self._nthreads = nthreads

        if mapdirectories:
            for md in mapdirectories:
                if not os.path.lexists(md):
                    raise QMappingError("Directory %s does not exist!" % md)
        # if mapping directories were not passed in as an argument, store all directories in the current folder
        else:
            mapdirectories = sorted(
                [md for md in os.listdir(os.getcwd()) if os.path.isdir(md)])
            if self._verbose and mapdirectories:
                print "Will use these directories for mapping (use --mapdirs to change this):"
                print ", ".join(mapdirectories)

            # if there are no folders in the current working directory, map just the current one
            if not mapdirectories:
                mapdirectories = [
                    os.getcwd(),
                ]
                if self._verbose:
                    print "No subdirectories. Mapping files in current directory only."

        self._map_dirs = [os.path.abspath(md) for md in mapdirectories]
        self._map_parms = {
            "hij": hij,
            "gas_shift": gas_shift,
            "skip": skip,
            "bins": bins,
            "minpts_per_bin": minpts_per_bin,
            "kT":
            float(temperature) * float(QScfg.get("mapping", "gas_const")),
            "temperature": temperature
        }
        self._failed = []
        self._mapped = []
Ejemplo n.º 3
0
from Qpyl.common import backup_file, init_logger, get_version_full

logger = init_logger('Qpyl')

parser = argparse.ArgumentParser(description="""
Script for extracting temperatures and energies from QDyn outputs.
Mostly used for debugging.
""",
                                 add_help=False)
reqarg = parser.add_argument_group("Required")
reqarg.add_argument("outputs", nargs="+", help="Qdyn output files")
optarg = parser.add_argument_group("Optional")
optarg.add_argument("--plots_out",
                    dest="plots_out",
                    help="Output filename for plot data (default='{}')"
                    "".format(QScfg.get("files", "analysedyns_plots")),
                    default=QScfg.get("files", "analysedyns_plots"))

optarg.add_argument("--stepsize",
                    dest="stepsize",
                    default=None,
                    type=float,
                    help="If the stepsize in your log is 0.000, define it "
                    "with this flag.")

optarg.add_argument("--timeunit",
                    dest="timeunit",
                    default="ps",
                    help="Which units of time should the results be in? fs, "
                    "ps or ns? Default is ps.")
Ejemplo n.º 4
0
def gc(args):

    if not os.path.lexists(args.pdb):
        print "This file went missing: {}".format(args.pdb)
        sys.exit(1)

    if args.qmaskfile:
        try:
            qmask = open(args.qmaskfile, "r").read().split()
            if not qmask:
                raise IOError
        except IOError:
            print "Can't read '{}' or file empty".format(args.qmaskfile)
            sys.exit(1)
    else:
        qmask = None

    lambdas = []
    for lamb in args.lra_l:
        try:
            lamb = float(lamb)
            if lamb < 0 or lamb > 1:
                raise ValueError
        except ValueError:
            print "FATAL! Lambda values make no sense. 0 <= lambda <= 1 please."
            sys.exit(1)
        lambdas.append((lamb, 1 - lamb))

    calcdirs = args.dirs
    if not calcdirs:
        lsdir = os.listdir(os.getcwd())
        calcdirs = [f for f in lsdir if os.path.isdir(f)]
    if not calcdirs:
        calcdirs = [
            os.getcwd(),
        ]
        print "No subdirectories. Calculating in current directory only.\n"
    else:
        print "Will use these directories for calculating GCs (use --dirs to "\
              "change this): {}\n".format(", ".join(calcdirs))

    qgc = QGroupContrib(args.qcalc_exec, calcdirs, args.pdb,
                        QScfg.get("files", "en_list_fn"), lambdas[0],
                        lambdas[1], args.resid_first, args.resid_last,
                        args.scale_ionized, args.nthreads, qmask)

    try:
        qgc.calcall()
    except QGroupContribError as error_msg:
        print "\nMassive fail:\n{}\n".format(error_msg)
        sys.exit(1)
    except KeyboardInterrupt:
        qgc.kill_event.set()
        raise

    # writeout QCalc inputs and outputs
    if args.writeout:
        for calcdir, (qcinps, qcouts) in qgc._qcalc_io.iteritems():
            for i, qci in enumerate(qcinps):
                fn = os.path.join(calcdir, "q_calc.gc.{}.inp".format(i + 1))
                try:
                    open(fn, 'w').write(qci)
                except OSError as err:
                    print "Error when writing to {}: {}".format(fn, err)
                else:
                    print "Wrote {}".format(fn)
            for i, qco in enumerate(qcouts):
                fn = os.path.join(calcdir, "q_calc.gc.{}.out".format(i + 1))
                try:
                    open(fn, 'w').write(qco)
                except OSError as err:
                    print "Error when writing to {}: {}".format(fn, err)
                else:
                    print "Wrote {}".format(fn)

    # write out details and top 10 GCs to stdout and outfile
    if not qgc.gcs:
        top_gcs = "None, all directories failed..."
        top_gcs_reorg = "None, all directories failed..."
    else:
        top_rows = sorted(qgc.gcs_stats.get_rows(),
                          key=lambda x: -abs(x[13]))[:10]

        out_l = ["{:<10} {:>10} {:>10}".format("# Residue", "Mean", "Stdev")]

        for row in top_rows:
            rid, rn, el, elstd = row[0], row[1], row[13], row[14]

            tmp = "{}_{}".format(rn.capitalize(), rid)
            tmp2 = "{:<10} {:10.2f} {:10.2f}".format(tmp, el, elstd)
            out_l.append(tmp2)

        top_gcs = "\n".join(out_l)

        top_rows = sorted(qgc.gcs_stats.get_rows(),
                          key=lambda x: -abs(x[17]))[:10]

        out_l = ["{:<10} {:>10} {:>10}".format("# Residue", "Mean", "Stdev")]

        for row in top_rows:
            rid, rn, el, elstd = row[0], row[1], row[17], row[18]

            tmp = "{}_{}".format(rn.capitalize(), rid)
            tmp2 = "{:<10} {:10.2f} {:10.2f}".format(tmp, el, elstd)
            out_l.append(tmp2)

        top_gcs_reorg = "\n".join(out_l)

    outstr = """
{gc_details}
Top LRA (el) contributions:
{top_gcs}

Top REORG (el) contributions:
{top_gcs_reorg}
""".format(gc_details=qgc.details,
           top_gcs=top_gcs,
           top_gcs_reorg=top_gcs_reorg)

    print outstr
    fn_out = args.output_fn
    backup = backup_file(fn_out)
    if backup:
        print "# Backed up '{}' to '{}'".format(fn_out, backup)
    open(fn_out, "w").write(outstr)
    print "Wrote '{}'...".format(fn_out)

    # convert plots to json and write them out
    fn_out = args.plots_out
    plots = qgc.plotdata
    jsonenc = plotdata.PlotDataJSONEncoder(indent=2)
    backup = backup_file(fn_out)
    if backup:
        print "# Backed up '{}' to '{}'".format(fn_out, backup)
    open(fn_out, 'w').write(jsonenc.encode(plots))
    print "Wrote '{}'... (q_plot.py is your "\
          "friend)".format(fn_out)

    # writeout the pdbgc if requested
    if args.pdbgc_out:
        backup = backup_file(args.pdbgc_out)
        if backup:
            print "# Backed up '{}' to '{}'".format(args.pdbgc_out, backup)
        open(args.pdbgc_out, 'w').write(qgc.get_pdbgc())
        print "Wrote '{}'... (use Pymol/Chimera/VMD and color by occupancy "\
              "(LRA) or B-factor (reorg))".format(args.pdbgc_out)
Ejemplo n.º 5
0
def main():
    logger = init_logger('Qpyl')

    parser = argparse.ArgumentParser(description="""
    A friendly command-line interface for calculating distances, angles, rmsds,
    group contributions, etc. with Qcalc.
    """)

    subp = parser.add_subparsers(title="subcommands", dest="command")

    parser.add_argument("-v",
                        "--version",
                        action="version",
                        version=get_version_full())

    subps = {}
    subps["gc"] = subp.add_parser("gc",
                                  help="Group contribution calculation.",
                                  description="""
                                  Calculate group contributions - nonbonded
                                  Linear Response Approximation energies
                                  between (protein) residues and the 
                                  reactive Q region.""",
                                  add_help=False)

    gc_reqarg = subps["gc"].add_argument_group("Required")
    gc_reqarg.add_argument("pdb", help="PDB structure created with Qprep.")

    gc_reqarg.add_argument("resid_first",
                           type=int,
                           help="Index of first residue to be "
                           "included in the calculation.")

    gc_reqarg.add_argument("resid_last",
                           type=int,
                           help="Index of last residue to be "
                           "included in the calculation. ")

    gc_optarg = subps["gc"].add_argument_group("Optional")
    gc_optarg.add_argument("--iscale",
                           dest="scale_ionized",
                           type=float,
                           default=QScfg.get("gc", "scale_ionized"),
                           help="Scale down electrostatic interactions of "
                           "ionized residues (ASP, GLU, HIP, LYS, ARG) "
                           "(see doi:10.1021/jp962478o). Default is {}"
                           "".format(QScfg.get("gc", "scale_ionized")))

    gc_optarg.add_argument("--qmask",
                           dest="qmaskfile",
                           default=None,
                           help="File containing the Q-atom mask (line "
                           "or space separated atom indexes). By default, "
                           "this is extracted from the [atoms] section "
                           "in the FEP file.")

    def_lra_l = QScfg.get("gc", "lambdas_state1").split(",")
    gc_optarg.add_argument("--lra_l",
                           dest="lra_l",
                           nargs=2,
                           metavar=("l1", "l2"),
                           default=def_lra_l,
                           help="Specify lambdas (state 1) for GC LRA."
                           "Default is '{}'."
                           "".format(str(def_lra_l)))

    gc_optarg.add_argument("--nt",
                           dest='nthreads',
                           type=int,
                           default=QScfg.get("gc", "nthreads"),
                           help="Number of threads (default = {})"
                           "".format(QScfg.get("gc", "nthreads")))

    gc_optarg.add_argument("--plots_out",
                           dest="plots_out",
                           help="Output filename for plot data (default="
                           "'{}').".format(QScfg.get("files", "gc_plots")),
                           default=QScfg.get("files", "gc_plots"))

    gc_optarg.add_argument("--dirs",
                           dest="dirs",
                           nargs="+",
                           help="Directories to use (default is "
                           "all subdirs or current working dir).",
                           default=[])

    gc_optarg.add_argument("--out",
                           dest="output_fn",
                           help="Output filename (default='{}')."
                           "".format(QScfg.get("files", "calcs_log")),
                           default=QScfg.get("files", "calcs_log"))

    gc_optarg.add_argument("--pdbgc",
                           dest="pdbgc_out",
                           help="Output filename of PDB structure "
                           "with group contributions in place of "
                           "B-factors. Default=Don't output.",
                           default=None)

    gc_optarg.add_argument("--writeout",
                           action="store_true",
                           default=False,
                           help="Write out QCalc inputs and outputs. "
                           "Default=Don't writeout.")

    gc_optarg.add_argument("--qcalc_exec",
                           dest="qcalc_exec",
                           default=QScfg.get("qexec", "qcalc"),
                           help="qcalc executable path (default={})."
                           "".format(QScfg.get("qexec", "qcalc")))

    gc_optarg.add_argument("-h",
                           "--help",
                           action="help",
                           help="show this "
                           "help message and exit")

    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit(1)
    elif len(sys.argv) == 2 and sys.argv[1] not in [
            "-h", "--help", "-v", "--version"
    ]:
        try:
            subps[sys.argv[1]].print_help()
        except KeyError:
            print "Subcommand '{}' not available...\n".format(sys.argv[1])
        sys.exit(1)

    args = parser.parse_args()

    if args.command == "gc":
        gc(args)
Ejemplo n.º 6
0
if __name__ == "__main__":

    parser = argparse.ArgumentParser(description="""
    Useful GUI tool for plotting JSON data created by other q_tools.
    Alternatively, you can use it to export all the data to Grace format.
    """, add_help=False)
    reqarg = parser.add_argument_group("Required")
    reqarg.add_argument("plotfiles",  nargs="+",
                        help="qa.PlotData.json file(s) (up to six)")
    optarg = parser.add_argument_group("Optional")
    optarg.add_argument("--export", dest="export", nargs="*",
                        default=argparse.SUPPRESS,
                        help="Export plots in Grace format to this directory: "
                             "'{}'. Try without args, to see available plots."
                             "".format(QScfg.get("files", "plot_export_dir")))
    optarg.add_argument("-v", "--version", action="version",
                        version=get_version_full())
    optarg.add_argument("-h", "--help", action="help", help="show this "
                        "help message and exit")

    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit(1)

    args = parser.parse_args()

    if len(args.plotfiles) > 6:
        print "Currently, only six data files are supported. Deal with it..."
        sys.exit(1)
    if hasattr(args, "export") and len(args.plotfiles) > 1:
Ejemplo n.º 7
0
reqarg.add_argument("restraint",
                    help="Sequence restraints applied to topology ('top') "
                    "or relaxed structure ('relax') or "
                    "whatever is used in the relaxation input ('inp').")

optarg = parser.add_argument_group("Optional")
optarg.add_argument("--rs",
                    dest="runscript",
                    default=None,
                    help="shell runscript for Q")

optarg.add_argument("--frames",
                    dest="frames",
                    type=int,
                    help="Number of frames (31,51,101,...). Default={}."
                    "".format(QScfg.get("inputs", "fep_frames")),
                    default=QScfg.get("inputs", "fep_frames"))

optarg.add_argument("--repeats",
                    dest="repeats",
                    type=int,
                    help="number of repeats/replicas. Default={}."
                    "".format(QScfg.get("inputs", "num_repeats")),
                    default=QScfg.get("inputs", "num_repeats"))

optarg.add_argument("--fep",
                    dest="fep",
                    default=None,
                    help="FEP file (default is the one in the input file)."
                    "It can contain atom placeholders.")
Ejemplo n.º 8
0
def genfeps(fep_proc,
            relax_input,
            restraint="inp",
            pdb=None,
            fep=None,
            runscript=None,
            frames=QScfg.get("inputs", "fep_frames"),
            repeats=QScfg.get("inputs", "num_repeats"),
            fromlambda=None,
            prefix=QScfg.get("inputs", "prefix_rep"),
            first_frame_eq=False,
            logger=None):

    frames = int(frames)
    repeats = int(repeats)
    if fromlambda != None:
        fromlambda = float(fromlambda)

    if not logger:
        # log to console, only warnings
        logger = logging.getLogger(__name__)
        logger.setLevel(logging.WARNING)
        handler = logging.StreamHandler(sys.stdout)
        formatter = SpecialFormatter()
        handler.setFormatter(formatter)
        logger.addHandler(handler)

    # constants
    PREFIX_EQ = "equil_"
    PREFIX_FEP = "fep_"

    # check if files exist
    for k, v in locals().iteritems():
        if k in ['pdb', 'fep_proc', 'fep', 'top', 'runscript', 'relax_input']:
            if v and not os.path.lexists(v):
                raise QGenfepsError("File '%s' doesn't exist." % v)

    if restraint not in ["top", "relax", "inp"]:
        raise QGenfepsError(
            "Argument 'restraint' has to be either 'inp', 'top' or 'relax'")

    # find and replace atom placeholders. if not PDB was given to replace them, exit
    fep_proc_str = open(fep_proc, 'r').read()
    c = q_pdbindex.findPlaceholders(fep_proc_str)
    if c and not pdb:
        raise QGenfepsError(
            "Found placeholders, but no PDB was given (--pdb):\n%s\n" %
            ", ".join(c))
    elif c:
        logger.info("These placeholders will be replaced with atom indices: " +
                    ", ".join(c))
        try:
            fep_proc_str = q_pdbindex.convertToIndexes(fep_proc_str, pdb)
        except KeyError as e:
            raise QGenfepsError("Failed to replace placeholders: %s" % str(e))

    # make a nice header comment in each input file with the details about the arguments used
    argfep = "--fep %s" % fep if fep else ""
    argfl = "--fromlambda %s" % fromlambda if fromlambda else ""
    argrs = "--rs %s" % runscript if runscript else ""
    argpdb = "--pdb %s" % pdb if pdb else ""
    header_comment = """#
# Generated with {name}, version {version}, on {date}
# CWD: {cwd}
# CMDline: {name} {fep_proc} {relax_input} --rest {restraint} --frames {frames} --repeats {repeats} {fep} {fromlambda} {rs} {pdb}
#
""".format(name=os.path.basename(__file__),
           version=__version__,
           date=time.ctime(),
           cwd=os.getcwd(),
           fep_proc=fep_proc,
           relax_input=relax_input,
           restraint=restraint,
           frames=frames,
           repeats=repeats,
           fep=argfep,
           fromlambda=argfl,
           rs=argrs,
           pdb=argpdb)

    # get topology and fep and others from the last relaxation input
    top_file_abs, fep_file_abs, re_file_abs, rest_file = None, None, None, None
    lambda_initial = None
    try:
        c = QDynInput(open(relax_input, 'r').read())
    except QDynInputError as e:
        raise QGenfepsError(
            "There is something wrong with the given input file (%s):\n%s" %
            (relax_input, str(e)))

    di = os.path.dirname(relax_input)
    try:
        files = c.parameters["files"]
        lambda_initial = float(c.parameters["lambdas"].split()[0])
        top_file_abs = os.path.join(di, files["topology"])
        re_file_abs = os.path.join(di, files["final"])
        fep_file_abs = os.path.join(di, files["fep"])
        if "restraint" in files:
            rest_file = os.path.join(di, files["restraint"])
    except KeyError as e:
        raise QGenfepsError(
            "Parsing the relaxation input file failed, keyword missing... %s" %
            str(e))

    # check if the files actually exist
    for fn, descr in [(top_file_abs, 'topology'), (fep_file_abs, 'fep'),
                      (re_file_abs, 'final'), (rest_file, 'restraint')]:
        if fn and not os.path.lexists(fn):
            raise QGenfepsError(
                "When parsing the input, found this filename '%s' next to the '%s' command. Unfortunately, the file doesnt exist..."
                % (fn, descr))

    # change the FEP (if debugging your system, you might want to use an old relax and not waste 100M core hours when changing a soft core value in the fep)
    if fep: fep_file_abs = os.path.abspath(fep)

    # change the inital lambda (this is not recommended, the system should be properly relaxed at a particual lambda before doing FEP)
    if fromlambda != None:
        lambda_initial = float(fromlambda)
        if lambda_initial > 1.0 or lambda_initial < 0.0:
            raise QGenfepsError("Lambda value is bogus, are you on drugs?")

    # create lambda values, find the closest to the starting one and rearrange accordingly
    # [0.0, 0.02, 0.04, ... 0.98, 1.0]  for frames==51
    lambdas = [float(num) / (frames - 1) for num in xrange(0, frames)]

    # [2,]   for lambda_initial == 0.04 (or close to 0.04) and frames==51
    l_i = [
        i for i in xrange(0, frames)
        if (abs(lambdas[i] - lambda_initial) <= (1.0 / frames))
    ]
    # there should be only one
    l_i = l_i[0]
    lambda_initial = lambdas[l_i]

    # [0.02, 0.0, ] for the case of lambda_initial == 0.04 and frames == 51
    forward_lambdas = list(reversed(lambdas[0:l_i]))
    # [0.06, 0.08, ..., 1.0] for the case of lambda_initial == 0.04 and frames == 51
    backward_lambdas = lambdas[l_i + 1:]

    lambdas = [
        lambda_initial,
    ] + forward_lambdas + backward_lambdas

    # print out some useful information
    logger.info("Using restart file: %s " % os.path.relpath(re_file_abs))
    logger.info("Using topology file: %s " % os.path.relpath(top_file_abs))
    logger.info("Using FEP file: %s " % os.path.relpath(fep_file_abs))
    logger.info("Starting from lambda value (state 1): %s " % lambda_initial)
    logger.info("Number of FEP frames: %s " % frames)

    # create a temporary directory to store the files that are identical in all replicas - top, fep, runscript, relax restart, restraint file (if any)
    # and copy the common files
    TMPDIR = tempfile.mkdtemp()
    top_fn = os.path.basename(top_file_abs)
    fep_fn = os.path.basename(fep_file_abs)
    relax_re_fn = "cont_" + os.path.basename(re_file_abs)
    shutil.copy2(top_file_abs, TMPDIR)
    shutil.copy2(fep_file_abs, TMPDIR)
    shutil.copy2(re_file_abs, os.path.join(TMPDIR, relax_re_fn))
    if runscript:
        shutil.copy2(runscript, TMPDIR)
    else:
        logger.info("No Q runscript given.")

    # handle the whole restraint coordinates crap...
    # rest_file is the file from the relaxation input (if any)
    # rest_fn is the basename of the restraints file (either from input or relaxed.re.rest), or None if rest. to topology
    if restraint == "relax":
        logger.info("Restraining to: relaxation")
        rest_fn = "cont_" + os.path.basename(re_file_abs) + ".rest"
        shutil.copy2(re_file_abs, os.path.join(TMPDIR, rest_fn))
    elif restraint == "top":
        logger.info("Restraining to: topology")
        rest_fn = None
    else:  # default, from input
        if rest_file:
            logger.info("Restraining to: %s (from input)" %
                        os.path.relpath(rest_file))
            rest_fn = "cont_" + os.path.basename(rest_file)
            shutil.copy2(rest_file, TMPDIR)
        else:
            logger.info("Restraining to: topology (from input)")
            rest_fn = None

    # parse the proc file
    general_inp = []
    eq_steps_inps = [
        [],
    ]
    fep_inp = []
    script_vars = {}

    section = ""
    for line in fep_proc_str.split("\n"):
        # remove comments and strip whitespaces.
        line = re.split("#|\!", line)[0].strip()
        # empty lines are useless
        if line == "":
            continue
        # found a section
        if line[0] == "{":
            section = line.strip("{}").lower()
            continue

        if not section:
            raise QGenfepsError(
                "Parsing the procedure file failed... This line: '%s' is not inside any section:"
                % line)

        if section == "script_vars":
            c = line.split()
            var, value = c[0], " ".join(c[1:])
            script_vars[var] = value
        elif section == "general":
            general_inp.append(line)
        elif section == "steps_equil":
            if "__________" in line:
                eq_steps_inps.append([])
            else:
                eq_steps_inps[-1].append(line)
        elif section == "fep":
            fep_inp.append(line)
        else:
            raise QGenfepsError(
                "Parsing the procedure file failed: Unsupported section: '%s'"
                % (section))

    # check for steps with no parameters ( too many _________ lines ) and remove them
    for i in range(len(eq_steps_inps) - 1, -1, -1):
        if not eq_steps_inps[i]:
            eq_steps_inps.pop(i)

    # check for missing sections
    for l, n in ("general_inp", "GENERAL"), ("eq_steps_inps",
                                             "STEPS_EQUIL"), ("fep_inp",
                                                              "FEP"):
        if not l:
            raise QGenfepsError(
                "Parsing the procedure file failed: Section '%s' is missing" %
                (n))

    # join lists of lines to strings and replace the placeholders
    script_variables = sorted(script_vars.items(), reverse=True)
    gen_inp_s = "\n".join(general_inp)
    fep_inp_s = "\n".join(fep_inp)
    eq_steps_inps_s = ["\n".join(eq_step_inp) for eq_step_inp in eq_steps_inps]

    for placeholder, value in script_variables:
        gen_inp_s = gen_inp_s.replace(placeholder, value)
        fep_inp_s = fep_inp_s.replace(placeholder, value)
        for eq_step_inp_s in eq_steps_inps_s:
            eq_step_inp_s = eq_step_inp_s.replace(placeholder, value)

    ####################
    # make equil. inputs
    eq_steps = []
    for step_n, eq_step_inp_s in enumerate(eq_steps_inps_s):
        # create the files section
        final = "%s%03d_%4.3f.re" % (PREFIX_EQ, step_n, lambda_initial)
        dcd = "%s%03d_%4.3f.dcd" % (PREFIX_EQ, step_n, lambda_initial)
        files = {
            'final': final,
            'trajectory': dcd,
            'topology': top_fn,
            'fep': fep_fn
        }

        if first_frame_eq:
            files['energy'] = "%s%03d_%4.3f.en" % (PREFIX_EQ, step_n,
                                                   lambda_initial)

        if rest_fn:
            files["restraint"] = rest_fn

        if step_n != 0:
            files["restart"] = "%s%03d_%4.3f.re" % (PREFIX_EQ, step_n - 1,
                                                    lambda_initial)
        else:
            files["restart"] = relax_re_fn

        # parse the general input and update with step input and files section
        try:
            inp = QDynInput(gen_inp_s)
            inp.update(eq_step_inp_s)
            if "energy" in inp.parameters["intervals"]:
                files["energy"] = "%s%03d_%4.3f.en" % (PREFIX_EQ, step_n,
                                                       lambda_initial)
            elif first_frame_eq:
                raise QGenfepsError(
                    "Argument first_frame_eq requires the energy printout defined in the intervals section of the equilibration (e.g. 'energy   10')"
                )

            inp.update(parameters={"files": files})
            inp.update(
                parameters={
                    "lambdas": "%9.7f %9.7f" %
                    (lambda_initial, 1 - lambda_initial)
                })
        except QDynInputError as e:
            raise QGenfepsError("Problem with equil. step no. %d: %s" %
                                (step_n, str(e)))

        # get the input string
        try:
            inpstr = inp.get_string()
        except QDynInputError as e:
            raise QGenfepsError("Error in equil. step %d: %s" %
                                (step_n, str(e)))

        # check if random seed is not defined or is fixed in the first step
        if step_n == 0:
            if repeats > 1:
                if ("random_seed" not in inp.parameters["md"]
                        or int(inp.parameters["md"]["random_seed"]) > 0):
                    raise QGenfepsError(
                        "Fixed random seed (or restart velocities) works only with one repeat (others will be identical).\n\
    Please use 'random_seed   -1' in your first equilibration step to generate random random seeds."
                    )

            elif "random_seed" not in inp.parameters["md"]:
                logger.info(
                    "No random seed in first step of equilibration, using restart velocities."
                )

                if (not rest_file
                        and rest_fn) or (not rest_fn and rest_file) or (
                            rest_file and
                            (os.path.basename(rest_file) != rest_fn)):
                    logger.warning(
                        "This will not be a true continuation run! The relaxation restraint does not match yours. Use 'inp' instead of 'top' or 'relax' for the restraint."
                    )

        # append the input
        eq_steps.append(inp)

    #################
    # make FEP inputs
    en_filenames = []
    feps = []

    for step_n, lam in enumerate(lambdas):
        # create the files section
        final = "%s%03d_%4.3f.re" % (PREFIX_FEP, step_n, lam)
        dcd = "%s%03d_%4.3f.dcd" % (PREFIX_FEP, step_n, lam)
        en = "%s%03d_%4.3f.en" % (PREFIX_FEP, step_n, lam)
        files = {
            'final': final,
            'trajectory': dcd,
            'topology': top_fn,
            'energy': en,
            'fep': fep_fn
        }

        # if this step is in new direction (backwards) then set the previous lambda and step to initial
        if backward_lambdas and lam == backward_lambdas[0]:
            prev_fep = feps[0]
        elif step_n == 0:
            prev_fep = eq_steps[-1]
        else:
            prev_fep = feps[-1]

        # if this flag is set, all steps that point to the first step should point to the last eq step
        if first_frame_eq:
            if step_n == 1 or (backward_lambdas
                               and lam == backward_lambdas[0]):
                prev_fep = eq_steps[-1]

        if rest_fn:
            files["restraint"] = rest_fn

        files["restart"] = prev_fep.parameters["files"]["final"]

        # update the parameters and check the input
        try:
            inp = QDynInput(gen_inp_s)
            inp.update(fep_inp_s)
            if "energy" not in inp.parameters["intervals"]:
                raise QGenfepsError(
                    "FEP stage requires the energy printout defined in the intervals section (e.g. 'energy   10')"
                )

            inp.update(parameters={"files": files})
            inp.update(parameters={"lambdas": "%9.7f %9.7f" % (lam, 1 - lam)})
            inp.check()
        except QDynInputError as e:
            raise QGenfepsError("Error in FEP step %d: %s\n" %
                                (step_n, str(e)))

        # append the input
        feps.append(inp)

        # add the energy filename to the list
        en_filenames.append(inp.parameters["files"]["energy"])

    # if first_frame_eq is set add the energy file and remove the first fep frame
    if first_frame_eq:
        logger.info(
            "Replacing the first FEP frame with the last equilibration step")
        en_filenames[0] = eq_steps[-1].parameters["files"]["energy"]
        feps.pop(0)

    # check random seed in fep
    if "random_seed" in feps[0].parameters["md"] and int(
            feps[0].parameters["md"]["random_seed"]) < 1:
        logger.warning(
            "Generating random seeds in FEP inputs. Are you sure this is ok?")

    # write a file that contains the names of all energy files in proper order
    # this file is used later by q_mapper.py
    # sort the enfiles according to lambda (1.0 -> 0.0) so that the mapping will always go from reactants to products
    enfiles_lambdas = sorted([(enf.split("_")[-1], i)
                              for i, enf in enumerate(en_filenames)],
                             reverse=True)
    en_filenames_sorted = [en_filenames[i] for l, i in enfiles_lambdas]
    enf = os.path.join(TMPDIR, QScfg.get("files", "en_list_fn"))
    open(enf, 'w').write("\n".join(en_filenames_sorted))

    # create directories for repeats/replicas (rep_000,rep_001,rep_002...)
    # copy everything from TMPDIR (topology, fep file, relax restart and restraint file (if any))
    # create the eq and fep inputs

    # first check for existing directories
    for num in xrange(0, repeats):
        rep = "%s%03d" % (prefix, num)
        if os.path.lexists(rep):
            raise QGenfepsError(
                "Directory '%s' exists. Please (re)move it or change the prefix with --prefix."
                % rep)

    lsdir = os.listdir(TMPDIR)
    rep_dirs = []
    for num in xrange(0, repeats):
        rep = "%s%03d" % (prefix, num)
        os.mkdir(rep)
        # copy stuff from TMPDIR
        for f in lsdir:
            shutil.copy2(os.path.join(TMPDIR, f), rep)

        # create eq inputs
        for step_n, eq_step in enumerate(eq_steps):

            # check if random seed is a fixed value or not (generate random or fail)
            eqs = copy.deepcopy(eq_step)  # a copy
            if "random_seed" in eqs.parameters["md"] and int(
                    eqs.parameters["md"]["random_seed"]) < 1:
                rs = random.randint(1, 1000000)
                eqs.update(parameters={"md": {"random_seed": rs}})

            try:
                s = eqs.get_string()
            except QDynInputError as e:
                raise QGenfepsError("Error in step %d: %s" % (step_n, str(e)))
            fn = os.path.join(
                rep, "%s%03d_%4.3f.inp" % (PREFIX_EQ, step_n, lambda_initial))
            s = header_comment + s
            open(fn, 'w').write(s)

        last_eq_fn = fn
        # create FEP inputs
        for step_n, fep in enumerate(feps):
            if first_frame_eq:
                step_n += 1

            fs = copy.deepcopy(fep)  # a copy
            if "random_seed" in fs.parameters["md"] and int(
                    fs.parameters["md"]["random_seed"]) < 1:
                rs = random.randint(1, 1000000)
                fs.update(parameters={"md": {"random_seed": rs}})

            try:
                s = fs.get_string()
            except QDynInputError as e:
                raise QGenfepsError("Error in step %d: %s\n" %
                                    (step_n, str(e)))
            lam = lambdas[step_n]  # feps was created in lambdas iteration
            fn = os.path.join(rep,
                              "%s%03d_%4.3f.inp" % (PREFIX_FEP, step_n, lam))
            s = header_comment + s
            open(fn, 'w').write(s)

        logger.info("Created inputs for repeat/replica '%s'." % rep)
        rep_dirs.append(rep)

    # get the amount of storage that will be wasted
    # for this we need the atom count from the topology
    for line in open(os.path.join(TMPDIR, top_fn), 'r').readlines(1024):
        if "no. of atoms, no. of solute atoms" in line:
            num_atoms_all = int(line.split()[0])
            break
    REST_B_PER_ATOM = 48.0
    TRJ_B_PER_ATOM = 12.0
    EN_B_PER_STEP = 370.0  # very rough estimate, depends on Q version, it can double if group_contributions are calculated
    CONV_MB = 2**20

    qintervals = {
        "trj": ["trajectory", 100, num_atoms_all * TRJ_B_PER_ATOM
                ],  # q_parameter_key, q_default_value, approx_bytes_per_frame
        "log": ["output", 10,
                2000],  # 2000 is a very rough estimate of bytes_per_frame
        "temp": ["temperature", 10, 160],
        "en": ["energy", 10, EN_B_PER_STEP],
        "nb": ["non_bond", 10, 80]
    }
    total_data = {"trj": 0, "log": 0, "en": 0, "rest": 0}
    # calculate approx amount of data
    for i, step in enumerate(eq_steps + feps):
        data = {}
        for k, v in qintervals.iteritems():
            try:
                data[k] = int(step.parameters["md"]["steps"]) / int(
                    step.parameters["intervals"][v[0]]) * v[2]
            except KeyError:
                data[k] = int(
                    step.parameters["md"]["steps"]) / v[1] * v[2]  # default
            except ZeroDivisionError:
                data[k] = 0  # no printout
            finally:
                # if energy or trajectory, check that files for output are defined, otherwise set the printout to 0
                if v[0] in ("energy", "trajectory") and not (
                        v[0] in step.parameters["files"].keys()):
                    data[k] = 0

        trj_data = data["trj"]
        en_data = data["en"]
        log_data = (data["log"] + data["temp"] + data["nb"])
        rest_data = num_atoms_all * REST_B_PER_ATOM
        total_data["trj"] += trj_data
        total_data["log"] += log_data
        total_data["en"] += en_data
        total_data["rest"] += rest_data

        data = (trj_data + log_data + rest_data + en_data) / CONV_MB

    logger.info("Your runs will waste approx. %.2f MB of storage. Per replica: %.2f MB (trj: %.1f, log: %.1f, en: %.1f, rest: %.1f)"  % \
                  (sum(total_data.values())/CONV_MB*repeats,
                   sum(total_data.values())/CONV_MB, total_data["trj"]/CONV_MB,
                   total_data["log"]/CONV_MB,
                   total_data["en"]/CONV_MB,
                   total_data["rest"]/CONV_MB))

    # remove temporary directory
    shutil.rmtree(TMPDIR)

    return rep_dirs
Ejemplo n.º 9
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('ref_dga',
                        type=float,
                        help='Activation free energy (reference)')
    parser.add_argument('ref_dg0',
                        type=float,
                        help='Reaction free energy (reference)')
    parser.add_argument('init_hij',
                        type=float,
                        help='first guess Hij coupling constant')
    parser.add_argument('init_gs',
                        type=float,
                        help='first guess gas shift constant')
    parser.add_argument('--nt',
                        dest='nthreads',
                        type=int,
                        help='Number of threads (default = %s)' %
                        QScfg.get("mapping", "nthread"),
                        default=QScfg.get("mapping", "nthread"))
    parser.add_argument('--bin',
                        dest='bins',
                        type=int,
                        help='number of bins (default=%s)' %
                        QScfg.get("mapping", "bin"),
                        default=QScfg.get("mapping", "bin"))
    parser.add_argument(
        '--skip',
        dest='skip',
        type=int,
        help='number of points to skip in each frame (default=%s)' %
        QScfg.get("mapping", "skip"),
        default=QScfg.get("mapping", "skip"))
    parser.add_argument('--min',
                        dest='minpts_per_bin',
                        type=int,
                        help='minimum points for bin (default=%s)' %
                        QScfg.get("mapping", "minpts_per_bin"),
                        default=QScfg.get("mapping", "minpts_per_bin"))
    parser.add_argument('--temp',
                        dest='temperature',
                        type=float,
                        help='Temperature (default=%s)' %
                        QScfg.get("mapping", "temp"),
                        default=QScfg.get("mapping", "temp"))
    parser.add_argument('--step',
                        dest='step_size',
                        type=float,
                        help='Step size (default = %s)' % STEPSIZE,
                        default=STEPSIZE)
    parser.add_argument(
        '--threshold',
        dest='threshold',
        type=float,
        help='Convergence threshold for dG# and dG0, default = %s' % THRESHOLD,
        default=THRESHOLD)
    parser.add_argument('--iter',
                        dest='iterations',
                        type=int,
                        help='Max number of iterations (default = %s)' %
                        ITERATIONS,
                        default=ITERATIONS)
    parser.add_argument(
        '--mapdirs',
        nargs="+",
        dest='mapdirs',
        help='Replica directories (default=all dirs in current folder) ',
        default=[])
    parser.add_argument('--mapper_logfile',
                        dest='mapper_logfile',
                        help='q_mapper logfile name (default=%s)' %
                        QScfg.get("files", "mapper_logfile"),
                        default=QScfg.get("files", "mapper_logfile"))
    parser.add_argument(
        '--nosingle',
        dest='nosingle',
        action='store_true',
        help='Do not run the first iteration on only 1 replica')

    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit(1)

    args = parser.parse_args()

    qmap_args = {
        "bins": args.bins,
        "skip": args.skip,
        "minpts_per_bin": args.minpts_per_bin,
        "temperature": args.temperature,
        "mapdirectories": args.mapdirs,
        "verbose": False,
        "nthreads": args.nthreads
    }

    print "Attempting to fit to dG# = %s and dG0 = %s\n(number of threads = %s, stepsize = %s, threshold = %s, max iterations = %s)\n" % (
        args.ref_dga, args.ref_dg0, args.nthreads, args.step_size,
        args.threshold, args.iterations)

    gs_init = args.init_gs
    hij_init = args.init_hij

    # create QMapper instance with all arguments
    try:
        qmapper = q_mapper.QMapper(hij_init, gs_init, **qmap_args)
    except q_mapper.QMappingError as e:
        print "Problem initializing qmapper: %s" % str(e)
        sys.exit(1)
    mapdirs = qmapper.get_mapdirs(relative_paths=True)
    print "These directories will be used:\n%s\n" % (", ".join(mapdirs))

    # automap with only the first replica (when we have 3 or more) to get a better init guess quickly
    if not args.nosingle and len(mapdirs) > 2:
        try:
            print "Iteration #0, using only the first folder (disable this with --nosingle)."
            single_qmap_args = dict(qmap_args)
            single_qmap_args["mapdirectories"] = (mapdirs[0], )
            single_qmapper = q_mapper.QMapper(hij_init, gs_init,
                                              **single_qmap_args)
        except q_mapper.QMappingError as e:
            print "Problem initializing qmapper: %s" % str(e)
            sys.exit(1)

        (qan_maps_final, hij_init, gs_init,
         means_final) = do_iteration(single_qmapper, hij_init, gs_init, args)
        print "Switching to all directories..."

    # switch to all directories and iterative mapping
    iteration = 1
    means_init = None
    while (True):
        print "Iteration #%d" % iteration

        (qan_maps_final, hij_final, gs_final,
         means_final) = do_iteration(qmapper,
                                     hij_init,
                                     gs_init,
                                     args,
                                     means_init=means_init)

        # Check for convergence
        if abs(float(means_final[0]) -
               float(args.ref_dga)) < args.threshold and abs(
                   float(means_final[1]) -
                   float(args.ref_dg0)) < args.threshold:

            # save results summary
            logstr = "%s\n%s" % (qmapper.get_details(),
                                 qan_maps_final.get_summary())
            open(args.mapper_logfile, 'w').write(logstr)

            # print out some stuff
            print "\n\nWell done, use this on the protein:"
            print qmapper.get_input_parms()
            if qan_maps_final.get_failed() or qmapper.get_failed():
                print "WARNING: Some directories failed to map..."
            print "\nLook at %s!" % args.mapper_logfile
            break

        iteration += 1
        if iteration >= args.iterations:
            print "Did not converge. Try changing the step (--step), increasing number of iterations (--iter) or lowering the treshold (--threshold)"
            print
            sys.exit(1)

        means_init = means_final
        hij_init = hij_final
        gs_init = gs_final
Ejemplo n.º 10
0
def main():
    logger = init_logger('Qpyl')

    parser = argparse.ArgumentParser(description="""
    Command-line interface for mapping EVB (or just plain old FEP) simulations
    with QFep. At the moment, supports only single Hij (constant) and alpha.
    For FEP, use Hij=alpha=0.

    By default, all subdirectories in current dir will be used
    for mapping, or current dir if no subdirs are found.
    This can be changed with --dirs.
    """,
                                     add_help=False)

    reqarg = parser.add_argument_group("Required")
    reqarg.add_argument("hij", type=float, help="Hij coupling constant")

    reqarg.add_argument("alpha", type=float, help="state 2 shift (alpha)")

    optarg = parser.add_argument_group("Optional")
    optarg.add_argument("--nt",
                        dest='nthreads',
                        type=int,
                        default=QScfg.get("mapping", "nthreads"),
                        help="Number of threads (default = {})"
                        "".format(QScfg.get("mapping", "nthreads")))

    optarg.add_argument("--bins",
                        dest="gap_bins",
                        type=int,
                        default=QScfg.get("mapping", "gap_bins"),
                        help="Number of gap-bins (default={})."
                        "".format(QScfg.get("mapping", "gap_bins")))

    optarg.add_argument("--skip",
                        dest="points_skip",
                        type=int,
                        default=QScfg.get("mapping", "points_skip"),
                        help="Number of points to skip in each frame "
                        "(default={})."
                        "".format(QScfg.get("mapping", "points_skip")))

    optarg.add_argument("--min",
                        dest="minpts_bin",
                        type=int,
                        default=QScfg.get("mapping", "minpts_bin"),
                        help="Minimum points for gap-bin (default={})."
                        "".format(QScfg.get("mapping", "minpts_bin")))

    optarg.add_argument("--temp",
                        dest="temperature",
                        type=float,
                        default=QScfg.get("mapping", "temperature"),
                        help="Temperature (default={})."
                        "".format(QScfg.get("mapping", "temperature")))

    optarg.add_argument("--dirs",
                        nargs="+",
                        dest="mapdirs",
                        default=[],
                        help="Directories to map (default=all subdirs "
                        "in cwd or current dir)")

    optarg.add_argument("--out",
                        dest="outfile",
                        default=QScfg.get("files", "mapper_log"),
                        help="Logfile name (default={})."
                        "".format(QScfg.get("files", "mapper_log")))

    optarg.add_argument("--qfep_exec",
                        dest="qfep_exec",
                        default=QScfg.get("qexec", "qfep"),
                        help="qfep executable path (default={})."
                        "".format(QScfg.get("qexec", "qfep")))

    optarg.add_argument("-v",
                        "--version",
                        action="version",
                        version=get_version_full())
    optarg.add_argument("-h",
                        "--help",
                        action="help",
                        help="show this "
                        "help message and exit")

    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit(1)

    args = parser.parse_args()

    mapdirs = args.mapdirs

    # if mapping directories were not passed in as an argument,
    # store all directories in the current folder
    if not mapdirs:
        lsdir = os.listdir(os.getcwd())
        mapdirs = [md for md in lsdir if os.path.isdir(md)]

    mapdirs.sort()

    # if there are no folders in the current working directory,
    # map just the current one
    if not mapdirs:
        mapdirs = [
            os.getcwd(),
        ]
        print "No subdirectories. Mapping files in current directory only."
    else:
        print "Will use these directories for mapping (use --dirs to "\
              "change this): {}".format(", ".join(mapdirs))

    qmapper_parms = {
        "mapdirs": mapdirs,
        "hij": args.hij,
        "alpha": args.alpha,
        "nthreads": args.nthreads,
        "temperature": args.temperature,
        "points_skip": args.points_skip,
        "minpts_bin": args.minpts_bin,
        "gap_bins": args.gap_bins,
        "qfep_exec": args.qfep_exec,
        "en_list_fn": QScfg.get("files", "en_list_fn"),
        "gas_const": QScfg.get("mapping", "gas_const")
    }

    qmapper = QMapper(**qmapper_parms)
    try:
        qmapper.mapall()
    except KeyboardInterrupt:
        qmapper.kill_event.set()
        raise

    qfep_inp_fn = QScfg.get("files", "qfep_inp")
    qfep_out_fn = QScfg.get("files", "qfep_out")

    # write out the inputs and outputs
    for mapdir, (qfep_inp_str, qfep_out_str) in qmapper.mapped.iteritems():
        qfep_inp = os.path.join(mapdir, qfep_inp_fn)
        qfep_out = os.path.join(mapdir, qfep_out_fn)
        open(qfep_inp, "w").write(qfep_inp_str)
        open(qfep_out, "w").write(qfep_out_str)

    # analyse the outputs
    output_files = [os.path.join(md, qfep_out_fn) for md in qmapper.mapped]
    qafs = QAnalyseFeps(output_files)

    outstr = """
{mapper_details}
Analysis Stats:
{analysis_stats}
Analysis Fails:
FEP: {fails}, EVB: {fails_dg}

Run q_analysefeps.py for more info...
""".format(mapper_details=qmapper.details,
           analysis_stats=qafs.stats_str,
           fails=len(qafs.failed) or "None",
           fails_dg=len(qafs.failed_dg) or "None")

    print outstr
    backup = backup_file(args.outfile)
    if backup:
        print "# Backed up '{}' to '{}'".format(args.outfile, backup)
    open(args.outfile, "w").write(outstr)
    print "Wrote '{}'...".format(args.outfile)
Ejemplo n.º 11
0
                    "'cont_inp' - same as in the --cont input, "
                    "'cont_final' - final restart in --cont input. "
                    "Required if --cont is specified, otherwise, "
                    "defaults to 'top'.")

optarg.add_argument("--pdb",
                    dest="pdb",
                    default=None,
                    help="PDB file created with qprep. Used to replace "
                    "$RESID.ATOMNAME$ placeholders with atom indices "
                    "(eg. $512.N1$ -> 8356).")

optarg.add_argument("--outdir",
                    dest="outdir",
                    help="Output directory name. Default='{}'"
                    "".format(QScfg.get("inputs", "relax_dir")),
                    default=QScfg.get("inputs", "relax_dir"))

optarg.add_argument("--ignore_errors",
                    action="store_true",
                    default=False,
                    help="Keyword/parameter checks will no longer be fatal."
                    "Use with care.")

optarg.add_argument("-v",
                    "--version",
                    action="version",
                    version=get_version_full())

optarg.add_argument("-h",
                    "--help",
Ejemplo n.º 12
0
def main():
    logger = init_logger('Qpyl')

    parser = argparse.ArgumentParser(description="""
Tool for analysing QFep outputs - extracting FEP results, activation and reaction free
energies, calculating LRA contributions, calculating statistics over all
outputs, and exporting all the data into JSON format. Should be used after
every mapping.
    """, add_help=False)
    reqarg = parser.add_argument_group("Required")
    reqarg.add_argument("fepdirs", nargs="+",
                        help="Directories to scan for qfep output.")

    optarg = parser.add_argument_group("Optional")
    def_lra_l = QScfg.get("analysis", "lambdas_state1").split(",")

    optarg.add_argument("--lra_l", dest="lra_l", nargs=2,
                        metavar=("l1", "l2"),
                        default=def_lra_l,
                        help="Specify lambdas (state 1) at which LRA and "
                             "REORG are calculated. Default is '{}'."
                             "".format(str(def_lra_l)))


    optarg.add_argument("--qfep_out", dest="qfep_out",
                        help="Qfep output filename (default='{}')"
                             "".format(QScfg.get("files", "qfep_out")),
                        default=QScfg.get("files", "qfep_out"))

    optarg.add_argument("--out", dest="output_fn",
                        help="Output filename (default='{}')"
                             "".format(QScfg.get("files", "analysefeps_log")),
                        default=QScfg.get("files", "analysefeps_log"))

    optarg.add_argument("--plots_out", dest="plots_out",
                        help="Output filename for plot data (default='{}')"
                             "".format(QScfg.get("files", "analysefeps_plots")),
                        default=QScfg.get("files", "analysefeps_plots"))

    optarg.add_argument("--subcalcs", dest="subcalcs", default=False,
                        help="Write out plot data for sub-calculations "
                             "(QCP, QCP_mass, Exclusions). By default "
                             "this data is not written out.",
                        action="store_true")

    optarg.add_argument("--subcalc_dir", dest="subcalc_dir",
                        help="Output directory for sub-calculation plot data "
                             "Default={}".format(QScfg.get("files", \
                                                 "analysefeps_subcalc_dir")),
                        default=QScfg.get("files", "analysefeps_subcalc_dir"))
    optarg.add_argument("-v", "--version", action="version",
                        version=get_version_full())
    optarg.add_argument("-h", "--help", action="help", help="show this help "
                        "  message and exit")


    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit(1)

    args = parser.parse_args()

    lra_l = []
    for lamb in args.lra_l:
        try:
            lamb = float(lamb)
            if lamb < 0 or lamb > 1:
                raise ValueError
        except ValueError:
            print("FATAL! LRA lambdas make no sense. 0<lambda<1 please.")
            sys.exit(1)
        lra_l.append(lamb)

    if args.subcalcs and os.path.lexists(args.subcalc_dir):
        print("Directory '{}' exists. Please (re)move it or "\
              "use --subcalc_dir.".format(args.subcalc_dir))
        sys.exit(1)

    # analyse the outputs
    qos = [os.path.join(md, args.qfep_out) for md in sorted(args.fepdirs)]
    qaf = QAnalyseFeps(qos, lra_lambdas=lra_l)

    stats, fails = [], []

    # get the statistics
    stats.append(qaf.stats_str)
    for sub_calc_key, sub_calc in sorted(six.iteritems(qaf.sub_calcs)):
        stats.append(sub_calc.stats_str)

    # get those that completely failed
    if qaf.failed:
        fails.append("Failed to parse:")
    for failed_path, failed_msg in sorted(six.iteritems(qaf.failed)):
        relp = os.path.relpath(failed_path)
        fails.append("-> {}: {}".format(relp, failed_msg))

    # get those that didn't produce dG*/dG0
    if qaf.failed_dg:
        fails.append("Failed to produce dGa/dG0:")
    for failed_path, failed_msg in sorted(six.iteritems(qaf.failed_dg)):
        relp = os.path.relpath(failed_path)
        fails.append("-> {}: {}".format(relp, failed_msg))

    stats = "\n".join(stats)
    fails = "\n".join(fails) or None

    summary = """
----------------------------------- SUMMARY -----------------------------------
# Analysed with: QTools/q_analysefeps.py ({version})
# Work dir: {cwd}
# Date: {date}
# CMDline: {cmdline}


----- Statistics -----

{stats}

------- Fails --------

{fails}
-------------------------------------------------------------------------------
""".format(version=__version__, date=time.ctime(), cwd=os.getcwd(),
           stats=stats, fails=fails, cmdline=" ".join(sys.argv))

    print(summary)

    if not qaf.qfos:
        print("\nFATAL! None of the outputs could be parsed!")
        print("Are you running an ancient Q version? Then don't...")
        print("If not, report a bug.")
        sys.exit(1)


    # save some useful data
    output_string = """
------------------------------- Free energies ---------------------------------
{}
{}
""".format(qaf.dg_all, summary)

    fn_out = args.output_fn
    backup = backup_file(fn_out)
    open(fn_out, "w").write(output_string)

    if backup:
        print("Wrote '{}'...    # Backed up to '{}'".format(fn_out, backup))
    else:
        print("Wrote '{}'...".format(fn_out))

    # convert plots to json and write them out
    fn_out = args.plots_out
    plots = qaf.plotdata
    jsonenc = plotdata.PlotDataJSONEncoder(indent=2, separators=(",", ": "))
    backup = backup_file(fn_out)
    open(fn_out, 'w').write(jsonenc.encode(plots))
    if backup:
        print("Wrote '{}'... (q_plot.py is your friend)   "\
              "# Backed up to '{}'".format(fn_out, backup))
    else:
        print("Wrote '{}'... (q_plot.py is your friend)".format(fn_out))

    # if there are sub-calculations in the outputs
    if qaf.sub_calcs:
        if not args.subcalcs:
            print("\nNote: These sub-calculations were found: {}. "\
                  "Use --subcalcs to write out the plot data."\
                  "".format(", ".join(qaf.sub_calcs)))
            sys.exit(1)
        else:
            os.mkdir(args.subcalc_dir)
            for subcalc_key, subcalc in six.iteritems(qaf.sub_calcs):
                fn_out = os.path.join(args.subcalc_dir,
                                      "qaf.{}.json".format(subcalc_key))

                open(fn_out, 'w').write(jsonenc.encode(subcalc.plotdata))
                print("Wrote '{}'... (q_plot.py is your "\
                      "friend)".format(fn_out))
Ejemplo n.º 13
0
def genrelax(relax_proc,
             top=None,
             fep=None,
             runscript=None,
             pdb=None,
             cont=None,
             outdir=QScfg.get("inputs", "relax_dir"),
             logger=None):

    if not logger:
        # log to console, only warnings
        logger = logging.getLogger(__name__)
        logger.setLevel(logging.WARNING)
        handler = logging.StreamHandler(sys.stdout)
        formatter = SpecialFormatter()
        handler.setFormatter(formatter)
        logger.addHandler(handler)

    for k, v in locals().iteritems():
        if k in [
                'pdb', 'cont', 'relax_proc', 'fep', 'top', 'runscript',
                'relax_input'
        ]:
            if v and not os.path.lexists(v):
                raise QGenrelaxError("File '%s' doesn't exist." % v)

    # constants
    PREFIX = "relax_"
    DIR = os.path.join(os.getcwd(), outdir)
    if os.path.lexists(DIR):
        raise QGenrelaxError(
            "Directory '%s' exists. Please (re)move it or set 'outdir'." % DIR)
        sys.exit(1)
    TMPDIR = tempfile.mkdtemp()

    header_comment = "# Generated with %s, version %s, on %s\n# CWD: %s\n# Cmdline: %s\n" % (
        os.path.basename(sys.argv[0]), __version__, time.ctime(), os.getcwd(),
        " ".join(sys.argv))

    # find and replace placeholders. if not PDB was given to replace them, exit
    relax_proc_str = open(relax_proc, 'r').read()
    c = q_pdbindex.findPlaceholders(relax_proc_str)
    if c and not pdb:
        raise QGenrelaxError(
            "Found placeholders, but no PDB was given (--pdb):\n%s\n" %
            ", ".join(c))
    elif c:
        logger.info("These placeholders will be replaced with atom indices: " +
                    ", ".join(c))
        try:
            relax_proc_str = q_pdbindex.convertToIndexes(relax_proc_str, pdb)
        except KeyError as e:
            raise QGenrelaxError("Failed to replace placeholders: %s" % str(e))

    # get topology and fep and others from previous input if given (--cont)
    if cont:
        if top:
            raise QGenrelaxError(
                "'top' and 'cont' don't like each other. Difficult to continue with a different topology..."
            )
        try:
            c = QDynInput(open(cont, 'r').read())
        except QDynInputError as e:
            raise QGenrelaxError(
                "There is something wrong with the given input file (%s):\n%s"
                % (cont, str(e)))
        cont_files = c.parameters["files"]
        di = os.path.dirname(cont)
        top_fn = cont_files["topology"]
        re_fn = "cont_" + cont_files["final"]
        shutil.copy2(os.path.join(di, top_fn), TMPDIR)
        shutil.copy2(os.path.join(di, cont_files["final"]),
                     os.path.join(TMPDIR, re_fn))
        if fep:
            logger.warning(
                "Using the fep file '%s', instead of the one found in the input\n"
                % (fep))
            fep_fn = os.path.basename(fep)
            shutil.copy2(fep, TMPDIR)
        else:
            try:
                fep_fn = cont_files["fep"]
                shutil.copy2(os.path.join(di, fep_fn), TMPDIR)
            except KeyError:
                logger.info("No FEP file found in the input")
    # or take the arguments
    else:
        if not top:
            raise QGenrelaxError(
                "Please specify the topology file ('top') or specify 'cont' to continue from a previous relaxation."
            )

        cont_files = None
        top_fn = os.path.basename(top)
        shutil.copy2(top, TMPDIR)
        try:
            fep_fn = os.path.basename(fep)
            shutil.copy2(fep, TMPDIR)
        except AttributeError:
            logger.info("NOTE: No FEP file!")

    try:
        shutil.copy2(runscript, TMPDIR)
    except AttributeError:
        logger.info("No submission script was given.")

    general_inp = []
    steps_inps = [
        [],
    ]
    script_vars = {}

    section = ""
    for line in relax_proc_str.split("\n"):
        # remove comments and strip whitespaces.
        line = re.split("#|\!", line)[0].strip()
        # empty lines are useless
        if line == "":
            continue
        # found a section
        if line[0] == "{":
            section = line.strip("{}").lower()
            continue

        if not section:
            raise QGenrelaxError(
                "Failed to parse '%s'... this line - '%s' is not inside any section:"
                % (relax_proc, line))

        if section == "script_vars":
            c = line.split()
            var = c[0]
            value = " ".join(c[1:])
            script_vars[var] = value
        elif section == "general":
            general_inp.append(line)
        elif section == "steps":
            if "__________" in line:
                steps_inps.append([])
            else:
                steps_inps[-1].append(line)

    # check for steps with no parameters ( too many _________ lines ) and remove them
    for i in range(len(steps_inps) - 1, -1, -1):
        if not steps_inps[i]:
            steps_inps.pop(i)

    # join lists of lines to strings and replace the placeholders
    gen_inp_s = "\n".join(general_inp)
    for placeholder, value in script_vars.iteritems():
        gen_inp_s = gen_inp_s.replace(placeholder, value)

    step_inps_s = []
    for i, step_inp in enumerate(steps_inps):
        s = "\n".join(step_inp)
        for placeholder, value in script_vars.iteritems():
            s = s.replace(placeholder, value)
        step_inps_s.append(s)

    # make and save the inputs
    steps = []
    overridden_prms_all = []
    step_n = 1
    inp_fns = []  # to store the filenames and use the return value
    for step_inp_s in step_inps_s:
        # create the files section
        final = "%s%03g.re" % (PREFIX, step_n)
        dcd = "%s%03g.dcd" % (PREFIX, step_n)
        files = {'final': final, 'trajectory': dcd, 'topology': top_fn}
        try:
            files['fep'] = fep_fn
        except NameError:
            pass
        if step_n != 1:
            prev_step = step_n - 1
            files["restart"] = "%s%03g.re" % (PREFIX, prev_step)
        elif cont_files:
            files["restart"] = re_fn

        try:
            # parse the general input
            inp = QDynInput(gen_inp_s)
            # update the general parameters with step input, printout the overriden parms, update the files section
            overridden_prms = inp.update(step_inp_s)
            if overridden_prms:
                overridden_prms_all.append((step_n, ", ".join([
                    "%s:%s->%s" % (key, value_old, value_new)
                    for key, (value_old,
                              value_new) in overridden_prms.iteritems()
                ])))

            if "energy" in inp.parameters["intervals"]:
                files["energy"] = "%s%03g.en" % (PREFIX, step_n)

            inp.update(parameters={"files": files})

        except QDynInputError as e:
            raise QGenrelaxError("Problem with step no. %d:\n%s" %
                                 (step_n, str(e)))

        # set the random seed
        mdp = inp.parameters["md"]
        if "random_seed" in mdp and int(mdp["random_seed"]) < 1:
            rs = random.randint(1, 1000000)
            inp.update(parameters={"md": {"random_seed": rs}})
            logger.info("Generated random seed in step %d: %d" % (step_n, rs))

        # get the input string
        try:
            inpstr = inp.get_string()
        except QDynInputError as e:
            raise QGenrelaxError("Error in step %d: %s\n" % (step_n, str(e)))

        inpfn = "%s%03g.inp" % (PREFIX, step_n)
        inp_fns.append(os.path.join(DIR, inpfn))
        s = header_comment + inpstr
        open(os.path.join(TMPDIR, inpfn), 'w').write(s)

        steps.append(inp)
        step_n += 1

    try:
        shutil.copytree(TMPDIR, DIR)
    except OSError:
        raise QGenrelaxError("Cannot create directory '%s'." % DIR)
        sys.exit(1)
    # remove temporary directory
    shutil.rmtree(TMPDIR)
    logger.info("Created inputs %s%03g.inp - %s%03g.inp" %
                (PREFIX, 1, PREFIX, len(steps)))

    # print some useful information

    if overridden_prms_all:
        logger.info("Overridden parameters:")
        for step_n, op in overridden_prms_all:
            logger.info("%d: %s" % (step_n, op))

    summary = """
Quick summary
{0:<10} {1:>5} {2:>10} {3:>10} {4:^10} {5:^10} {6:^10} {7:^30} {8:^10} {9:>10} 
""".format("Step", "T", "Stepsize", "Steps", "Seq.rest", "Dist.rest",
           "Ang.rest", "Shake", "Rand.Seed", "Data (MB)")
    locale.setlocale(locale.LC_ALL, '')
    restraints = []
    total_time = 0
    # print out how much data this run will produce, for this we need the atom count from the topology
    for line in open(os.path.join(DIR, top_fn), 'r').readlines(1024):
        if "no. of atoms, no. of solute atoms" in line:
            num_atoms_all = int(line.strip().split()[0])
            break

    REST_B_PER_ATOM = 48.0
    TRJ_B_PER_ATOM = 12.0
    EN_B_PER_STEP = 370.0  # very rough estimate, depends on Q version, it can double if group_contributions are calculated
    CONV_MB = 2**20

    qintervals = {
        "trj": ["trajectory", 100, num_atoms_all * TRJ_B_PER_ATOM
                ],  # q_parameter_key, q_default_value, approx_bytes_per_frame
        "log": ["output", 10,
                2000],  # 2000 is a very rough estimate of bytes_per_frame
        "temp": ["temperature", 10, 160],
        "en": ["energy", 10, EN_B_PER_STEP],
        "nb": ["non_bond", 10, 80]
    }
    total_data = {"trj": 0, "log": 0, "en": 0, "rest": 0}

    for i, step in enumerate(steps):
        nstep = i + 1
        try:

            # get md parameters
            mdparms = step.parameters["md"]
            total_time += float(mdparms["stepsize"]) * int(mdparms["steps"])
            random_seed = mdparms.get("random_seed", "")
            numsteps = int(mdparms["steps"])

            # get restraints
            step_rests = {
                "sequence_restraints": [],
                "distance_restraints": [],
                "angle_restraints": []
            }
            for rest_type in step_rests.keys():
                for seqrest in step.parameters.get(rest_type, []):
                    if seqrest in restraints:
                        step_rests[rest_type].append(
                            str(restraints.index(seqrest) + 1))
                    else:
                        restraints.append(seqrest)
                        step_rests[rest_type].append(str(len(restraints)))
            seq = ",".join(step_rests["sequence_restraints"])
            dist = ",".join(step_rests["distance_restraints"])
            angle = ",".join(step_rests["angle_restraints"])

            # get shake parameters
            shake = []
            if mdparms.get(
                    "shake_solvent", "on"
            ) == "on":  # this is a Q default, hopefully it will not change
                shake.append("solvent")
            if mdparms.get("shake_hydrogens", "off") == "on":
                shake.append("hydrogens")
            if mdparms.get("shake_solute", "off") == "on":
                shake.append("solute")
            shake = ",".join(shake)

            # calculate approx amount of data
            data = {}
            for k, v in qintervals.iteritems():
                try:
                    data[k] = numsteps / int(
                        step.parameters["intervals"][v[0]]) * v[2]
                except KeyError:
                    data[k] = numsteps / v[1] * v[2]  # default
                except ZeroDivisionError:
                    data[k] = 0  # no printout
                finally:
                    # if energy or trajectory, check that files for output are defined, otherwise set the printout to 0
                    if v[0] in ("energy", "trajectory") and not (
                            v[0] in step.parameters["files"].keys()):
                        data[k] = 0

            trj_data = data["trj"]
            en_data = data["en"]
            log_data = (data["log"] + data["temp"] + data["nb"])
            rest_data = num_atoms_all * REST_B_PER_ATOM
            total_data["trj"] += trj_data
            total_data["log"] += log_data
            total_data["en"] += en_data
            total_data["rest"] += rest_data

            data = (trj_data + log_data + rest_data + en_data) / CONV_MB


            summary += "{0:<10} {1:>5} {2:>10} {3:>10} {4:^10} {5:^10} {6:^10} {7:^30} {8:^10} {9:>10.2f}\n".format(\
                    nstep, mdparms["temperature"], mdparms["stepsize"], locale.format('%d', numsteps, 1),\
                    seq, dist, angle, shake, random_seed, data)
        except KeyError as e:
            raise QGenrelaxError(
                "You are missing either 'steps', 'temperature' or 'stepsize' in one of your relaxation steps. These parameters are quite important you know..."
            )

    summary += "Restraints:\n"
    for i, rest in enumerate(restraints):
        summary += "%d: %s\n" % (i + 1, rest)

    summary += """
Total time: {0} ps
Total wasted storage (wild approximation): \
{1:.2f} MB (trj: {2:.1f}, log: {3:.1f}, en: {4:.1f}, rest: {5:.1f}
""".format(total_time / 1000.0,
           sum(total_data.values()) / CONV_MB, total_data["trj"] / CONV_MB,
           total_data["log"] / CONV_MB, total_data["en"] / CONV_MB,
           total_data["rest"] / CONV_MB)

    for l in summary.split("\n"):
        logger.info(l)

    return inp_fns
Ejemplo n.º 14
0
    parser.add_argument(
        '--cont',
        dest='cont',
        help=
        'Continue a previous relaxation, argument is the name of the last input file (e.g. "relax_012.inp")',
        default=argparse.SUPPRESS)
    parser.add_argument(
        '--pdb',
        dest='pdb',
        help=
        'PDB file created with qprep. Used to replace $RESID.ATOMNAME$ placeholders with atom indices (ex. $512.N1$ -> 5514).',
        default=argparse.SUPPRESS)
    parser.add_argument('--outdir',
                        dest='outdir',
                        help='Output directory name. Default=%s' %
                        QScfg.get("inputs", "relax_dir"),
                        default=QScfg.get("inputs", "relax_dir"))

    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit(1)

    args = parser.parse_args()

    logger = logging.getLogger(__name__)
    logger.setLevel(logging.INFO)
    handler = logging.StreamHandler(sys.stdout)
    formatter = SpecialFormatter()
    handler.setFormatter(formatter)
    logger.addHandler(handler)
Ejemplo n.º 15
0
if __name__ == "__main__":

    try:
        import argparse
    except ImportError:
        import lib.argparse as argparse

    parser = argparse.ArgumentParser()
    parser.add_argument('hij', type=float, help='Hij coupling constant')
    parser.add_argument('gas_shift', type=float, help='gas shift constant')
    parser.add_argument('--nt',
                        dest='nthreads',
                        type=int,
                        help='Number of threads (default = %s)' %
                        QScfg.get("mapping", "nthread"),
                        default=QScfg.get("mapping", "nthread"))
    parser.add_argument('--bin',
                        dest='bins',
                        type=int,
                        help='number of bins (default=%s)' %
                        QScfg.get("mapping", "bin"),
                        default=QScfg.get("mapping", "bin"))
    parser.add_argument(
        '--skip',
        dest='skip',
        type=int,
        help='number of points to skip in each frame (default=%s)' %
        QScfg.get("mapping", "skip"),
        default=QScfg.get("mapping", "skip"))
    parser.add_argument('--min',
Ejemplo n.º 16
0
def _call_mapper(qm, hij, gs):
    try:
        qm.set_hij(hij)
        qm.set_gas_shift(gs)
        (mapped, failed) = qm.q_map()
        qanalysemaps = q_analysemaps.QAnalyseMaps(mapped)
        if not qanalysemaps.get_analysed():
            print "\nAll replicas failed to analyse... Try changing the initial guess values (probably your simulations are crap though)... Also, look at qfep output files (%s)..." % QScfg.get(
                "files", "qfep_out")
            print "\nHere are the error messages:"
            for mapdir, error in qanalysemaps.get_failed():
                print "%s -> %s" % (os.path.relpath(mapdir), error)
            sys.exit(1)

        return qanalysemaps

    except q_mapper.QMappingError as e:
        print "%s\n\nTry changing the initial guess values and/or the step size (--step). If that doesn't work you're screwed." % e
        sys.exit(1)
Ejemplo n.º 17
0
    from lib import plotdata
    try:
        from collections import OrderedDict as ODict
    except ImportError:
        import lib.OrderedDict as ODict
    try:
        import argparse
    except ImportError:
        import lib.argparse as argparse

    parser = argparse.ArgumentParser()
    parser.add_argument("logfiles", nargs="+", help="Qdyn log files")
    parser.add_argument("--plots_out",
                        dest="plots_out",
                        help="output filename for plot data (default='%s')" %
                        QScfg.get("files", "analysedyn_plots"),
                        default=QScfg.get("files", "analysedyn_plots"))
    parser.add_argument(
        "--stepsize",
        dest="stepsize",
        help="If the stepsize in your log is 0.000, define it with this flag.",
        default=None)
    parser.add_argument(
        "--timeunit",
        dest="timeunit",
        help=
        "Which units of time should the results be in? fs, ps or ns? Default is ps.",
        default="ps")
    parser.add_argument(
        "--skip",
        dest="skip",
Ejemplo n.º 18
0
def main():
    logger = init_logger('Qpyl')

    parser = argparse.ArgumentParser(description="""
    Fits EVB parameters Hij and alpha to reproduce
    reference activation and reaction free energies.

    By default, all subdirectories in current dir will be used
    for mapping, or current dir if no subdirs are found.
    This can be changed with --dirs.

    Initial guess values for Hij and alpha should be relatively close to
    their correct values (+-50) otherwise qfep crashes. If it doesn't converge,
    change the step size (--step), number of iterations (--iter) or the threshold
    (--threshold).
    """,
                                     add_help=False)
    reqarg = parser.add_argument_group("Required")
    reqarg.add_argument("ref_dga",
                        type=float,
                        help="Reference activation free energy.")

    reqarg.add_argument("ref_dg0",
                        type=float,
                        help="Reference reaction free energy.")

    reqarg.add_argument("init_hij",
                        type=float,
                        help="Initial guess for Hij (offdiagonal)")

    reqarg.add_argument("init_alpha",
                        type=float,
                        help="Initial guess for alpha (state 2 shift)")

    optarg = parser.add_argument_group("Optional")
    optarg.add_argument("--nt",
                        dest='nthreads',
                        type=int,
                        default=QScfg.get("mapping", "nthreads"),
                        help="Number of threads (default = {})"
                        "".format(QScfg.get("mapping", "nthreads")))

    optarg.add_argument("--bins",
                        dest="gap_bins",
                        type=int,
                        default=QScfg.get("mapping", "gap_bins"),
                        help="Number of gap-bins (default={})."
                        "".format(QScfg.get("mapping", "gap_bins")))

    optarg.add_argument("--skip",
                        dest="points_skip",
                        type=int,
                        default=QScfg.get("mapping", "points_skip"),
                        help="Number of points to skip in each frame "
                        "(default={})."
                        "".format(QScfg.get("mapping", "points_skip")))

    optarg.add_argument("--min",
                        dest="minpts_bin",
                        type=int,
                        default=QScfg.get("mapping", "minpts_bin"),
                        help="Minimum points for gap-bin (default={})."
                        "".format(QScfg.get("mapping", "minpts_bin")))

    optarg.add_argument("--temp",
                        dest="temperature",
                        type=float,
                        default=QScfg.get("mapping", "temperature"),
                        help="Temperature (default={})."
                        "".format(QScfg.get("mapping", "temperature")))

    optarg.add_argument("--dirs",
                        nargs="+",
                        dest="mapdirs",
                        default=[],
                        help="Directories to map (default=all subdirs "
                        "in cwd that contain the energy-files list {})."
                        "".format(QScfg.get("files", "en_list_fn")))

    optarg.add_argument("--out",
                        dest="outfile",
                        default=QScfg.get("files", "automapper_log"),
                        help="Logfile name (default={})."
                        "".format(QScfg.get("files", "automapper_log")))

    _args, _, _, _defaults = inspect.getargspec(QMapper.fit_to_reference)
    defs = dict(zip(_args[-len(_defaults):], _defaults))

    optarg.add_argument("--step",
                        dest="step_size",
                        type=float,
                        help="Step size (default={})."
                        "".format(defs["step_size"]),
                        default=defs["step_size"])

    optarg.add_argument("--threshold",
                        dest="threshold",
                        type=float,
                        help="Convergence threshold for dG# and dG0 "
                        "(default={}).".format(defs["threshold"]),
                        default=defs["threshold"])

    optarg.add_argument("--iter",
                        dest="max_iterations",
                        type=int,
                        help="Max number of iterations (default={})."
                        "".format(defs["max_iterations"]),
                        default=defs["max_iterations"])

    optarg.add_argument("--nosingle",
                        dest="nosingle",
                        action="store_true",
                        help="Do not run the first iteration on only 1 dir.")

    optarg.add_argument("--qfep_exec",
                        dest="qfep_exec",
                        default=QScfg.get("qexec", "qfep"),
                        help="qfep executable path (default={})."
                        "".format(QScfg.get("qexec", "qfep")))
    optarg.add_argument("-v",
                        "--version",
                        action="version",
                        version=get_version_full())
    optarg.add_argument("-h",
                        "--help",
                        action="help",
                        help="show this help "
                        "  message and exit")

    if len(sys.argv) == 1:
        parser.print_help()
        sys.exit(1)

    args = parser.parse_args()

    print """\
Attempting to fit to dG# = {} and dG0 = {}
(stepsize = {}, threshold = {}, max iterations = {})
""".format(args.ref_dga, args.ref_dg0, args.step_size, args.threshold,
           args.max_iterations)

    mapdirs = args.mapdirs

    # if mapping directories were not passed in as an argument,
    # store all directories in the current folder
    if not mapdirs:
        lsdir = os.listdir(os.getcwd())
        mapdirs = [md for md in lsdir if os.path.isdir(md)]

    mapdirs.sort()

    # if there are no folders in the current working directory,
    # map just the current one
    if not mapdirs:
        mapdirs = [
            os.getcwd(),
        ]
        print "No subdirectories. Mapping files in current directory only."
    else:
        print "Will use these directories for mapping (use --dirs to "\
              "change this): {}".format(", ".join(mapdirs))

    qmapper_parms = {
        "hij": args.init_hij,
        "alpha": args.init_alpha,
        "nthreads": args.nthreads,
        "temperature": args.temperature,
        "points_skip": args.points_skip,
        "minpts_bin": args.minpts_bin,
        "gap_bins": args.gap_bins,
        "qfep_exec": args.qfep_exec,
        "en_list_fn": QScfg.get("files", "en_list_fn"),
        "gas_const": QScfg.get("mapping", "gas_const")
    }

    # automap with only the first replica (when we have 3 or more)
    # to get a better init guess quickly
    if not args.nosingle and len(mapdirs) > 2:
        print "\nInitial fit, using only the first folder (disable this "\
                "with --nosingle)."
        # create QMapper instance with all arguments
        qmapper_parms["mapdirs"] = mapdirs[:1]
        qmapper_single = QMapper(**qmapper_parms)
        try:
            qmapper_single.fit_to_reference(args.ref_dga,
                                            args.ref_dg0,
                                            step_size=args.step_size,
                                            threshold=args.threshold,
                                            max_iterations=1)

        except QMapperError:
            print "...failed, will try with all dirs anyhow..."
        except KeyboardInterrupt:
            qmapper_single.kill_event.set()
            raise
        else:
            qmapper_parms.update({
                "hij": qmapper_single.parms["hij"],
                "alpha": qmapper_single.parms["alpha"]
            })

        print "\nSwitching to all directories..."

    qmapper_parms["mapdirs"] = mapdirs
    qmapper = QMapper(**qmapper_parms)

    try:
        rcode = qmapper.fit_to_reference(args.ref_dga,
                                         args.ref_dg0,
                                         step_size=args.step_size,
                                         threshold=args.threshold,
                                         max_iterations=args.max_iterations)
    except QMapperError as error_msg:
        print "\nMassive fail:\n{}\n".format(error_msg)
        sys.exit(1)
    except KeyboardInterrupt:
        qmapper.kill_event.set()
        raise

    if not rcode:
        print "Did not converge. Try changing the step (--step), increasing "\
              "number of iterations (--iter) or raising the threshold "\
              "(--threshold)\n"

    else:
        print """

Well done! Use this on your non-reference simulations:
{}

""".format(qmapper.input_parms_str)

        # write out the inputs and outputs from the last step
        qfep_inp_fn = QScfg.get("files", "qfep_inp")
        qfep_out_fn = QScfg.get("files", "qfep_out")
        for mapdir, (qfep_inp_str, qfep_out_str) in qmapper.mapped.iteritems():
            qfep_inp = os.path.join(mapdir, qfep_inp_fn)
            qfep_out = os.path.join(mapdir, qfep_out_fn)
            open(qfep_inp, "w").write(qfep_inp_str)
            open(qfep_out, "w").write(qfep_out_str)

        # analyse the outputs
        output_files = [os.path.join(md, qfep_out_fn) for md in qmapper.mapped]
        qafs = QAnalyseFeps(output_files)
        fails = "\n".join([
            "{}: {}".format(qfo, err) for qfo, err in qafs.failed.iteritems()
        ])

        outstr = """
{mapper_details}
Analysis Stats:
{analysis_stats}
Analysis Fails:
{analysis_fails}
""".format(mapper_details=qmapper.details,
           analysis_stats=qafs.stats_str,
           analysis_fails=fails or "None")

        if fails or qmapper.failed:
            print """
WARNING! Some dirs failed to map/analyse! Look at the log!

"""

        print "Writting out the logfile..."
        backup = backup_file(args.outfile)
        if backup:
            print "# Backed up '{}' to '{}'".format(args.outfile, backup)
        open(args.outfile, "w").write(outstr)
        print "Wrote '{}'...".format(args.outfile)
Ejemplo n.º 19
0
     'path to the input file from the last relaxation step (to extract all the relevant filenames - re,top,fep and lambda values)'
 )
 parser.add_argument(
     '--rest',
     dest='restraint',
     help=
     'Sequence restraints applied to topology (top) or relaxed structure (relax). Default is whatever is in the relaxation input (inp)',
     default="inp")
 parser.add_argument('--rs',
                     dest='runscript',
                     help='shell runscript for Q',
                     default=argparse.SUPPRESS)
 parser.add_argument('--frames',
                     type=int,
                     help='number of frames (31,51,101,...). Default=%s' %
                     QScfg.get("inputs", "fep_frames"),
                     default=QScfg.get("inputs", "fep_frames"))
 parser.add_argument('--repeats',
                     type=int,
                     help='number of repeats/replicas. Default=%s' %
                     QScfg.get("inputs", "num_repeats"),
                     default=QScfg.get("inputs", "num_repeats"))
 parser.add_argument('--fep',
                     help='FEP file (default is the one in the input file)',
                     default=argparse.SUPPRESS)
 parser.add_argument(
     '--fromlambda',
     type=float,
     help=
     'Starting lambda for state 1. Example: --fromlambda 0.45  will go from 0.45,0.55 in both directions, to 1.0,0.0 and 0.0,1.0. Example2: --fromlambda 0.0 will drive the reaction in reverse direction. Default is the one in the relaxation input (usually 1.0 - starting from the reactants state).',
     default=argparse.SUPPRESS)