示例#1
0
 def setModel(self, model):
     """ set the MetabolicModel and reset flux and related variables
     """
     self.model = model
     self.flux = MetabolicFlux()
     self.metFlux, self.inRatios, self.outRatios = {}, {}, {}
     self.minFlux, self.maxFlux = {}, {}
示例#2
0
def main():
    # 1. Parse command line

    usage = "Usage: %prog <solution-file> [options]"
    version = "%prog\n" + COPYRIGHT_VERSION_STRING
    parser = OptionParser(usage=usage, version=version)
    parser.add_option("-r",
                      "--reactions",
                      dest="reactionFile",
                      help="use "
                      "reversibilities from reaction FILE",
                      metavar="FILE")
    parser.add_option("-p",
                      "--parameters",
                      dest="paramFile",
                      help="use constraints from the given scenario FILE",
                      metavar="FILE")

    options, args = parser.parse_args()

    # 2. Read solution file

    solution = MetabolicFlux()
    try:
        solution.readFromFile(args[0])
    except IndexError:
        print("Error: No solution file given.\nUsage is\n    " +
              os.path.basename(sys.argv[0]) + " <solution-file> [options]")
        exit()
    except IOError, strerror:
        print("An error occurred while trying to read file %s:" %
              os.path.basename(args[0]))
        print strerror
        exit()
示例#3
0
def main():
    # 1. Parse command line

    usage = "Usage: %prog <file1> <file2> [options]"
    version = "%prog\n" + COPYRIGHT_VERSION_STRING
    parser = OptionParser(usage=usage, version=version)
    parser.add_option("-o",
                      "--output",
                      dest="outputFile",
                      help="output FILE "
                      "(output is written to console if this is missing)",
                      metavar="FILE")
    parser.add_option("-c",
                      "--cutoff",
                      dest="cutoff",
                      help="Cutoff below which"
                      " difference is considered zero; default is 1E-10")
    parser.set_defaults(cutoff="1E-10")

    options, args = parser.parse_args()

    if len(args) < 2:
        print "Error: Need two solution files."
        print("Usage is\n    " + os.path.basename(sys.argv[0]) + " <file1> "
              "<file2> [options]")
        exit()

    try:
        cutoff = float(options.cutoff)
    except ValueError:
        print "Error: Invalid floating point value for cutoff."
        exit()
    if cutoff < 0.:
        print(
            "Warning: Cutoff is less than zero. Setting cutoff to zero, "
            "i.e. no cutoff.")
        cutoff = 0.

    basename = map(os.path.basename, args)
    # Use full path for identifying files if basenames are identical
    if basename[0] == basename[1]:
        basename = args

    # 2. Parse solution files and compute absolute differences

    solution = MetabolicFlux(), MetabolicFlux()
    for i in range(2):
        # Get pair of MetabolicFlux objects
        try:
            solution[i].readFromFile(args[i])
        except IOError, strerror:
            print("An error occurred while trying to read file %s:" %
                  os.path.basename(basename[i]))
            print strerror
            exit()
        except SyntaxError, strerror:
            print "An error occurred parsing file %s:" % basename[i]
            print strerror
            exit()
示例#4
0
    def checkSyntax(self):
        """ check assertions for syntax errors without actually performing any
            potentially time-consuming analyses

        This function prints a message to the console for every assertion that
        contains a syntax error.

        Returns: True if all assertions can be evaluated, False if error occurs
        """
        # Backup member variables and re-initialize with dummy values to make
        # sure that all references exist
        bakflux, bakMetFlux = self.flux, self.metFlux
        bakInRatios, bakOutRatios = self.inRatios, self.outRatios
        bakMinFlux, bakMaxFlux = self.minFlux, self.maxFlux

        self.flux = MetabolicFlux(self.model, [0.] * len(self.model))
        self.metFlux = dict(
            zip(self.model.metabolites, [0.] * len(self.model.metabolites)))
        self.inRatios = dict(
            zip(self.model.metabolites, [{}] * len(self.model.metabolites)))
        self.outRatios = dict(
            zip(self.model.metabolites, [{}] * len(self.model.metabolites)))
        self.minFlux = dict(
            zip(self.model.reactionDict.keys(), [0.] * len(self.model)))
        self.maxFlux = dict(
            zip(self.model.reactionDict.keys(), [0.] * len(self.model)))
        excepted = []
        for i in range(len(self.assertions)):
            try:
                eval(self.assertions[i])
            except (SyntaxError, NameError):
                excepted.append(repr(self.assertions_orig[i]))

        # Restore member variables to original values
        self.flux, self.metFlux = bakflux, bakMetFlux
        self.inRatios, self.outRatios = bakInRatios, bakOutRatios
        self.minFlux, self.maxFlux = bakMinFlux, bakMaxFlux

        if excepted:
            print(
                "The following assertions cannot be evaluated due to errors"
                ":\n  " + "\n  ".join(excepted))
            #  The following was removed because the Python error messages are misleading.
            #            for a in excepted:
            #                print "\n  %r\n  %s: %s\n" % (a[0], a[1], a[2])
            return False
        return True
示例#5
0
    def parseSolutionFileByHandle(f):
        """ read the FVA solution file given as a file object (must be open)

        Returns:
        (fbaSolution, minmax) tuple with

        fbaSolution -- MetabolicFlux object with flux distribution, and lb, ub
        minmax      -- dict { reaction : flux minimum, flux maximum }
        """
        reactions = set()
        reactionVec, fluxVec = [], []
        boundsDict = {}
        minmax = {}

        line_no = 0
        for line in f:
            line_no += 1
            if (line.lstrip().upper().startswith("NAME") or line == ""
                    or line.isspace()):
                continue

            try:
                rea, values_str = map(str.rstrip, line.split(":"))
            except ValueError:
                raise SyntaxError("Syntax error in line %u:\nLine must "
                                  "contain exactly one colon (':')." % line_no)
            if rea in reactions:
                raise SyntaxError("Syntax error in line %u: Duplicate "
                                  "reaction." % line_no)
            reactions.add(rea)
            reactionVec.append(rea)

            try:
                values = map(float, values_str.split(None, 6)[:6])
            except ValueError:
                raise SyntaxError("Syntax error in line %u: Invalid "
                                  "floating point value." % line_no)
            try:
                fluxVec.append(values[1])
                minmax[rea] = values[0], values[2]
                boundsDict[rea] = values[4], values[5]
            except IndexError:
                raise SyntaxError("Syntax error in line %u:\nLine must "
                                  "contain exactly six values (min_flux, "
                                  "fba_flux, max_flux, diff, lb, ub)." %
                                  line_no)
        return MetabolicFlux(reactionVec, fluxVec, boundsDict), minmax
示例#6
0
def parallel_ko_worker(comm,
                       model,
                       solver,
                       wtVec,
                       fbaParams,
                       koGroups=None,
                       weights=None,
                       numIter=1,
                       useMoma=When.AUTO,
                       lethalityCutoff=_CUTOFF_LETHAL):
    """ compute process (worker) for parallel knockout analysis

    Keyword arguments:

    comm       -- MPI communicator
    model      -- the MetabolicModel
    solver     -- name of QP/NLP solver (or "default")
    wtVec      -- FBA solution for wildtype
    fbaParams  -- parameters for FBA (incl. linear equality and inequality
                                      constraints)
    koGroups   -- list of pairs (group name, list of reactions)
    weights    -- weight vector for weighted MOMA (None -> perform regular MOMA,
                  else: weight flux i with weights[i])
    numIter    -- number of NLP runs (if NLP solver is used) for MOMA
    useMoma    -- selector of optimization strategy, enum values (class When):
                  NEVER  - always perform FBA (LP)
                  AUTO   - perform FBA first, followed by MOMA if not lethal
                  ALWAYS - always perform MOMA (QP)
    lethalityCutoff
               -- threshold for biomass flux signifying lethality
    """
    if not koGroups:
        koGroups = _makeDefaultKoGroups(model)


#    print "worker: %d reactions, %d knockout groups" % (len(model),
#                                                        len(koGroups))
    wtSolution = MetabolicFlux(model, wtVec)
    nanVec = array([nan] * len(wtVec))
    infVec = array([inf] * len(wtVec))
    moma = MomaAnalyzer(solver)

    # index of reaction group to be knocked out (as 0-dimensional numpy array)
    i = array(0, 'i')
    comm.Recv(i)
    while i >= 0:
        group, reaList = koGroups[i]

        # Restrict flux through all reactions in group to zero
        tmp_lb = {}  # {index in model : LB value}
        tmp_ub = {}  # {  - '' -       : UB  ''  }
        for rea in reaList:
            try:
                rIndex = model.reactionDict[rea]
            except KeyError:
                # Skip any blocked reactions (knockout has no effect)
                continue
            tmp_lb[rIndex] = model.reactions[rIndex].lb
            tmp_ub[rIndex] = model.reactions[rIndex].ub
            model.reactions[rIndex].lb = model.reactions[rIndex].ub = 0.

        if not tmp_lb:
            print "  - skipped group '%s' (only blocked reactions)" % group
            comm.Send(wtVec)
            comm.Recv(i)
            continue

        obj_val = lethalityCutoff + 1.

        # Perform FBA first to check for lethality
        if useMoma != When.ALWAYS:
            fba = FbAnalyzer(fbaParams.solver)
            # Note: Model is already reduced
            obj_val, solutionFlux = fba.runOnModel(model,
                                                   fbaParams,
                                                   rmDeadEnds=False)[:2]
            status = SolverStatus.PREPARED
            if not solutionFlux:
                obj_val = 0.

        # Perform MOMA if knockout not already predicted by FBA to be lethal
        if useMoma != When.NEVER and abs(obj_val) > lethalityCutoff:
            solutionFlux, status = moma.runOnModel(model, wtSolution,
                                                   fbaParams.linConstraints,
                                                   numIter, weights)[1:3]

        # Send result to dispatcher
        if status == SolverStatus.UNKNOWN:
            # If status is 'unknown, not converged', send vector with only 'nan'
            # entries
            comm.Send(nanVec)
        elif status in (SolverStatus.PRIM_INFEAS, SolverStatus.DUAL_INFEAS):
            # If status is 'infeasible', send vector with only 'inf' entries
            comm.Send(infVec)
        elif len(solutionFlux) == 0:
            if status == SolverStatus.PREPARED:
                # FBA infeasible
                comm.Send(infVec)
            else:
                comm.Send(nanVec)
        else:
            solutionVec = array(solutionFlux.getVecOrderedByModel(model))
            comm.Send(solutionVec)

        # Restore original constraints
        for rea in reaList:
            try:
                rIndex = model.reactionDict[rea]
            except KeyError:
                continue
            model.reactions[rIndex].lb = tmp_lb[rIndex]
            model.reactions[rIndex].ub = tmp_ub[rIndex]

        # Get next index
        comm.Recv(i)
示例#7
0
def parallel_ko_dispatch(comm,
                         numprocs,
                         model,
                         solver,
                         objective,
                         wtSolution,
                         wtObjVal=None,
                         koGroups=None,
                         filePrefix=None,
                         weights=None):
    """ root process (dispatcher) for parallel knockout analysis

    Keyword arguments:

    comm       -- MPI communicator
    numprocs   -- number of processes (including root process)
    model      -- the MetabolicModel
    solver     -- name of solver (or "default")
    objective  -- coefficient vector of linear objective function of FBA
    wtSolution -- FBA solution for wildtype
    wtObjVal   -- objective function value for wildtype solution (optional)
    koGroups   -- list of pairs (group name, list of reactions)
    filePrefix -- if given, write MOMA/FBA solutions to files starting with this
                  prefix; if empty, solutions are discarded
    weights    -- weight vector for weighted MOMA (None -> perform regular MOMA,
                  else: weight flux i with weights[i])

    Returns list of (distance, diff, obj_val) tuples, indexed like koGroups,

    distance -- value of actual MOMA/FBA objective function at solution
    diff     -- summed absolute difference between mutant and wildtype solutions
    obj_val  -- value of FBA objective function at MOMA/FBA solution for mutant
    """
    if not koGroups:
        koGroups = _makeDefaultKoGroups(model)


#    print "dispatch: %d reactions, %d knockout groups" % (len(model),
#                                                          len(koGroups))
    wtVec = wtSolution.getVecOrderedByModel(model)
    if wtObjVal is None:
        wtObjVal = dot(objective, wtVec)
    moma = MomaAnalyzer(solver)

    nJobs = len(koGroups)
    stopMsg = array(-1, 'i')  # stop message (-1)
    status = MPI.Status()
    result = [None] * nJobs
    jobList = [-1
               ] * numprocs  # mapping of process -> job (jobList[0] is dummy)
    # receive buffer for MOMA/FBA solution vectors
    solutionVec = empty(len(model), 'd')
    # index of next job to be processed (as 0-dimensional numpy array)
    nxt = array(0, 'i')
    free_processes = set(range(1, numprocs))  # set of processes free for work
    nDone = 0  # number of finished jobs

    while nDone < nJobs:
        while free_processes and nxt < nJobs:
            # Assign reaction to free process
            print koGroups[nxt][0]
            proc_index = free_processes.pop()
            # Send index of next job to next free process
            comm.Send(nxt, proc_index)
            # Mark in job list (int() is used to convert from ref. to literal)
            jobList[proc_index] = int(nxt)
            nxt += 1

        # If there are more processes than jobs, stop extra processes
        while free_processes:
            comm.Send(stopMsg, free_processes.pop())

        # Receive results from compute processes
        comm.Recv(solutionVec, MPI.ANY_SOURCE, status=status)
        proc_index = status.Get_source()

        # Test if solutionVec[0] is nan (nan means not converged)
        if solutionVec[0] != solutionVec[0]:
            result[jobList[proc_index]] = (nan, nan, 0.)
        elif solutionVec[0] == inf:
            # inf means infeasible, i.e. no solution exists
            result[jobList[proc_index]] = (inf, inf, 0.)
        else:
            jobIndex = jobList[proc_index]
            solutionFlux = MetabolicFlux(model, solutionVec)
            diff = sum(solutionFlux.absDiff(wtSolution).fluxDict.values())
            obj_val = max(0., dot(objective, solutionVec))
            distance = moma.evalObjFunc(wtVec, solutionVec, weights)
            result[jobIndex] = (distance, diff, obj_val)
            if filePrefix:
                solutionFlux.writeToFile(filePrefix + koGroups[jobIndex][0] +
                                         _FILE_SUFFIX)

        # Increase job counter and mark reporting process as free
        nDone += 1
        free_processes.add(proc_index)

    # Stop last compute process
    while free_processes:
        comm.Send(stopMsg, free_processes.pop())

    return result
示例#8
0
                _mpi_exit(comm, 1)

            if not fbaSolution.hasSameReactions(model):
                print(
                    "Error in file %s: FVA solution and model must have the "
                    "same reactions." % os.path.basename(options.wMomaFvaFile))
                _mpi_exit(comm, 1)

            weights = MomaAnalyzer.getWeightsFromFluxVar(
                model, wmomaMinmax, options.alpha, options.beta)

        # 7.a Read wildtype solution from file (if given)

        if options.wtSolution:
            # Read wildtype solution from file
            wtSolution = MetabolicFlux()
            try:
                wtSolution.readFromFile(options.wtSolution)
            except IOError, strerror:
                print("An error occurred while trying to read file %s:" %
                      os.path.basename(options.wtSolution))
                print strerror
                _mpi_exit(comm, 1)
            except SyntaxError, strerror:
                print("An error occurred parsing file %s:" %
                      os.path.basename(options.wtSolution))
                print strerror
                _mpi_exit(comm, 1)

            if not wtSolution.hasSameReactions(model):
                print(
示例#9
0
class ModelWatcher(object):
    """ Class for plausibility analysis of metabolic models
    """

    commentSign = '#'

    def __init__(self, model=None, fvaTolerance=.95):
        """ initialize watcher class

        Keyword arguments:

        model        -- MetabolicModel to be checked
        fvaTolerance -- objective function threshold for FVA
        """
        self.setModel(model)
        self.clearAssertions()
        self.fvaTolerance = fvaTolerance

    def clearAssertions(self):
        self.assertions, self.assertions_orig = [], []

    def setModel(self, model):
        """ set the MetabolicModel and reset flux and related variables
        """
        self.model = model
        self.flux = MetabolicFlux()
        self.metFlux, self.inRatios, self.outRatios = {}, {}, {}
        self.minFlux, self.maxFlux = {}, {}

    def readAssertionsFromFile(self, filename):
        """ parse the assertion file identified by filename
            -- wrapper for readAssertionsFromFileHandle()
        """
        with open(filename) as f:
            return self.readAssertionsFromFileHandle(f)

    def readAssertionsFromFileHandle(self, f):
        """ read the assertion file given as a file object

        Modified member variables:

        assertions_orig -- list of assertions in original format
        assertions      -- list of Python statements to be evaluated

        Comments and empty (or all-space) lines are removed
        """
        s = f.read()

        # Remove comments - everything from comment sign ('#') to end of line
        commentPos = 0
        while commentPos >= 0:
            commentPos = s.find(self.commentSign, commentPos)
            if commentPos >= 0:
                eolPos = s.find('\n', commentPos)
                if eolPos < 0:
                    # Last line - delete everything starting from comment sign
                    s = s[:commentPos]
                    commentPos = -1
                else:
                    # Excise comment
                    s = s[:commentPos] + s[eolPos:]

        if s.find(':') >= 0:
            raise SyntaxError('Illegal character found (:)')

        self.assertions_orig = s.split('\n')

        # Replace reaction and metabolite names with unique non-matching IDs
        # including a type specifier (r or m)

        idDict = dict(
            zip(self.model.reactionDict.keys(), "r" * len(self.model)) +
            zip(self.model.metaboliteDict.keys(), "m" *
                len(self.model.metaboliteDict)))

        # Find non-overlapping longest matches (greedy) of reaction and
        # metabolite names and replace with unique non-matching IDs
        counter = 0
        replaceDict, replaceDictRev = {}, {}
        for ID in sorted(idDict.keys(), key=len, reverse=True):
            pos = 0
            while pos >= 0:
                pos = s.find(ID, pos)
                if pos >= 0:
                    if ID in replaceDict:
                        replaceId = replaceDict[ID]
                    else:
                        # Generate new ID
                        replaceId = ":%u%c:" % (counter, idDict[ID])
                        replaceDict[ID] = replaceId
                        replaceDictRev[replaceId] = ID
                        counter += 1

                    s = s[:pos] + replaceId + s[pos + len(ID):]
                    pos = pos + len(replaceId) + 1

        reaString = r"(:\d+r:)"
        metString = r"(:\d+m:)"
        inratioPattern = re.compile(r"inratio\s*\(\s*" + metString +
                                    r"\s*,\s*" + reaString + r"\s*\)")
        outratioPattern = re.compile(r"outratio\s*\(\s*" + metString +
                                     r"\s*,\s*" + reaString + r"\s*\)")
        minPattern = re.compile(r"min\s*\(\s*" + reaString + r"\s*\)")
        maxPattern = re.compile(r"max\s*\(\s*" + reaString + r"\s*\)")
        reaPattern = re.compile(reaString)
        metPattern = re.compile(metString)

        # Replace inratio/outratio expressions with references to self.inRatios/
        #                                                         self.outRatios
        s = inratioPattern.sub(
            lambda x: "self.inRatios[%r].get(%r, 0.)" %
            (replaceDictRev[x.group(1)], replaceDictRev[x.group(2)]), s)
        s = outratioPattern.sub(
            lambda x: "self.outRatios[%r].get(%r, 0.)" %
            (replaceDictRev[x.group(1)], replaceDictRev[x.group(2)]), s)

        # Replace min/max expressions with references to self.minFlux/
        #                                                self.maxFlux
        s = minPattern.sub(
            lambda x: "self.minFlux[%r]" % replaceDictRev[x.group(1)], s)
        s = maxPattern.sub(
            lambda x: "self.maxFlux[%r]" % replaceDictRev[x.group(1)], s)

        # Replace reaction identifiers with references to self.flux
        s = reaPattern.sub(
            lambda x: "self.flux[%r]" % replaceDictRev[x.group(0)], s)

        # Replace metabolite identifiers with references to self.metFlux
        s = metPattern.sub(
            lambda x: "self.metFlux[%r]" % replaceDictRev[x.group(0)], s)

        self.assertions = s.split('\n')

        # Remove blank lines (cannot be evaluated)
        for i in range(len(self.assertions) - 1, -1, -1):
            if self.assertions[i] == "" or self.assertions[i].isspace():
                del self.assertions[i]
        for i in range(len(self.assertions_orig) - 1, -1, -1):
            if (self.assertions_orig[i] == ""
                    or self.assertions_orig[i].isspace()):
                del self.assertions_orig[i]

    def checkSyntax(self):
        """ check assertions for syntax errors without actually performing any
            potentially time-consuming analyses

        This function prints a message to the console for every assertion that
        contains a syntax error.

        Returns: True if all assertions can be evaluated, False if error occurs
        """
        # Backup member variables and re-initialize with dummy values to make
        # sure that all references exist
        bakflux, bakMetFlux = self.flux, self.metFlux
        bakInRatios, bakOutRatios = self.inRatios, self.outRatios
        bakMinFlux, bakMaxFlux = self.minFlux, self.maxFlux

        self.flux = MetabolicFlux(self.model, [0.] * len(self.model))
        self.metFlux = dict(
            zip(self.model.metabolites, [0.] * len(self.model.metabolites)))
        self.inRatios = dict(
            zip(self.model.metabolites, [{}] * len(self.model.metabolites)))
        self.outRatios = dict(
            zip(self.model.metabolites, [{}] * len(self.model.metabolites)))
        self.minFlux = dict(
            zip(self.model.reactionDict.keys(), [0.] * len(self.model)))
        self.maxFlux = dict(
            zip(self.model.reactionDict.keys(), [0.] * len(self.model)))
        excepted = []
        for i in range(len(self.assertions)):
            try:
                eval(self.assertions[i])
            except (SyntaxError, NameError):
                excepted.append(repr(self.assertions_orig[i]))

        # Restore member variables to original values
        self.flux, self.metFlux = bakflux, bakMetFlux
        self.inRatios, self.outRatios = bakInRatios, bakOutRatios
        self.minFlux, self.maxFlux = bakMinFlux, bakMaxFlux

        if excepted:
            print(
                "The following assertions cannot be evaluated due to errors"
                ":\n  " + "\n  ".join(excepted))
            #  The following was removed because the Python error messages are misleading.
            #            for a in excepted:
            #                print "\n  %r\n  %s: %s\n" % (a[0], a[1], a[2])
            return False
        return True

    def run(self, fbaParams, syntaxOk=True, printExcepted=False):
        """ check assertions against results of FBA, FVA, & split-ratio analysis

        This function performs FBA, split-ratio analysis, and FVA and evaluates
        the assertions. It enumerates all assertions that do not hold.

        Keyword arguments:
        fbaParams     -- objective function and solver for FBA
        syntaxOk      -- if False, previously performed syntax check has failed
        printExcepted -- if False, syntax errors in assertions are not reported
        """

        # 1. Perform flux balance analysis on the metabolic network

        fba = FbAnalyzer(fbaParams.solver)
        self.flux = fba.runOnModel(self.model, fbaParams)[1]
        if len(self.flux) == 0:
            print(
                "No FBA solution was obtained. The optimization problem is "
                "either unbounded or infeasible.")
            return

        # 2. Compute metabolite fluxes and split ratios

        splitRatios = self.flux.computeAllSplitRatios(self.model)
        self.metFlux, self.outRatios, self.inRatios = {}, {}, {}
        for met in splitRatios:
            outRatios, inRatios = splitRatios[met]
            self.metFlux[met] = sum(inRatios[rea][1] for rea in inRatios)
            self.outRatios[met] = dict(
                (rea, outRatios[rea][0]) for rea in outRatios)
            self.inRatios[met] = dict(
                (rea, inRatios[rea][0]) for rea in inRatios)

        # 3. Perform flux variability analysis on the model

        fva = FvAnalyzer("default")  # always use GLPK (=> fastFVA)
        minmax = fva.runOnModel(self.model, fbaParams, self.fvaTolerance,
                                self.flux)[0]

        self.minFlux, self.maxFlux = {}, {}
        for i in range(len(self.model)):
            self.minFlux[self.model.reactions[i].name], self.maxFlux[
                self.model.reactions[i].name] = minmax[i]

        # 4. Check assertions

        failed = []
        excepted = []
        for i in range(len(self.assertions)):
            try:
                if not eval(self.assertions[i]):
                    failed.append(repr(self.assertions_orig[i]))
            except (SyntaxError, NameError):
                excepted.append(repr(self.assertions_orig[i]))

        if printExcepted and excepted:
            print(
                "The following assertions could not be evaluated due to "
                "errors:\n  " + "\n  ".join(excepted))
        if failed:
            print "The following assertions failed:\n  " + "\n  ".join(failed)
        else:
            if not syntaxOk or (printExcepted and excepted):
                print "All other assertions hold."
            else:
                print "All assertions hold."
示例#10
0
def main():
    # 1. Parse command line

    usage = "Usage: %prog <solution-file> [options]"
    version = "Split-ratio analysis\n" + COPYRIGHT_VERSION_STRING
    parser = OptionParser(usage=usage, version=version)
    parser.add_option("-r",
                      "--reactions",
                      dest="reactionFile",
                      help="use "
                      "metabolic model given by reaction FILE",
                      metavar="FILE")
    parser.add_option("-m",
                      "--metabolite",
                      dest="metabolite",
                      help="NAME of "
                      "the single metabolite to be analyzed (optional)",
                      metavar="NAME")
    parser.add_option("-o",
                      "--output",
                      dest="outputFile",
                      help="perform "
                      "analysis for all metabolites and write output to FILE",
                      metavar="FILE")
    parser.add_option("-t",
                      "--omit-fluxes-below",
                      dest="threshold",
                      type="float",
                      help="omit metabolites in output whose flux"
                      " is below the given THRESHOLD (only with -o)",
                      metavar="THRESHOLD")
    parser.add_option("-u",
                      "--omit-unbranched",
                      dest="omitUnbranched",
                      action="store_true",
                      help="if set, metabolites with "
                      "unbranched flux are omitted (only with -o)")
    parser.add_option("-c",
                      "--cutoff",
                      dest="cutoff",
                      type="float",
                      help="use "
                      "the given cutoff VALUE (default 0)",
                      metavar="VALUE")
    parser.add_option("-f",
                      "--cutoff-is-absolute",
                      dest="cutoffIsAbsolute",
                      action="store_true",
                      help="if set, cutoff is in absolute "
                      "flux units rather than a value between 0 and 1")
    parser.add_option(
        "-a",
        "--list-all",
        dest="listAll",
        action="store_true",
        help="if set, cutoff is ignored, and even zero fluxes are"
        " shown (per definition as outgoing)")
    parser.set_defaults(threshold=-1.,
                        omitUnBranched=False,
                        cutoff=0.,
                        cutoffIsAbsolute=False,
                        listAll=False)

    options, args = parser.parse_args()
    parser.check_required('-r')

    if not options.metabolite and not options.outputFile:
        print "Neither metabolite nor output file given. Nothing to do."
        exit()

    # 2. Read solution file

    solution = MetabolicFlux()
    try:
        solution.readFromFile(args[0])
    except IndexError:
        print("Error: No solution file given.\nUsage is\n    " +
              os.path.basename(sys.argv[0]) + " <solution-file> [options]")
        exit()
    except IOError, strerror:
        print("An error occurred while trying to read file %s:" %
              os.path.basename(args[0]))
        print strerror
        exit()
示例#11
0
    try:
        model.addReactionsFromFile(options.reactionFile, rparser)
    except IOError, strerror:
        print("An error occurred while trying to read file %s:" %
              os.path.basename(options.reactionFile))
        print strerror
        exit()
    except SyntaxError, strerror:
        print("Error in reaction file %s:" %
              os.path.basename(options.reactionFile))
        print strerror
        exit()

    # 3. Parse solution file

    solution = MetabolicFlux()
    try:
        solution.readFromFile(options.solutionFile)
    except IOError, strerror:
        print("An error occurred while trying to read file %s:" %
              os.path.basename(options.solutionFile))
        print strerror
        exit()
    except SyntaxError, strerror:
        print("Error in solution file %s:" %
              os.path.basename(options.solutionFile))
        print strerror
        exit()

    # 4. Count metabolites' participation in active reactions
示例#12
0
    def runOnModel(self,
                   model,
                   wtSolution,
                   linConstraints=[],
                   numIter=1,
                   weights=None,
                   blockedReactions=[]):
        """ construct and solve the quadratic optimization problem
          - this function runs directly on a MetabolicModel and a MetabolicFlux

        Keyword arguments:

        model          -- the MetabolicModel
        wtSolution     -- FBA solution for the wildtype (given as MetabolicFlux)
        linConstraints -- list of LinearConstraint objects
        numIter        -- number of iterations of NLP to perform
        weights        -- weight vector for weighted MOMA (None -> perform
                          regular MOMA, else: weight flux i with weights[i])
        blockedReactions
                       -- remove the given blocked reactions before analysis
                          (faster and gives an optimal solution, as well)

        Returns:
        distance, solution, status, dimReduced

        distance   -- minimum possible distance from wtSolution with the given
                      matrix & constraints
        solution   -- a solution with minimal distance to wtSolution
                     (as MetabolicFlux)
        status     -- SolverStatus after optimization
        dimReduced -- pair (nRows, nColumns) with dimensions of reduced matrix
        """
        if blockedReactions:
            modelRed = model.getSubModelByExcludeList(blockedReactions)
            cbz = model.canBeZero(blockedReactions)
            nonZeroDeadEnds = [
                blockedReactions[i] for i in range(len(blockedReactions))
                if not cbz[i]
            ]
            if nonZeroDeadEnds:
                print(
                    "The following blocked reactions are constrained to a "
                    "non-zero flux:\n  " + "\n  ".join(nonZeroDeadEnds) +
                    "\nThe problem is infeasible.")
                return (nan, MetabolicFlux(), SolverStatus.PRIM_INFEAS,
                        array(modelRed.getStoichiometricMatrix()).shape)

            reactionsRed = set(modelRed.getReactionNames())
            if weights is None:
                weightsRed = None
            else:
                weightsRed = [0.] * len(modelRed)
                for rea in wtSolution:
                    if rea in reactionsRed:
                        weightsRed[modelRed.reactionDict[rea]] = \
                            weights[model.reactionDict[rea]]
                    weightsRed = array(weightsRed)
        else:
            modelRed = model
            weightsRed = weights

        matrix = array(modelRed.getStoichiometricMatrix())
        dimReduced = matrix.shape
        lb, ub = map(array, modelRed.getBounds())
        try:
            eqs, ineqs = ParamParser.linConstraintsToVectors(
                linConstraints, modelRed.reactionDict)
        except ValueError:
            # If any linear constraint is contradictory, return empty solution
            return (nan, MetabolicFlux(), SolverStatus.PRIM_INFEAS,
                    array(modelRed.getStoichiometricMatrix()).shape)

        distance, solution, status = self.run(
            matrix, lb, ub, wtSolution.getVecOrderedByModel(modelRed), eqs,
            ineqs, numIter, weightsRed)
        flux = MetabolicFlux(modelRed, solution)

        # Add removed reactions with flux 0. and original bounds to solution
        if len(modelRed) != len(model) and solution != []:
            reactionsRed = set(modelRed.getReactionNames())
            for rea in model:
                if rea.name not in reactionsRed:
                    flux.fluxDict[rea.name] = 0.
                    flux.boundsDict[rea.name] = (rea.lb, rea.ub)

        return distance, flux, status, dimReduced
示例#13
0
        print("An error occurred while trying to read file %s:" %
              os.path.basename(options.paramFile))
        print strerror
        exit()
    except SyntaxError, strerror:
        print("Error in scenario file %s:" %
              os.path.basename(options.paramFile))
        print strerror
        exit()
    except ValueError, strerror:
        print strerror
        exit()

    # 4. Parse solution file for wildtype

    wtFlux = MetabolicFlux()
    try:
        wtFlux.readFromFile(options.wtSolution)
    except IOError, strerror:
        print("An error occurred while trying to read file %s:" %
              os.path.basename(options.wtSolution))
        print strerror
        exit()
    except SyntaxError, strerror:
        print("An error occurred parsing file %s:" %
              os.path.basename(options.wtSolution))
        print strerror
        exit()

    if not wtFlux.hasSameReactions(model):
        print "Error: Solution and model must have the same reactions."
示例#14
0
    def runOnModel(self,
                   model,
                   fbaParams,
                   threshp=.95,
                   solution=None,
                   splitFluxes=True,
                   rmDeadEnds=True):
        """ perform flux variability analysis on the given model with
            objective value <= threshp * maximum

        Keyword arguments:

        model        -- the MetabolicModel
        fbaParams    -- FBA parameters
        threshp      -- threshold percentage (objective_value <= thresp*maximum)
        solution     -- optional: either FBA solution file or solution as
                        MetabolicFlux object
        splitFluxes  -- if True, run split fluxes (resulting in non-negative
                        flux variables) before FBA
        rmDeadEnds   -- if True, remove all reactions with dead ends before
                        analysis (faster and gives an optimal solution, as well)

        Returns:
        minmax, sFlux, lb, ub, dimReduced

        minmax       -- list of pairs (minimum, maximum), indexed like reactions
        sFlux        -- FBA solution (vector indexed like reactions)
        lb, ub       -- lower/upper bounds vectors, indexed like reactions
        dimReduced   -- pair (nRows, nColumns) with dimensions of reduced matrix
        """
        if rmDeadEnds:
            deadReactions = model.findDeadEnds(True)[1]
            modelRed = model.getSubModelByExcludeList(deadReactions)
            cbz = model.canBeZero(deadReactions)
            nonZeroDeadEnds = [
                deadReactions[i] for i in range(len(deadReactions))
                if not cbz[i]
            ]
            if nonZeroDeadEnds:
                print(
                    "The following blocked reactions are constrained to a "
                    "non-zero flux:\n  " + "\n  ".join(nonZeroDeadEnds) +
                    "\nThe problem is infeasible.")
                lbFull, ubFull = map(array, model.getBounds())
                return ([], MetabolicFlux(), lbFull, ubFull,
                        array(modelRed.getStoichiometricMatrix()).shape)
        else:
            modelRed = model

        matrix = array(modelRed.getStoichiometricMatrix())
        dimReduced = matrix.shape
        lb, ub = map(array, modelRed.getBounds())

        # Build (negative) objective function vector
        objective = ParamParser.convertObjFuncToLinVec(fbaParams.objStr,
                                                       modelRed.reactionDict,
                                                       -1, fbaParams.maxmin)
        maxmin_factor = -1. if fbaParams.maxmin else 1.

        # Case 1. If an FBA solution is given, use that

        if isinstance(solution, MetabolicFlux):
            # Sort solution like matrix columns
            sFlux = solution.getVecOrderedByModel(modelRed)
            # Evaluate the objective function at solution
            obj_value = maxmin_factor * dot(objective, sFlux)

        # Case 2. If solution file is given, read solution

        elif solution is not None:
            sFlux = MetabolicFlux()
            try:
                sFlux.readFromFile(solution)
            except IOError, strerror:
                print("An error occurred while trying to read file %s:" %
                      os.path.basename(solution))
                print strerror
                exit()
            except SyntaxError, strerror:
                print("An error occurred parsing file %s:" %
                      os.path.basename(solution))
                print strerror
                exit()
示例#15
0
    def runOnModel(self,
                   model,
                   fbaParams,
                   splitFluxes=True,
                   minimizeTotalFlux=False,
                   rmDeadEnds=True):
        """ run flux-balance analysis on the given MetabolicModel

        Keyword arguments:

        model       -- the MetabolicModel with reactions and bounds
        fbaParams   -- optimization parameters (incl. objective function)
        splitFluxes -- if True, run split fluxes (resulting in non-negative flux
                       variables) before analysis
        minimizeTotalFlux
                    -- if True, find a solution with minimal total absolute flux
        rmDeadEnds   -- if True, remove all reactions with dead ends before
                        analysis (faster and gives an optimal solution, as well)

        Returns:
        obj_value, solution, dimReduced

        obj_value   -- optimal value of objective function
        solution    -- a solution where the objective function assumes obj_value
        dimReduced  -- pair (nRows, nColumns) with dimensions of reduced matrix
        """
        maxmin = fbaParams.maxmin
        objStr = fbaParams.objStr

        if isinstance(maxmin, str):
            maxmin = {"max": True, "min": False}[maxmin.lower()]

        if rmDeadEnds:
            deadReactions = model.findDeadEnds(True)[1]
            modelRed = model.getSubModelByExcludeList(deadReactions)
            cbz = model.canBeZero(deadReactions)
            nonZeroDeadEnds = [
                deadReactions[i] for i in range(len(deadReactions))
                if not cbz[i]
            ]
            if nonZeroDeadEnds:
                print(
                    "The following blocked reactions are constrained to a "
                    "non-zero flux:\n  " + "\n  ".join(nonZeroDeadEnds) +
                    "\nThe problem is infeasible.")
                return (0., MetabolicFlux(),
                        array(modelRed.getStoichiometricMatrix()).shape)
        else:
            modelRed = model

        matrix = array(modelRed.getStoichiometricMatrix())
        dimReduced = matrix.shape
        reaction_names = modelRed.getReactionNames()
        reactions = modelRed.reactionDict
        lb, ub = modelRed.getBounds()

        if splitFluxes:
            matrixSplit, reactionsSplit, lbSplit, ubSplit = \
                self.splitFluxes(matrix, reaction_names, lb, ub)
            try:
                ParamParser.convertObjFuncToLinVec(objStr, reactionsSplit,
                                                   len(lbSplit), maxmin)
            except KeyError, s:
                if deadReactions:
                    print(
                        "Error while trying to construct the objective "
                        "function vector:\n%s\nThis may be due to removal "
                        "of nonfunctional reactions." % s)
                    return 0., MetabolicFlux(), dimReduced

            obj_value, solutionSplit = self.run(reactionsSplit, matrixSplit,
                                                lbSplit, ubSplit, fbaParams)
            solution = []
            try:
                if solutionSplit == []:
                    solution = []
                else:
                    if minimizeTotalFlux:
                        # Optimize solution by limiting total flux
                        limit, obj_value, solutionSplit, nSteps = \
                            self.runWithTotalFluxMinimization(reactionsSplit,
                                matrixSplit, lbSplit, ubSplit, fbaParams,
                                sum(solutionSplit), 1e-8, 1e-12)
                        print(
                            "Found optimal flux limit of %.10g in %u steps." %
                            (limit, nSteps))

                    solution = array(
                        FbAnalyzer.rejoinFluxes(solutionSplit, reactionsSplit,
                                                reactions))
            except NameError, strerror:
                print strerror
示例#16
0
                                matrixSplit, lbSplit, ubSplit, fbaParams,
                                sum(solutionSplit), 1e-8, 1e-12)
                        print(
                            "Found optimal flux limit of %.10g in %u steps." %
                            (limit, nSteps))

                    solution = array(
                        FbAnalyzer.rejoinFluxes(solutionSplit, reactionsSplit,
                                                reactions))
            except NameError, strerror:
                print strerror

        else:
            obj_value, solution = self.run(reactions, matrix, lb, ub,
                                           fbaParams)
        flux = MetabolicFlux(modelRed, solution)

        # Add removed reactions with flux 0. and original bounds to solution
        if len(modelRed) != len(model) and len(solution) != 0:
            reactionsRed = set(reaction_names)
            for rea in model:
                if rea.name not in reactionsRed:
                    flux.fluxDict[rea.name] = 0.
                    flux.boundsDict[rea.name] = (rea.lb, rea.ub)

        return obj_value, flux, dimReduced


def main():
    # 1. Parse command line