#215 GrowthCouplingPotential

Open Kristian Jensen KristianJensen
Coverage Reach
strain_design/heuristic/evolutionary/optimization.py strain_design/heuristic/evolutionary/multiprocess/observers.py strain_design/heuristic/evolutionary/multiprocess/optimization.py strain_design/heuristic/evolutionary/multiprocess/plotters.py strain_design/heuristic/evolutionary/multiprocess/migrators.py strain_design/heuristic/evolutionary/multiprocess/__init__.py strain_design/heuristic/evolutionary/objective_functions.py strain_design/heuristic/evolutionary/variators.py strain_design/heuristic/evolutionary/archives.py strain_design/heuristic/evolutionary/plotters.py strain_design/heuristic/evolutionary/evaluators.py strain_design/heuristic/evolutionary/stats.py strain_design/heuristic/evolutionary/processing.py strain_design/heuristic/evolutionary/generators.py strain_design/heuristic/evolutionary/decoders.py strain_design/heuristic/evolutionary/observers.py strain_design/heuristic/evolutionary/genomes.py strain_design/heuristic/evolutionary/metrics.py strain_design/heuristic/evolutionary/__init__.py strain_design/heuristic/evolutionary_based.py strain_design/heuristic/__init__.py strain_design/deterministic/flux_variability_based.py strain_design/deterministic/linear_programming.py strain_design/deterministic/__init__.py strain_design/pathway_prediction/pathway_predictor.py strain_design/pathway_prediction/util.py strain_design/pathway_prediction/__init__.py strain_design/__init__.py flux_analysis/analysis.py flux_analysis/structural.py flux_analysis/simulation.py flux_analysis/util.py flux_analysis/__init__.py core/target.py core/strain_design.py core/model_dual.py core/pathway.py core/utils.py core/manipulation.py core/result.py core/__init__.py api/designer.py api/products.py api/hosts.py api/__init__.py models/webmodels.py models/universal.py models/__init__.py parallel.py io.py network_analysis/networkx_based.py network_analysis/util.py network_analysis/__init__.py config.py data/metanetx.py exceptions.py

No flags found

Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.

e.g., #unittest #integration

#production #enterprise

#frontend #backend

Learn more about Codecov Flags here.


@@ -31,6 +31,10 @@
Loading
31 31
from cobra.exceptions import OptimizationError
32 32
from cobra.flux_analysis import find_essential_reactions
33 33
34 +
import optlang
35 +
from optlang.duality import convert_linear_problem_to_dual
36 +
37 +
import cameo
34 38
from cameo import config
35 39
from cameo import ui
36 40
from cameo.core.model_dual import convert_to_dual
@@ -44,7 +48,7 @@
Loading
44 48
45 49
logger = logging.getLogger(__name__)
46 50
47 -
__all__ = ["OptKnock"]
51 +
__all__ = ["OptKnock", "GrowthCouplingPotential"]
48 52
49 53
50 54
class OptKnock(StrainDesignMethod):
@@ -125,7 +129,7 @@
Loading
125 129
        if exclude_reactions:
126 130
            # Convert exclude_reactions to reaction ID's
127 131
            exclude_reactions = [
128 -
                r.id if isinstance(r, cobra.core.Reaction) else r for r in exclude_reactions
132 +
                r.id if isinstance(r, cobra.Reaction) else r for r in exclude_reactions
129 133
            ]
130 134
            for r_id in exclude_reactions:
131 135
                if r_id not in self._model.reactions:
@@ -425,3 +429,386 @@
Loading
425 429
        </ul>
426 430
        %s""" % (self._target, self.data_frame._repr_html_())
427 431
        return html_string
432 +
433 +
434 +
class GrowthCouplingPotential(StrainDesignMethod):
435 +
    """
436 +
    Optimize the Growth Coupling Potential through a combination of knockouts, knockins and medium additions
437 +
438 +
    Use the 'run' method to optimize the MILP problem and find the best solution.
439 +
440 +
    In order to find multiple sub-optimal solutions through the use of solution pools, please refer to the
441 +
    relevant solvers documentation. The underlying solver object can be accessed through
442 +
        GrowthCouplingPotential(...).model.solver.problem
443 +
444 +
    The method is described in the paper "OptCouple: Joint simulation of gene knockouts,
445 +
    insertions and medium modifications for prediction of growth-coupled strain designs"
446 +
    https://www.sciencedirect.com/science/article/pii/S2214030118300373
447 +
448 +
    Attributes
449 +
    ----------
450 +
    model : cobra.Model
451 +
        A cobra model object containing the target reaction as well as all native and heterologous reactions.
452 +
    target : cobra.Reaction or string
453 +
        The reaction (or reaction ID) that is to be growth-coupled
454 +
    knockout_reactions : list
455 +
        A list of ID's for the reactions that the algorithm should attempt to knock out
456 +
    knockin_reactions : list
457 +
        A List of ID's for the reactions that are heterologous and that the algorithm should attempt to add
458 +
    medium_additions : list
459 +
        A list of metabolite ID's for the the metabolites that should potentially be added to the medium
460 +
    n_knockouts : int
461 +
        The maximum allowed number of knockouts
462 +
    n_knockins : int
463 +
        The maximum allowed number of knockins
464 +
    n_medium : int
465 +
        The maximum allowed number of medium additions
466 +
    use_solution_pool : Bool
467 +
        Set to True when using the Gurobi solver to identify multiple alternative solutions at once
468 +
    """
469 +
    def __init__(
470 +
            self, model, target, biomass_id, knockout_reactions, knockin_reactions, medium_additions,
471 +
            n_knockouts, n_knockin, n_medium, remove_blocked=True, use_solution_pool=False, **kwargs
472 +
    ):
473 +
        super(GrowthCouplingPotential, self).__init__(**kwargs)
474 +
475 +
        # Check model for forced fluxes, which should not be present. The zero solution must be allowed.
476 +
        for r in model.reactions:
477 +
            if r.lower_bound > 0 or r.upper_bound < 0:
478 +
                raise ValueError(
479 +
                    "%s has a forced flux. Remove the reaction or change its bounds for the function to work." % r.id)
480 +
481 +
        # If a cobra.Reaction is given as target, convert to its ID string.
482 +
        if isinstance(target, cobra.Reaction):
483 +
            target = target.id
484 +
        self.target = target
485 +
486 +
        if target not in knockout_reactions:
487 +
            knockout_reactions.append(target)
488 +
489 +
        self.original_model = model
490 +
        self.biomass_id = biomass_id
491 +
        self.model = model = model.copy()
492 +
493 +
        # Add boundary reactions for these metabolites named "ADD_<metabolitename>" to the model, with bounds (-10,0).
494 +
        medium_addition_reactions = []  # List of the addition reactions added to the model
495 +
        for m in medium_additions:
496 +
            met = model.metabolites.get_by_id(m)
497 +
            r = model.add_boundary(met, type="medium addition", reaction_id=("ADD_" + m), lb=-10, ub=0)
498 +
            # r.type = "medium"
499 +
            medium_addition_reactions.append(r.id)
500 +
501 +
        # Set the solver to Gurobi for the fastest result. Set to CPLEX if Gurobi is not available.
502 +
        if "gurobi" in cobra.util.solver.solvers.keys():
503 +
            logger.info("Changing solver to Gurobi and tweaking some parameters.")
504 +
            if "gurobi_interface" not in model.solver.interface.__name__:
505 +
                model.solver = "gurobi"
506 +
            # The tolerances are set to the minimum value. This gives maximum precision.
507 +
            problem = model.solver.problem
508 +
            problem.params.NodeMethod = 1  # primal simplex node relaxation
509 +
            problem.params.FeasibilityTol = 1e-9
510 +
            problem.params.OptimalityTol = 1e-3
511 +
            problem.params.IntFeasTol = 1e-9
512 +
            problem.params.MIPgapAbs = 1e-9
513 +
            problem.params.MIPgap = 1e-9
514 +
515 +
        elif "cplex" in cobra.util.solver.solvers.keys():
516 +
            logger.warning(
517 +
                "Changing solver to CPLEX, as Gurobi is not available."
518 +
                "This may cause a big slowdown and limit options afterwards.")
519 +
            if "cplex_interface" not in model.solver.interface.__name__:
520 +
                model.solver = "cplex"
521 +
            # The tolerances are set to the minimum value. This gives maximum precision.
522 +
            problem = model.solver.problem
523 +
            problem.parameters.mip.strategy.startalgorithm.set(1)  # primal simplex node relaxation
524 +
            problem.parameters.simplex.tolerances.feasibility.set(1e-9)
525 +
            problem.parameters.simplex.tolerances.optimality.set(1e-3)
526 +
            problem.parameters.mip.tolerances.integrality.set(1e-9)
527 +
            problem.parameters.mip.tolerances.absmipgap.set(1e-9)
528 +
            problem.parameters.mip.tolerances.mipgap.set(1e-9)
529 +
530 +
        else:
531 +
            logger.warning("You are trying to run 'GrowthCouplingPotential' with %s. This might not end well." %
532 +
                           model.solver.interface.__name__.split(".")[-1])
533 +
534 +
        # Remove reactions that are blocked: no flux through these reactions possible.
535 +
        # This will reduce the search space for the solver, if not done already.
536 +
        if remove_blocked:
537 +
            blocked_reactions = cameo.flux_analysis.analysis.find_blocked_reactions(model)
538 +
            model.remove_reactions(blocked_reactions)
539 +
            blocked_reaction_ids = {r.id for r in blocked_reactions}
540 +
            knockout_reactions = {r for r in knockout_reactions if r not in blocked_reaction_ids}
541 +
            knockin_reactions = {r for r in knockin_reactions if r not in blocked_reaction_ids}
542 +
            medium_additions = {r for r in medium_additions if r not in blocked_reaction_ids}
543 +
            logger.debug("Removed " + str(len(blocked_reactions)) + " reactions that were blocked")
544 +
545 +
        # Make dual
546 +
        copied_model = model.copy()
547 +
        copied_model.optimize()
548 +
        dual_problem = convert_linear_problem_to_dual(copied_model.solver)
549 +
        logger.debug("Dual problem successfully created")
550 +
551 +
        # Combine primal and dual
552 +
        primal_problem = model.solver
553 +
554 +
        for var in dual_problem.variables:  # All variables in the dual are copied to the primal
555 +
            var = primal_problem.interface.Variable.clone(var)
556 +
            primal_problem.add(var)
557 +
        for const in dual_problem.constraints:  # All constraints in the dual are copied to the primal
558 +
            const = primal_problem.interface.Constraint.clone(const, model=primal_problem)
559 +
            primal_problem.add(const)
560 +
        logger.debug("Dual and primal combined")
561 +
562 +
        dual_problem.optimize()
563 +
564 +
        # Dictionaries to hold the binary control variables:
565 +
        native_y_vars = {}  # 1 for knockout, 0 for active
566 +
        heterologous_y_vars = {}  # 1 for knockin, 0 for inactive
567 +
        medium_y_vars = {}  # 1 for medium addition (up to -10), 0 for no addition
568 +
569 +
        # Now the fun stuff
570 +
        constrained_dual_vars = set()
571 +
        M = max(-cobra.Configuration().lower_bound, cobra.Configuration().upper_bound)  # Large value for big-M method
572 +
573 +
        # Fill the dictionaries with binary variables
574 +
        # For the knockouts: only for the native reactions which are not exchanges
575 +
        for reac_id in knockout_reactions:
576 +
            reaction = model.reactions.get_by_id(reac_id)
577 +
578 +
            # Add constraint variables
579 +
            interface = model.solver.interface
580 +
            y_var = interface.Variable("y_" + reaction.id, type="binary")
581 +
582 +
            # Constrain the primal: flux through reactions within (-1000, 1000)
583 +
            model.solver.add(interface.Constraint(reaction.flux_expression - M * (1 - y_var), ub=0,
584 +
                                                  name="primal_y_const_" + reaction.id + "_ub"))
585 +
            model.solver.add(interface.Constraint(reaction.flux_expression + M * (1 - y_var), lb=0,
586 +
                                                  name="primal_y_const_" + reaction.id + "_lb"))
587 +
588 +
            # Constrain the dual
589 +
            constrained_vars = []
590 +
591 +
            if reaction.upper_bound != 0:
592 +
                dual_forward_ub = model.solver.variables["dual_" + reaction.forward_variable.name + "_ub"]
593 +
                model.solver.add(interface.Constraint(dual_forward_ub - M * y_var, ub=0))
594 +
                constrained_vars.append(dual_forward_ub)
595 +
            if reaction.lower_bound != 0:
596 +
                dual_reverse_ub = model.solver.variables["dual_" + reaction.reverse_variable.name + "_ub"]
597 +
                model.solver.add(interface.Constraint(dual_reverse_ub - M * y_var, ub=0))
598 +
                constrained_vars.append(dual_reverse_ub)
599 +
            constrained_dual_vars.update(constrained_vars)
600 +
601 +
            # Add to dictionary with binary variables for native reactions:
602 +
            native_y_vars[y_var] = reaction
603 +
604 +
        # For the knockins and medium additions:
605 +
        for reac_id in list(knockin_reactions) + list(medium_addition_reactions):
606 +
            reaction = model.reactions.get_by_id(reac_id)
607 +
            # Add constraint variables
608 +
            interface = model.solver.interface
609 +
            y_var = interface.Variable("y_" + reaction.id, type="binary")
610 +
611 +
            # Constrain the primal: flux through reaction within (-1000, 1000)
612 +
            model.solver.add(interface.Constraint(reaction.flux_expression - M * y_var, ub=0,
613 +
                                                  name="primal_y_const_" + reaction.id + "_ub"))
614 +
            model.solver.add(interface.Constraint(reaction.flux_expression + M * y_var, lb=0,
615 +
                                                  name="primal_y_const_" + reaction.id + "_lb"))
616 +
617 +
            # Constrain the dual
618 +
            constrained_vars = []
619 +
620 +
            if reaction.upper_bound != 0:
621 +
                dual_forward_ub = model.solver.variables["dual_" + reaction.forward_variable.name + "_ub"]
622 +
                model.solver.add(interface.Constraint(dual_forward_ub - M * (1 - y_var), ub=0))
623 +
                constrained_vars.append(dual_forward_ub)
624 +
            if reaction.lower_bound != 0:
625 +
                dual_reverse_ub = model.solver.variables["dual_" + reaction.reverse_variable.name + "_ub"]
626 +
                model.solver.add(interface.Constraint(dual_reverse_ub - M * (1 - y_var), ub=0))
627 +
                constrained_vars.append(dual_reverse_ub)
628 +
            constrained_dual_vars.update(constrained_vars)
629 +
630 +
            # Add y variable to the corresponding modifications dictionary
631 +
            if reac_id in medium_addition_reactions:  # reaction.type == "medium":
632 +
                medium_y_vars[y_var] = reaction
633 +
            elif reac_id in knockin_reactions:  # reaction.type == "heterologous":
634 +
                heterologous_y_vars[y_var] = reaction
635 +
            else:
636 +
                raise RuntimeError("Something is wrong")
637 +
638 +
        logger.debug("Control variables created")
639 +
640 +
        # Set the objective
641 +
        primal_objective = model.solver.objective
642 +
        dual_objective = interface.Objective.clone(
643 +
            dual_problem.objective, model=model.solver
644 +
        )
645 +
646 +
        reduced_expression = optlang.symbolics.Add(
647 +
            *((c * v) for v, c in dual_objective.expression.as_coefficients_dict().items()
648 +
              if v not in constrained_dual_vars)
649 +
        )
650 +
        dual_objective = interface.Objective(reduced_expression, direction=dual_objective.direction)
651 +
652 +
        full_objective = interface.Objective(primal_objective.expression - dual_objective.expression, direction="max")
653 +
        model.objective = full_objective
654 +
        logger.debug("Objective created")
655 +
656 +
        # Add number of knockouts constraint. ub=K+1 as the target will be forced to be 1 as well
657 +
        knockout_number_constraint = model.solver.interface.Constraint(
658 +
            optlang.symbolics.Add(*native_y_vars), lb=0, ub=n_knockouts + 1, name="number_of_knockouts_constraint"
659 +
        )
660 +
        model.solver.add(knockout_number_constraint)
661 +
662 +
        # Add number of knockins constraint
663 +
        knockin_number_constraint = model.solver.interface.Constraint(
664 +
            optlang.symbolics.Add(*heterologous_y_vars), lb=0, ub=n_knockin, name="number_of_knockins_constraint"
665 +
        )
666 +
        model.solver.add(knockin_number_constraint)
667 +
668 +
        # Add number of medium additions constraint
669 +
        medium_additions_number_constraint = model.solver.interface.Constraint(
670 +
            optlang.symbolics.Add(*medium_y_vars), lb=0, ub=n_medium, name="number_of_medium_additions_constraint"
671 +
        )
672 +
        model.solver.add(medium_additions_number_constraint)
673 +
674 +
        logger.debug("Added constraint for number of knockouts, knockins and medium additions")
675 +
676 +
        # Force target control variable to be 1, but allow flux in primal
677 +
        model.solver.constraints["primal_y_const_" + target + "_lb"].lb = -2000
678 +
        model.solver.constraints["primal_y_const_" + target + "_ub"].ub = 2000
679 +
        model.variables["y_" + target].lb = 1
680 +
681 +
        self.model = model
682 +
        self.native_y_vars = native_y_vars
683 +
        self.heterologous_y_vars = heterologous_y_vars
684 +
        self.medium_y_vars = medium_y_vars
685 +
686 +
        self.knockout_reactions = knockout_reactions
687 +
        self.knockin_reactions = knockin_reactions
688 +
        self.medium_additions = medium_additions
689 +
690 +
        self.use_solution_pool = use_solution_pool
691 +
692 +
        self.model.solver.configuration.presolve = True
693 +
694 +
        if use_solution_pool:
695 +
            if "gurobi_interface" not in model.solver.interface.__name__:
696 +
                raise NotImplementedError("Solution pools are currently only available with the Gurobi solver")
697 +
698 +
            # Find the N best solutions (N is specified as pool_size in run())
699 +
            self.model.solver.problem.params.PoolSearchMode = 2
700 +
701 +
            # Don't store solutions with objective = 0
702 +
            self.model.solver.problem.params.PoolGap = 0.99
703 +
704 +
    def run(self, pool_size=None, pool_time_limit=None):
705 +
        """
706 +
        Run the GrowthCouplingPotential method
707 +
708 +
        pool_size: None or int
709 +
            The number of alternative solutions to find (0 - 2,000,000,000)
710 +
        pool_time_limit: None or int
711 +
            The maximum time (in seconds) to spend finding solutions. Will terminate with a time_limit status.
712 +
        """
713 +
        if self.use_solution_pool:
714 +
            if pool_size is not None:
715 +
                self.model.solver.problem.params.PoolSolutions = pool_size
716 +
717 +
            if pool_time_limit is not None:
718 +
                self.model.solver.problem.params.TimeLimit = pool_time_limit
719 +
720 +
        sol = self.model.optimize()
721 +
722 +
        if self.use_solution_pool:
723 +
            solution_pool = self.extract_gurobi_solution_pool()
724 +
            return solution_pool
725 +
        else:
726 +
            objective_value = sol.objective_value
727 +
            knockouts = [
728 +
                reac.id for var, reac in self.native_y_vars.items() if var.primal > 0.9 and reac.id != self.target
729 +
            ]
730 +
            knockins = [reac.id for var, reac in self.heterologous_y_vars.items() if var.primal > 0.9]
731 +
            medium_additions = [reac.id for var, reac in self.medium_y_vars.items() if var.primal > 0.9]
732 +
            return {
733 +
                "knockouts": knockouts,
734 +
                "knockins": knockins,
735 +
                "medium": medium_additions,
736 +
                "obj_val": objective_value
737 +
            }
738 +
739 +
    def extract_gurobi_solution_pool(self):
740 +
        """
741 +
        Extracts the individual solutions from an MILP solution pool created by the Gurobi solver.
742 +
        Returns the solution pool and a header with information to accompany the list of dicts.
743 +
        """
744 +
745 +
        target_id = self.target
746 +
        biomass_id = self.biomass_id
747 +
748 +
        milp = self.model
749 +
        if "gurobi_interface" not in milp.solver.interface.__name__:
750 +
            raise ValueError(
751 +
                "The solver for the MILP is not Gurobi. This function only works for Gurobi created solution pools.")
752 +
        if target_id not in milp.solver.problem.getVars():
753 +
            raise ValueError("Specified target reaction ID %s not found in the variable list." % target_id)
754 +
        if biomass_id not in milp.solver.problem.getVars():
755 +
            raise ValueError("Specified biomass reaction ID %s not found in the variable list." % biomass_id)
756 +
757 +
        solution_pool = []
758 +
        for solution_number in range(milp.solver.problem.solcount):
759 +
            solution = {}
760 +
            milp.solver.problem.params.SolutionNumber = solution_number
761 +
            solution["number"] = solution_number
762 +
            # Note that the objective is the growth coupling potential, not the growth or production rate
763 +
            solution["objective"] = milp.solver.problem.PoolObjVal
764 +
765 +
            # Prepare dict for looping over variables
766 +
            target_flux_name = "target_flux_(%s)" % target_id
767 +
            biomass_id_reverse = biomass_id + "_reverse_"
768 +
            target_id_reverse = target_id + "_reverse_"
769 +
770 +
            solution["growth_coupling_slope"] = None
771 +
            solution[target_flux_name] = 0
772 +
            solution["growth_rate"] = 0
773 +
            solution["growth_without_target"] = None
774 +
            solution["knockout"] = []
775 +
            solution["knockin"] = []
776 +
            solution["medium_addition"] = []
777 +
778 +
            for v in milp.solver.problem.getVars():
779 +
                if v.VarName.startswith("y_") and v.xn > 0.99:
780 +
                    reaction_id = v.VarName[2:]  # removing "y_"
781 +
                    if reaction_id == self.target:
782 +
                        continue
783 +
                    if reaction_id in self.knockout_reactions:
784 +
                        solution["knockout"].append(reaction_id)
785 +
                    elif reaction_id in self.knockin_reactions:
786 +
                        solution["knockin"].append(reaction_id)
787 +
                    elif reaction_id in self.medium_additions:
788 +
                        solution["medium_addition"].append(reaction_id)
789 +
                    else:
790 +
                        raise RuntimeError(reaction_id)
791 +
792 +
                # Extract target flux and growth rate. Subtract the forward and reverse fluxes to get the net flux.
793 +
                if v.VarName == target_id:
794 +
                    solution[target_flux_name] += v.xn
795 +
                if v.VarName.startswith(target_id_reverse):
796 +
                    solution[target_flux_name] -= v.xn
797 +
                if v.VarName == biomass_id:
798 +
                    solution["growth_rate"] += v.xn
799 +
                if v.VarName.startswith(biomass_id_reverse):
800 +
                    solution["growth_rate"] -= v.xn
801 +
802 +
803 +
            solution["growth_without_target"] = solution["growth_rate"] - solution["objective"]
804 +
            if round(solution["objective"], 7) > 0:
805 +
                solution["growth_coupling_slope"] = solution[target_flux_name] / solution["objective"]
806 +
807 +
            solution_pool.append(solution)
808 +
809 +
        return solution_pool
810 +
811 +
    @staticmethod
812 +
    def write_solutions_to_file(solutions, filename):
813 +
        import pandas as pd
814 +
        pd.DataFrame(solutions).to_csv(filename)

@@ -74,7 +74,6 @@
Loading
74 74
75 75
class DifferentialFVA(StrainDesignMethod):
76 76
    r"""Differential flux variability analysis.
77 -
78 77
    Compares flux ranges of a reference model to a set of models that
79 78
    have been parameterized to lie on a grid of evenly spaced points in the
80 79
    n-dimensional production envelope (n being the number of reaction bounds
@@ -89,10 +88,8 @@
Loading
89 88
        | . . . . . . \
90 89
        o--------------*- >
91 90
                     growth
92 -
93 91
    Overexpression, downregulation, knockout, flux-reversal and other
94 92
    strain engineering targets can be inferred from the resulting comparison.
95 -
96 93
    Parameters
97 94
    ----------
98 95
    design_space_model : cobra.Model
@@ -113,7 +110,6 @@
Loading
113 110
        will be normalized by.
114 111
    points : int, optional
115 112
        Number of points to lay on the surface of the n-dimensional production envelope (defaults to 10).
116 -
117 113
    Examples
118 114
    --------
119 115
    >>> from cameo import models
@@ -283,7 +279,6 @@
Loading
283 279
    def run(self, surface_only=True, improvements_only=True, progress=True,
284 280
            view=None, fraction_of_optimum=1.0):
285 281
        """Run the differential flux variability analysis.
286 -
287 282
        Parameters
288 283
        ----------
289 284
        surface_only : bool, optional
@@ -299,7 +294,6 @@
Loading
299 294
            A value between zero and one that determines the width of the
300 295
            flux ranges of the reference solution. The lower the value,
301 296
            the larger the ranges.
302 -
303 297
        Returns
304 298
        -------
305 299
        pandas.Panel
@@ -482,25 +476,18 @@
Loading
482 476
    def _generate_designs(cls, solutions, reference_fva):
483 477
        """
484 478
        Generates strain designs for Differential FVA.
485 -
486 479
        The conversion method has three scenarios:
487 480
        #### 1. Knockout
488 -
489 481
            Creates a ReactionKnockoutTarget.
490 -
491 482
        #### 2. Flux reversal
492 -
493 483
            If the new flux is negative then it should be at least the upper
494 484
            bound of the interval. Otherwise it should be at least the lower
495 485
            bound of the interval.
496 -
497 486
        #### 3. The flux increases or decreases
498 -
499 487
            This table illustrates the possible combinations.
500 488
                * Gap is the sign of the normalized gap between the intervals.
501 489
                * Ref is the sign of the closest bound (see _closest_bound).
502 490
                * Bound is the value to use
503 -
504 491
            +-------------------+
505 492
            | Gap | Ref | Bound |
506 493
            +-----+-----+-------+
@@ -509,15 +496,12 @@
Loading
509 496
            |  +  |  -  |   UB  |
510 497
            |  +  |  +  |   LB  |
511 498
            +-----+-----+-------+
512 -
513 -
514 499
        Parameters
515 500
        ----------
516 501
        solutions: pandas.Panel
517 502
            The DifferentialFVA panel with all the solutions. Each DataFrame is a design.
518 503
        reference_fva: pandas.DataFrame
519 504
            The FVA limits for the reference strain.
520 -
521 505
        Returns
522 506
        -------
523 507
        list
@@ -620,7 +604,6 @@
Loading
620 604
    def nth_panel(self, index):
621 605
        """
622 606
        Return the nth DataFrame defined by (biomass, production) pairs.
623 -
624 607
        When the solutions were still based on pandas.Panel this was simply
625 608
        self.solutions.iloc
626 609
        """
@@ -691,23 +674,18 @@
Loading
691 674
        """
692 675
        Generates a color scale based on the flux distribution.
693 676
        It makes an array containing the absolute values and minus absolute values.
694 -
695 677
        The colors set as follows (p standsfor palette colors array):
696 678
        min   -2*std  -std      0      std      2*std   max
697 679
        |-------|-------|-------|-------|-------|-------|
698 680
        p[0] p[0] ..  p[1] .. p[2] ..  p[3] .. p[-1] p[-1]
699 -
700 -
701 681
        Parameters
702 682
        ----------
703 683
        palette: Palette, list, str
704 684
            A Palette from palettable of equivalent, a list of colors (size 5) or a palette name
705 -
706 685
        Returns
707 686
        -------
708 687
        tuple:
709 688
            ((-2*std, color), (-std, color) (0 color) (std, color) (2*std, color))
710 -
711 689
        """
712 690
        if isinstance(palette, str):
713 691
            palette = mapper.map_palette(palette, 5)
@@ -854,20 +832,17 @@
Loading
854 832
class FSEOF(StrainDesignMethod):
855 833
    """
856 834
    Performs a Flux Scanning based on Enforced Objective Flux (FSEOF) analysis.
857 -
858 835
    Parameters
859 836
    ----------
860 837
    model : cobra.Model
861 838
    enforced_reaction : Reaction
862 839
        The flux that will be enforced. Reaction object or reaction id string.
863 840
    primary_objective : Reaction
864 841
        The primary objective flux (defaults to model.objective).
865 -
866 842
    References
867 843
    ----------
868 844
    .. [1] H. S. Choi, S. Y. Lee, T. Y. Kim, and H. M. Woo, 'In silico identification of gene amplification targets
869 845
    for improvement of lycopene production.,' Appl Environ Microbiol, vol. 76, no. 10, pp. 3097–3105, May 2010.
870 -
871 846
    """
872 847
873 848
    def __init__(self, model, primary_objective=None, *args, **kwargs):
@@ -895,7 +870,6 @@
Loading
895 870
            simulation_kwargs=None):
896 871
        """
897 872
        Performs a Flux Scanning based on Enforced Objective Flux (FSEOF) analysis.
898 -
899 873
        Parameters
900 874
        ----------
901 875
        target: str, Reaction, Metabolite
@@ -906,17 +880,14 @@
Loading
906 880
        number_of_results : int, optional
907 881
            The number of enforced flux levels (defaults to 10).
908 882
        exclude : Iterable of reactions or reaction ids that will not be included in the output.
909 -
910 883
        Returns
911 884
        -------
912 885
        FseofResult
913 886
            An object containing the identified reactions and the used parameters.
914 -
915 887
        References
916 888
        ----------
917 889
        .. [1] H. S. Choi, S. Y. Lee, T. Y. Kim, and H. M. Woo, 'In silico identification of gene amplification targets
918 890
        for improvement of lycopene production.,' Appl Environ Microbiol, vol. 76, no. 10, pp. 3097–3105, May 2010.
919 -
920 891
        """
921 892
        model = self.model
922 893
        target = get_reaction_for(model, target)
@@ -991,7 +962,6 @@
Loading
991 962
class FSEOFResult(StrainDesignMethodResult):
992 963
    """
993 964
    Object for storing a FSEOF result.
994 -
995 965
    Attributes:
996 966
    -----------
997 967
    reactions: list
@@ -1002,7 +972,6 @@
Loading
1002 972
        A pandas DataFrame containing the fluxes for every reaction for each enforced flux.
1003 973
    run_args: dict
1004 974
        The arguments that the analysis was run with. To repeat do 'FSEOF.run(**FSEOFResult.run_args)'.
1005 -
1006 975
    """
1007 976
1008 977
    __method_name__ = "FSEOF"

Learn more Showing 2 files with coverage changes found.

Changes in cameo/core/target.py
-2
-1
+3
Loading file...
Changes in cameo/models/webmodels.py
-3
+2
+1
Loading file...
Files Coverage
cameo -0.76% 61.70%
Project Totals (56 files) 61.70%
Loading