Repository navigation
Conversation
MSGapfill.run_gapfilling returns "new" (template reactions to add) and "reversed" (reactions already in the model that the solution needs in a direction their bounds block). build() turned only "new" into gap_sol, and MSBuilder.integrate_gapfill_solution only adds reactions, so every reversal was dropped and the returned model could fail to grow on the medium it was gapfilled on. Add MSBuilder.apply_gapfill_reversals, which opens each reversed reaction in the gapfilled direction to the bound get_reaction_constraints_from_direction gives (the bound new reactions get), keeping the other bound and any wider bound, and call it in build() after integrate_gapfill_solution. The return value of build() is unchanged. Andrew Freiburger found and fixed this in his fork (freiburgermsu#19); this carries his approach onto dev. Tests: the helper on a small model, and build() on e_coli_core with GAPD_c0 blocked forward (gapfilling runs for real; ATP correction runs with no ATP media; only build_base_model and the ModelSEED ATP media are replaced). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Credit. Andrew Freiburger found and fixed this bug in his fork:
freiburgermsu/ModelSEEDpy#19, in
build_and_gapfill, hisfork's name for dev's
build(). This PR carries his fix onto dev. It uses his helper,apply_gapfill_reversals,with the same semantics. His PR also gives the effect on a 200-genome benchmark: 107 of 2,362 gap-filled models needed
a reversal, and in an earlier run that dropped reversals, 136 models could not grow.
Why this matters in our workflow
We build models with
MSBuilder.build(). When its gap-fill needs a reaction already in the model to run in adirection the model blocks,
build()returns a model without that change, and the model may not grow on the mediumit was gap-filled on. Our glucose builds have not needed a reversal so far, but in Andrew's benchmark (gap-filling on
complete medium) 107 of 2,362 gap-filled models, about 5%, needed a reversal.
What happens
msbuilder.pyL1041-L1053 at 062714b:run_gapfillingreturns"new"(template reactions to add) and"reversed"(model reactions whose needed directionthe model blocks). For a model reaction whose template reaction has
GapfillDirection=, the gap-fill packagewidens the model's bounds to the template reaction's bounds
(
gapfillingpkg.pyL434-L449).So a reversal happens when the model's bounds are narrower than the template's: for example, a reaction narrowed in the
model after it was built, or a model built from another template.
build()reads only"new", andintegrate_gapfill_solution(L962-L976)only adds reactions, so every reversal is dropped. The package's other integration paths do apply reversals:
MSGapfill.integrate_gapfill_solutionandMSBuilder.gapfill_model, both to ±100.How to reproduce
The reproduction uses the package's
e_coli_coretest model.ATPM_c0's lower bound is set to 0 (asMSBuilder.add_atpmmakes it), andGAPD_c0is made irreversible the wrong way, (-1000, 0). Intemplate_core_bigg.json,GAPD_cis reversible, withGapfillDirection=. Onlybuild_base_model, which needsan annotated genome, and
load_default_medias, whose media use ModelSEED compound ids, are replaced. Gap-fill runsfor real; ATP correction runs with no ATP media.
gap_solGAPD_c0in returned modelreversed {'GAPD_c0': '>'}{}reversed {'GAPD_c0': '>'}{}The fix
MSBuilder.apply_gapfill_reversals(model, reversed_reactions)(Andrew's helper). For each reversedreaction, it opens the gap-filled direction to the bound
get_reaction_constraints_from_directiongives, which is±1000, the bound
build()already gives new reactions. The other bound is kept, and so is a bound that is alreadywider. A reaction that is not in the model is skipped with a warning. The helper returns the ids it opened.
build()calls it right afterintegrate_gapfill_solution. The return value ofbuild()is unchanged.build(). It iterates the dict as given instead ofsorted(...). It does not acceptNone: on dev,gapfill_res["reversed"]is always a dict, because whenrun_gapfillingreturnsNone,build()already fails ongapfill_res["new"]. It has no debug log line.run_test_conditionsalready evaluates the solution with the reversed direction open, up to thetemplate's bound. So opening it in the final model does not admit anything the tests did not see.
Two package functions call
build():build_from_annotaton_ontology(L791) andbuild_metabolic_model(L1235). Bothuse the pre-refactor signature and fail before reaching this code (separate PR). External callers get the same return
value, and the returned model now includes the reversals.
Tests
tests/core/test_msbuilder.py::test_apply_gapfill_reversalscovers the helper on a small model: a reverse opening,a forward opening with the other bound kept, a wider bound kept, and an absent reaction skipped.
tests/core/test_msgapfill.py::test_build_applies_gapfill_reversalsis the reproduction above, using that file'sfixtures.
Against dev's code, both fail:
With the fix, both pass. Full suite (Python 3.10, cobra 0.32.1, CPLEX 22.1.1):
tests/coregoes from 56 to 58passed, and
tests/from 58 to 60.black22.8.0 and the other pre-commit hooks pass.Real-model check
We ran
MSBuilder.build()on two genome-scale builds (E. coli K-12 and a Pantoea strain, from RAST annotations,GramNeg template v7.1 with Core-V6.1, minimal glucose), once on dev and once on this branch. Neither gap-fill returned
a reversal, and the two results are identical: final models, every gap-fill result, ATP correction outputs and growth.
Related
🤖 Generated with Claude Code