Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle test errors from MTKv9 update (including ReactionSystem completeness) #784

Merged
merged 51 commits into from
Apr 3, 2024

Conversation

TorkelE
Copy link
Member

@TorkelE TorkelE commented Feb 13, 2024

For MTK v9 all inputs to various systems have to be complete. Which means we must either add complete(::ReactionSystem) wherever these are required, or make them complete by default. Since this can be sorted out on the v14 branch even before MTK v9 I figured we could do it in a separate branch.

Currently, I make ReactionSystems complete by default. which can be changed by a DSL option/optional argument:

@reaction_network begin
    @incompelte
    (p,d), 0 <--> X
end
ReactionSystem(rxs, t; complete = false)

However, we can flip the default really easily (while also renaming @incompelte to @compelte

Deciding which to go for is still a problem. I prefer this, since it only introduces the concept of completeness when it is actually required. I think it is useful to follow how MTK does stuff, but for something which has a major impact on Catalyst (and is not just notation), I think we should do what works best, independently of MTK (whatever the case, I hope to add a "differences to MTK" section somewhere in the docs).

@TorkelE TorkelE changed the base branch from master to Catalyst_version_14 February 13, 2024 02:45
@isaacsas isaacsas mentioned this pull request Feb 28, 2024
47 tasks
@TorkelE TorkelE force-pushed the reactionsystem_completeness branch 2 times, most recently from 2614a6c to a8ed387 Compare March 19, 2024 00:16
@TorkelE TorkelE changed the title Handle ReactionSystem completeness for MTK v9 update Handle MTKv9 errors (including ReactionSystem completeness) Mar 20, 2024
@TorkelE TorkelE changed the title Handle MTKv9 errors (including ReactionSystem completeness) Handle test errors from MTKv9 update (including ReactionSystem completeness) Mar 20, 2024
@TorkelE TorkelE force-pushed the reactionsystem_completeness branch from dba4535 to ed4ca76 Compare March 22, 2024 21:25
docs/pages.jl Show resolved Hide resolved
scaling parameter*. First, we simulate a simple two-state CRN model using the
scale the magnitude of the noise terms. Here, each reaction of the system generates a separate noise term in the CLE. If you require identical scaling for all reactions, the `@default_noise_scaling` option can be used. Else, you can supply a `noise_scaling` metadata for each individual reaction, describing how to scale the noise for that reaction.

We begin with considering the first approach. First, we simulate a simple two-state CRN model using the
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additions in this file is because this PR builds upon the noise scaling one, so showing its changes as changes here. Will disappear once that gets merged.

## Compositional modeling tooling
Catalyst supports two ModelingToolkit interfaces for composing multiple
[`ReactionSystem`](@ref)s together into a full model. The first mechanism for
extending a system is the `extend` command
```@example ex1
using Catalyst
basern = @reaction_network rn1 begin
@incomplete
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, the @incompelte option marks that a reaction system (created via the DSL) is not complete when created. Can change how to manage this later.

@@ -123,7 +123,7 @@ const forbidden_variables_error = let
end

# Declares the keys used for various options.
const option_keys = (:species, :parameters, :variables, :ivs, :compounds, :observables)
const option_keys = (:species, :parameters, :variables, :ivs, :compounds, :observables, :default_noise_scaling, :incomplete)
Copy link
Member Author

@TorkelE TorkelE Mar 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stuff that follows (in this file) are either the noise scaling (because this builds on that PR), or the compelteness.

@test all(abs.(f1.jac(u0, p, t) .≈ f2.jac(u0, p, t)))
@test all(abs.(g1(u0, p, t) .≈ g2(u0, p, t)))

@test f_eval(networks[1], u0_1, p_1, t) ≈ f_eval(networks[2], u0_2, p_2, t)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uses the new f_eval function to evaluate the ODESystem f function.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alsmot always, like here, f_eval is only called once for each network, do no use using a in-place version. Because most networks have different du vector sizes, reusing it across different systems is hard.

rn2 = complete(rn2)
@test ModelingToolkit.iscomplete(rn2)
end
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test for the new @incomplete functionality.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(need changing after final decision on completeness)

### Run Tests ###

# Tests for network without conservation laws.
# Tests for Symbol parameter input.
# Tests for Symbolics initial condition input.
# Tests for different types (Symbol/Symbolics) for parameters and initial conditions.
# Tests that attempts to find steady states of system with conservation laws, while u0 is not provided, gives an error.
let
@test_broken let # Requires https://github.com/SciML/ModelingToolkit.jl/issues/2566 to be fixed
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the tests that are currently broken. Basically, we cannot do homotopy continuation on systems with conservation laws until that issue gets sorted out.

@@ -50,7 +53,7 @@ end
# Tests correctness in presence of default values.
# Tests where some default values are overwritten with other values.
# Tests where input ps/u0 are tuples with mixed types.
let
@test_broken let # Requires https://github.com/SciML/ModelingToolkit.jl/issues/2566 to be fixed
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same problem as the one above.

@test isapprox(sol2[1], p[1] / p[2]; atol=1e-10)
@test isapprox(sol2[2]^3 / factorial(3), p[3] / p[4]; atol=1e-10)
@test isapprox(sol2[3], (p[5] * p[2]) / (p[6] * p[1]); atol=1e-10)
@test sol1[:X1] ≈ nlprob.ps[:k1] / nlprob.ps[:k2] atol=1e-10
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uses symbolic (instead of integer) indexing.

Loads of test where also written before I was familiar with nice ways to use , @test, and atol, so I rewrote quite a few tests using this while I was at it.

end

# Checks for system with conservation laws.
# Checks using interfacing with output solution.
let
# Conservation laws currently broken (you get stuck in an infinite loop in MTK or something).
return (@test_broken false)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another conservation law issue, this one only appears when a XProblem is created (because these creates a MTKParameters object, which is the real culprit, not sure what the problem in these are though).

# Gives an error. I can fix so there is not, but unsure what part of the code is what we actually are
# testing for, and what we are not. Sam, if you have any opinions on what to preserve in this test or not,
# tell me before I try to rewrite.
@test_broken let
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this is also broken,

-2*p[3]*u[2]*u[1] -1-p[3] * u[1] * u[1] 1;
2*p[3]*u[2]*u[1] p[3]*u[1]*u[1] -1.0]
@test all(abs.(test_jac .- real_jac) .< 1e-9)
u = Dict(rnd_u0(jacobian_network_2, rng; factor))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uses Dict to simplify evaluating real_jac in 3 lines from here.

p_1 = rnd_ps(networks[1], rng; factor)
(i == 3) && (p_1 =rnd_ps_Int64(networks[1], rng))
u0_2 = last.(u0_1)
p_2 = last.(p_1)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This depends on ReactionSystem not doing some weird reordering (which we do not want to promise in the future). However, here we loop through quite a few networks and just generate parameters. If we'd want to make order not matter here, we'd have to write out the vectors for each case manually, and handle them separately. I can see how to do this, but non-trivial amount of work. I'd rather do that at some later overhaul of the tests than right now (when we have tons of stuff to fix).

# Currently fails because binomial only takes Int input (and X is Float64).
# I see several solutions, but depends on whether we allow species to be specified as Int64.
# I have marked this one as broken for now.
@test_broken let
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test will remain broken until we decide how to handle non-Float64 definitions of species. Which will be messy, because if we do we have to rewrite the @compound stuff to permit that as well.

Once sorted out, we can fix these tests using the best solution (which depends on whether that is allowed or not).

sf = SDEFunction{false}(sdesys_noise_scaling, unknowns(rs),
parameters(sdesys_noise_scaling))
G2 = sf.g(u, p, t)
@test norm(G - G2) < 100 * eps()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These were moved in the noise scaling PR to the SDe simulation file (so not removed).

end
@test latexify(rn; mathrm = true) != latexify(rn; mathrm = false)
end

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now line 207

@@ -110,7 +117,8 @@ let
@test rn == rn2
end

@testset "make_reaction_system can be called from another module" begin
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chanegd the @testset block to let .. end block like for all of our other tests. Not sure if there is a reason for this here, since it is all already in a testset?

This was referenced Mar 30, 2024
Copy link
Member

@isaacsas isaacsas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There may be some older comments I missed deleting, so ask if any seem out of date or already settled. Sorry about that!

docs/src/catalyst_functionality/compositional_modeling.md Outdated Show resolved Hide resolved
docs/src/catalyst_functionality/compositional_modeling.md Outdated Show resolved Hide resolved
src/networkapi.jl Show resolved Hide resolved
src/reaction_network.jl Outdated Show resolved Hide resolved
src/reactionsystem.jl Show resolved Hide resolved
Comment on lines +54 to +72
# Tests that Jump Systems are correct (by comparing to network with manually written higher order rates).
# Currently fails for reason I do not understand. Likely reason similar to the weird case in the jump tests.
# Spent loads of time trying to figure out, the best I can get to is that it seems like the rng/seed is
# not fully reproducible.
let
@test_broken false
# Declares a JumpSystem manually. Would have used Catalyst again, but `binomial` still errors when
# called on symbolics. For reference, here is the network as it would be created using Catalyst.

# higher_order_network_alt2 = @reaction_network begin
# p, ∅ ⟼ X1
# r1 * binomial(X1, 2), 2X1 ⟾ 3X2
# mm(X1, r2, K) * binomial(X2, 3), 3X2 ⟾ X3 + 2X4
# r3 * binomial(X3, 1) * binomial(X4, 2), X3 + 2X4 ⟾ 3X5 + 3X6
# r4 * X2 * binomial(X5, 3) * binomial(X6, 3), 3X5 + 3X6 ⟾ 3X5 + 2X7 + 4X8
# r5 * binomial(X5, 3) * binomial(X7, 2) * binomial(X8, 4), 3X5 + 2X7 + 4X8 ⟾ 10X9
# r6 * binomial(X9, 10), 10X9 ⟾ X10
# d * binomial(X10, 2), 2X10 ⟾ ∅
# end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This passed before. We need to keep it working now. It is a valuable test that is pretty comprehensive...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please open issues on MTK/Symbolics if something like binomial is now broken that used to work.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did, I even wrote a PR to DynamicQuantities to get it solved as well, which got something, but not all the way. I will continue pushing for this though. Not sure when it will be fixed though. The @test_broken false can be removed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this issue is DynamicQuantites I would prefer we drop units over dropping this test and the use of binomials. We can then add units back if/when they update it.

Comment on lines +74 to +93
rate1(u, p, t) = p[1]
rate2(u, p, t) = p[2] * binomial(u[1], 2)
rate3(u, p, t) = mm(u[1], p[3], p[4]) * binomial(u[2], 3)
rate4(u, p, t) = p[5] * binomial(u[3], 1) * binomial(u[4], 2)
rate5(u, p, t) = p[6] * u[2] * binomial(u[5], 3) * binomial(u[6], 3)
rate6(u, p, t) = p[7] * binomial(u[5], 3) * binomial(u[7], 2) * binomial(u[8], 4)
rate7(u, p, t) = p[8] * binomial(u[9], 10)
rate8(u, p, t) = p[9] * binomial(u[10], 2)

affect1!(int) = (int.u[1] += 1)
affect2!(int) = (int.u[1] -= 2; int.u[2] += 3;)
affect3!(int) = (int.u[2] -= 3; int.u[3] += 1; int.u[4] += 2;)
affect4!(int) = (int.u[3] -= 1; int.u[4] -= 2; int.u[5] += 3; int.u[6] += 3;)
affect5!(int) = (int.u[5] -= 3; int.u[6] -= 3; int.u[5] += 3; int.u[7] += 2; int.u[8] += 4;)
affect6!(int) = (int.u[5] -= 3; int.u[7] -= 2; int.u[8] -= 4; int.u[9] += 10;)
affect7!(int) = (int.u[9] -= 10; int.u[10] += 1;)
affect8!(int) = (int.u[10] -= 2;)

higher_order_network_alt2 = ConstantRateJump.([rate1, rate2, rate3, rate4, rate5, rate6, rate7, rate8],
[affect1!, affect2!, affect3!, affect4!, affect5!, affect6!, affect7!, affect8!])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a nice test too, so we should get the old Catalyst version fixed and keep your new JumpProcesses version too and compare against both going forward.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed

Comment on lines +88 to 89
@test_throws Exception Catalyst.get_noise_scaling(r1)
@test isequal(Catalyst.get_noise_scaling(r2), η)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a has_noise_scaling function to test too (or is it tested somewhere else)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, yes, I will add tests for this one too.

parameters(sdesys_noise_scaling))
G2 = sf.g(u, p, t)
@test norm(G - G2) < 100 * eps()
@test_broken let # The next line throws an error.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just trying to test the ODE rhs function gives the same values as the NonlinearProblem. We can switch to just use the function within the NonlinearProblem (I think maybe it wasn't implemented/working when we originally wrote these tests).

TorkelE and others added 15 commits April 2, 2024 15:38
Co-authored-by: Sam Isaacson <isaacsas@users.noreply.github.com>
Co-authored-by: Sam Isaacson <isaacsas@users.noreply.github.com>
Co-authored-by: Sam Isaacson <isaacsas@users.noreply.github.com>
Co-authored-by: Sam Isaacson <isaacsas@users.noreply.github.com>
Co-authored-by: Sam Isaacson <isaacsas@users.noreply.github.com>
Co-authored-by: Sam Isaacson <isaacsas@users.noreply.github.com>
Co-authored-by: Sam Isaacson <isaacsas@users.noreply.github.com>
@TorkelE TorkelE merged commit 6589937 into Catalyst_version_14 Apr 3, 2024
3 checks passed
@TorkelE TorkelE deleted the reactionsystem_completeness branch June 8, 2024 18:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants