opencobra / cobrapy

COBRApy is a package for constraint-based modeling of metabolic networks.
http://opencobra.github.io/cobrapy/
GNU General Public License v2.0
461 stars 216 forks source link

"ValueError: invalid null reference" when saving modified model #1071

Closed WackerO closed 3 years ago

WackerO commented 3 years ago

Hello,

I am working on the curation of a model which contains unbalanced reactions. I used the following code to try and fix these, but get an error when saving the changed model:


  import cobra
  import cobra.test
  import copy
  import itertools
  import json
  import requests

  test_model = cobra.test.create_test_model("textbook")

  compartments = test_model.compartments.keys()
  compartments = {"_"+c.split("_")[-1] for c in compartments}
  changed_metabolites = {}
  run = 0
  for reac in test_model.reactions:
      mb = reac.check_mass_balance()
      if len(mb) > 0:
          run += 1
          if run > 3:
              break
          print("Found unbalanced reaction %s: %s" %(reac.id, mb))
          imbalance = len(mb)
          metab_dict = {}
          for m in reac.metabolites:
              met = m.id.rstrip()
              for end in compartments:
                  if met.endswith(end):  
                      met = met.split(end)[0]
              r = requests.get('http://bigg.ucsd.edu/api/v2/universal/metabolites/' + met)
              if r.status_code != 200:
                  print("For metabolite %s, got status code %s..." %(met.id, r.status_code))
              else:  
                  r.json()
                  r = json.loads(r.text)
                  metab_dict[m.id] = [r["charges"], r["formulae"]]
          combo_list = []
          key_list = list(metab_dict.keys())
          for m in key_list:
              combo_list.append(list(range(len(metab_dict[m][0]))))
              combo_list.append(list(range(len(metab_dict[m][1]))))
          combos = list(itertools.product(*combo_list))
          for c in combos:
              previous_model = copy.deepcopy(test_model)
              for i, el in enumerate(c):
                  if i % 2 == 0:
                      test_model.metabolites.get_by_id(key_list[int(i/2)]).charge = el
                  else:
                      test_model.metabolites.get_by_id(key_list[int((i-1)/2)]).formula = el
              new_mb = reac.check_mass_balance()
              if len(new_mb) == 0:
                  print("Reaction %s is now balanced: %s" %(reac.id, new_mb))
                  for k in key_list:
                      if k not in changed_metabolites.keys():
                          changed_metabolites[k] = (test_model.metabolites.get_by_id(k).charge,
                                                    test_model.metabolites.get_by_id(k).formula)
                      elif (k in changed_metabolites.keys() and
                            changed_metabolites[k][0] != test_model.metabolites.get_by_id(k).charge and
                            changed_metabolites[k][1] != test_model.metabolites.get_by_id(k).formula):
                          print("Conflict for metabolite %s!" %(k))
                  break
              elif len(new_mb) >= mb:
                  test_model = previous_model
              elif len(new_mb) < mb:
                  mb = new_mb
                  print("Reaction %s is better balanced than before: %s" %(reac.id, new_mb))
                  for k in key_list:
                      if k not in changed_metabolites.keys():
                          changed_metabolites[k] = (test_model.metabolites.get_by_id(k).charge,
                                                    test_model.metabolites.get_by_id(k).formula)
                      elif (k in changed_metabolites.keys() and
                            changed_metabolites[k][0] != test_model.metabolites.get_by_id(k).charge and
                            changed_metabolites[k][1] != test_model.metabolites.get_by_id(k).formula):
                          print("Conflict for metabolite %s!" %(k))
          else:
              print("Could not balance reaction %s." %(reac.id))

  cobra.io.write_sbml_model(test_model, "testmodel_balanced.xml")

ValueError: invalid null reference in method 'FbcSpeciesPlugin_setChemicalFormula', argument 2 of type 'std::string const &'

How can I fix this error? Thanks very much!

matthiaskoenig commented 3 years ago

You are trying to set a None as formula (but only strings are allowed). You have to make sure your formulas are strings. Or do a test

if el:
    test_model.metabolites.get_by_id(key_list[int((i-1)/2)]).formula = el
cdiener commented 3 years ago

None is the default for formulas in newly created metabolites in cobrapy though. So we should probably handle this case in the writer. Since it's optional in FBC maybe don't set it in this case?

matthiaskoenig commented 3 years ago

@WackerO Could you make sure you run the latest version of cobrapy and print out the el which is creating the issue. I just checked the codebase and the case should already be caught. I.e. there is a

        if metabolite.formula is not None:
            s_fbc.setChemicalFormula(metabolite.formula)
WackerO commented 3 years ago

Well, that was a stupid error. I did indeed accidentally assign incorrect formulas...Thanks very much for your help!