Braden-Griebel / imatpy

Python implementation of iMAT algorithm for integration of gene expression data with metabolic modeling.
https://imatpy.readthedocs.io/en/latest/index.html
1 stars 0 forks source link

IMATPy Error: unsupported operand type(s) for *: 'float' and 'NoneType' #3

Open Rohak72 opened 1 month ago

Rohak72 commented 1 month ago

Hey @Braden-Griebel!

First off, thanks for creating such a great tool -- it's been a really useful asset to my metabolic modeling work. Recently, I was trying to execute the IMAT functionalities to integrate dengue gene expression data with a high-level human GEM. I've successfully assigned each gene a quantitative classification (-1, 0, 1) and aggregated a series of reaction weights. However, when I try to run the core imat() function, I get a TypeError complaining about *'unsupported operand type(s) for : 'float' and 'NoneType'**.

Here's a full copy of the traceback:

Input In [16], in <cell line: 2>()
      1 from imatpy.imat import imat
----> 2 imat_results = imat(model=GEM, rxn_weights=rxn_weights, epsilon=1, threshold=0.01)

File ~/opt/anaconda3/lib/python3.9/site-packages/imatpy/imat.py:54, in imat(model, rxn_weights, epsilon, threshold)
     36 """
     37 Function for performing iMAT analysis. Returns a cobra Solution object,
     38 with objective value and fluxes.
   (...)
     51 :rtype: cobra.Solution
     52 """
     53 imat_model = add_imat_constraints(model, rxn_weights, epsilon, threshold)
---> 54 add_imat_objective_(imat_model, rxn_weights)
     55 return imat_model.optimize()

File ~/opt/anaconda3/lib/python3.9/site-packages/imatpy/imat.py:247, in add_imat_objective_(model, rxn_weights)
    243 imat_obj = model.solver.interface.Objective(
    244     sym.Add(*rh_obj) + sym.Add(*rl_obj), direction="max"
    245 )
    246 print(imat_obj)
--> 247 model.objective = imat_obj

File ~/opt/anaconda3/lib/python3.9/site-packages/cobra/core/model.py:1317, in Model.objective(self, value)
   1315     value = {rxn: 1 for rxn in reactions}
   1316     # TODO - check that it is reset with context.
-> 1317 set_objective(self, value, additive=False)

File ~/opt/anaconda3/lib/python3.9/site-packages/cobra/util/solver.py:196, in set_objective(model, value, additive)
    193     value = interface.Objective.clone(value, model=model.solver)
    195 if not additive:
--> 196     model.solver.objective = value
    197 else:
    198     model.solver.objective += value.expression

File ~/opt/anaconda3/lib/python3.9/site-packages/optlang/gurobi_interface.py:651, in Model.objective(self, value)
    649     coef = float(coef)
    650     var = self.problem.getVarByName(var.name)
--> 651     grb_terms.append(coef * var)
    652 for key, coef in quadratic_coefficients.items():
    653     coef = float(coef)

TypeError: unsupported operand type(s) for *: 'float' and 'NoneType'

It seems that there is an issue with the computation of the model's objective function, but I can't seem to figure what might exactly be going on. If you have any feedback or clarification regarding this, that would be great! I am happy to provide my GEM, gene call vector, and reaction weights if you'd like.

Thanks in advance, looking forward to hearing from you!

-Rohak

Braden-Griebel commented 1 month ago

Hello @Rohak72 ,

Thank you so much for testing out iMATpy!

Based on the NoneType, I'm wondering if one of the reaction weights ended up being None when it is trying to be added to the model. Are any of the reaction weights None (or some equivalent to None)?

Right now there are a couple of places that none could crop up as part of the pipeline, for example if the gene expression data is missing one of the genes found in the model that currently causes issues. You can check which genes are in the base model with model.genes.listattr("id") to get a list of all the genes, and compare that to the index of the gene expression data to see if one of the genes is missing (or has a different name).

If there aren't any Nones in the gene expression/reaction weights than I am not 100% sure what would be causing that error, but if you could share the data/model generating the error I could take a better look.

Best,

Braden

Rohak72 commented 1 month ago

Hi @Braden-Griebel,

Thanks for the feedback, I really appreciate it! Unfortunately, it does look like my reaction weights and expression data genes mirror their equivalents in the metabolic model. I also tried executing the iMAT scripts with the test data you provided (test_model.xml and test_model_reaction_weights.csv) and run into the same error. This makes me wonder if there is some sort of dependency or requirement that I'm not fulfilling on my end (e.g. package version). I should also mention that I'm using the Gurobi solver, if that makes a difference.

For reference, I've attached the reaction weights I'm using for iMAT. Please note that the list of weights is represented as a CSV, but you can convert it to a Pandas series when running the script. As for the model, it might be too big to send here, but you can download it at the following link: (https://github.com/biosustain/THG/blob/main/compare_models/models/THG-2023-02-25.xml).

Thanks again for your help, please let me know if you need anything else!

Best, Rohak

Braden-Griebel commented 1 month ago

Hello @Rohak72 ,

I haven't been able to recreate the issue, I tried running it with the test files since you mentioned getting the same error there, but it works when I run it (see code below). Since it's not working with the test, I suspect there might be something different with the environment. It looks like you are using anaconda based on the error message, would you mind sharing the environment file? (you can export the environment file with conda env export -n <MY_ENVIRONMENT> -f <MY_ENVIRONMENT>.yml).

Thanks!

Braden

# Imports
# Standard Library Imports
import pathlib

# External Imports
from imatpy.model_utils import read_model
from imatpy.imat import imat
import pandas as pd

# Set the paths to the model and the test reaction weights
MODEL_PATH = pathlib.Path(<INSERT PATH TO MODEL>)
WEIGHTS_PATH = pathlib.Path(<INSERT PATH TO REACTION WEIGHTS>) 

# Read in the model and the reaction weights
test_model = read_model(str(MODEL_PATH))
test_model.solver = "gurobi"
test_rxn_weights = pd.read_csv(WEIGHTS_PATH, header=None, index_col=0).squeeze("columns")

# Run the IMAT algorithm
res = imat(model = model, rxn_weights=rxn_weights, epsilon=1., threshold=0.01)

# Print the results
print(f"Optimal Value: {res.objective_value}")
print(f"Fluxes:\n {res.fluxes}")

Results

Optimal Value: 2.999999999999999 Fluxes: R_A_e_ex -1.0 R_B_e_ex -1.0 R_C_e_ex -1.0 R_F_e_ex 1.0 R_G_e_ex 1.0 R_H_e_ex 0.0 R_A_imp 1.0 R_B_imp 1.0 R_C_imp 1.0 R_F_exp 1.0 R_G_exp 1.0 R_H_exp 0.0 r_A_B_D_E 1.0 r_C_E_F 1.0 r_C_H 0.0 r_D_G 1.0 Name: fluxes, dtype: float64

Rohak72 commented 1 month ago

UPDATE: I'm able to successfully run iMAT's test inputs now (yay), but it seems that my actual inputs stall out with a warning saying "UserWarning: Solver status is 'infeasible'". So, perhaps it's an issue of a large model size? I'm not too sure.

Braden-Griebel commented 1 month ago

A solver status of infeasible (theoretically) means that there is some conflict in the constraints. Feasibility with linear, or mixed integer programming refers to solutions that meet all the constraints (but are not necessarily optimal). I've run into infeasibility when working with the models after updating them with the IMAT constraints (with the functions in the model_creation module), but I haven't encountered it with just the initial IMAT application before.

It shouldn't be due to the models size, but figuring out exactly what is causing the infeasibility can be tricky. With Gurobi, there are ways to take the model and identify conflicting constraints in the form of a irreducible inconsistent subset (IIS), or minimally relax conflicting constraints.

I'll try to look more into this (and I am still investigating the causes of the issues of infeasibility encountered in some of the other methods).

Rohak72 commented 1 month ago

Hi Braden,

That makes much more sense! Have you tried running iMAT with the files I provided? It would be interesting to see whether you also run into the same issue.

On another note, I did try using some of the other methods (instead of fva) and they all yielded the same model as my original input GEM; this trend also held for the test inputs. I was wondering if this is something you encountered too.

I understand that this project is still under development, so no worries at all if things aren't fully-fleshed out yet! Thanks for your help regardless.

Best, Rohak

Rohak72 commented 2 weeks ago

Hi Braden,

I hope you're doing well! Was wondering if you had been able to run iMAT with the files I'd provided earlier; if not, that's totally ok -- just wanted to check if the program was more successful on your end. Also, it'd be great to get your input regarding the issue of the model remaining unchanged post-iMAT. Thanks!

Best, Rohak

Rohak72 commented 1 week ago

Hi @Braden-Griebel,

Any updates? Thanks!

Best, Rohak