diff --git a/src/Model.jl b/src/Model.jl index 4d00edb..326b9f7 100644 --- a/src/Model.jl +++ b/src/Model.jl @@ -246,7 +246,7 @@ function create_model_from_config( catch e error("$(typeof(e)) while reading .yaml config file(s) $(abspath.(config_files)).\n"* "If the error isn't obvious by looking at the file(s) (often this is a whitespace issue), "* - "try an online YAML validator eg http://www.yamllint.com") + "install the VS Code YAML plugin, or try an online YAML validator eg http://www.yamllint.com") end conf_model = data[configmodel] @@ -778,12 +778,19 @@ function dispatch_methodlist( dl::ReactionMethodDispatchListNoGen, deltat::Float64=0.0 ) + lasti = -1 - for i in eachindex(dl.methods) - call_method(dl.methods[i], dl.vardatas[i], dl.cellranges[i], deltat) - end + try + for i in eachindex(dl.methods) + lasti = i + call_method(dl.methods[i], dl.vardatas[i], dl.cellranges[i], deltat) + end + catch + lasti != -1 && _dispatch_methodlist_methoderror(dl.methods[lasti][]) + rethrow() + end - return nothing + return nothing end function dispatch_methodlist( @@ -792,67 +799,112 @@ function dispatch_methodlist( deltat::Float64=0.0 ) - for j in eachindex(dl.methods) - methodref = dl.methods[j] - if has_modified_parameters(pa, methodref) - call_method(methodref, get_parameters(pa, methodref), dl.vardatas[j], dl.cellranges[j], deltat) - else - call_method(methodref, dl.vardatas[j], dl.cellranges[j], deltat) + lasti = -1 + + try + for i in eachindex(dl.methods) + lasti = i + methodref = dl.methods[i] + if has_modified_parameters(pa, methodref) + call_method(methodref, get_parameters(pa, methodref), dl.vardatas[i], dl.cellranges[i], deltat) + else + call_method(methodref, dl.vardatas[i], dl.cellranges[i], deltat) + end end - end + catch + lasti != -1 && _dispatch_methodlist_methoderror(dl.methods[lasti][]) + rethrow() + end - return nothing + return nothing end @generated function dispatch_methodlist( dl::ReactionMethodDispatchList{M, V, C}, - deltat::Float64=0.0 + deltat::Float64=0.0, ) where {M, V, C} + # Write out unrolled loop as an expression # See https://discourse.julialang.org/t/manually-unroll-operations-with-objects-of-tuple/11604 - - ex = quote ; end # empty expression - for j=1:fieldcount(M) - push!(ex.args, + unrollex = quote ; end # empty expression + for i=1:fieldcount(M) + push!(unrollex.args, quote + lasti = $i # let - # call_method(dl.methods[$j][], dl.vardatas[$j][], dl.cellranges[$j], deltat) + # call_method(dl.methods[$i][], dl.vardatas[$i][], dl.cellranges[$i], deltat) # pass Ref to function to reduce compile time - call_method(dl.methods[$j], dl.vardatas[$j], dl.cellranges[$j], deltat) + call_method(dl.methods[$i], dl.vardatas[$i], dl.cellranges[$i], deltat) # end end - ) + ) + end + + # interpolate the unrolled loop into a try-catch + ex = quote + lasti = -1 + + try + $unrollex + catch + lasti != -1 && _dispatch_methodlist_methoderror(dl.methods[lasti][]) + rethrow() + end + + return nothing end - push!(ex.args, quote; return nothing; end) return ex end + @generated function dispatch_methodlist( dl::ReactionMethodDispatchList{M, V, C}, pa::ParameterAggregator, deltat::Float64=0.0 ) where {M, V, C} - # See https://discourse.julialang.org/t/manually-unroll-operations-with-objects-of-tuple/11604 - - ex = quote ; end # empty expression - for j=1:fieldcount(M) - push!(ex.args, + # Write out unrolled loop as an expression + # See https://discourse.julialang.org/t/manually-unroll-operations-with-objects-of-tuple/11604 + unrollex = quote ; end # empty expression + for i=1:fieldcount(M) + push!(unrollex.args, quote - if has_modified_parameters(pa, dl.methods[$j]) - call_method(dl.methods[$j], get_parameters(pa, dl.methods[$j]), dl.vardatas[$j], dl.cellranges[$j], deltat) + lasti = $i + if has_modified_parameters(pa, dl.methods[$i]) + call_method(dl.methods[$i], get_parameters(pa, dl.methods[$i]), dl.vardatas[$i], dl.cellranges[$i], deltat) else - call_method(dl.methods[$j], dl.vardatas[$j], dl.cellranges[$j], deltat) + call_method(dl.methods[$i], dl.vardatas[$i], dl.cellranges[$i], deltat) end end ) end - push!(ex.args, quote; return nothing; end) + # interpolate the unrolled loop into a try-catch + ex = quote + lasti = -1 + + try + $unrollex + catch + lasti != -1 && _dispatch_methodlist_methoderror(dl.methods[lasti][]) + rethrow() + end + + return nothing + end + return ex end +function _dispatch_methodlist_methoderror(reactionmethod) + io = IOBuffer() + println(io, "dispatch_methodlist: a ReactionMethod failed:") + show(io, MIME"text/plain"(), reactionmethod) + @warn String(take!(io)) + return +end + ################################# # Pretty printing ################################ diff --git a/src/Reaction.jl b/src/Reaction.jl index 82d47c1..be947cb 100644 --- a/src/Reaction.jl +++ b/src/Reaction.jl @@ -324,11 +324,13 @@ end add_method_do!(@nospecialize(reaction::AbstractReaction), @nospecialize(methodfn::Function), @nospecialize(vars::Tuple{Vararg{AbstractVarList}}); kwargs...) = _add_method!(reaction, methodfn, vars, add_method_do!; kwargs...) +default_preparefn(m, vardata) = vardata + function _add_method!( @nospecialize(reaction::AbstractReaction), @nospecialize(methodfn::Function), @nospecialize(vars::Tuple{Vararg{AbstractVarList}}), add_method_fn; name=string(methodfn), p=nothing, - preparefn=(m, vardata) -> vardata, + preparefn=default_preparefn, operatorID=reaction.operatorID, domain=reaction.domain ) @@ -611,15 +613,19 @@ function Base.show(io::IO, react::AbstractReaction) end function Base.show(io::IO, ::MIME"text/plain", react::AbstractReaction) - println(io, typename(react)) - println(io, " name='", react.name, "'") - println(io, " classname='", react.classname, "'") - println(io, " domain='", domainname(react), "'") - println(io, " operatorID=", react.operatorID) - println(io, " parameters=", get_parameters(react)) - println(io, " methods_setup=", react.methods_setup) - println(io, " methods_initialize=", react.methods_initialize) - println(io, " methods_do=", react.methods_do) + dump_reaction(io, react) +end + +function dump_reaction(io::IO, react::AbstractReaction; prefix="", show_parameters::Bool=true) + println(io, prefix, typename(react)) + println(io, prefix, " name='", react.name, "'") + println(io, prefix, " classname='", react.classname, "'") + println(io, prefix, " domain='", domainname(react), "'") + println(io, prefix, " operatorID=", react.operatorID) + show_parameters && println(io, prefix, " parameters=", get_parameters(react)) + println(io, prefix, " methods_setup=", react.methods_setup) + println(io, prefix, " methods_initialize=", react.methods_initialize) + println(io, prefix, " methods_do=", react.methods_do) end """ diff --git a/src/ReactionMethod.jl b/src/ReactionMethod.jl index 94b9227..ac9647f 100644 --- a/src/ReactionMethod.jl +++ b/src/ReactionMethod.jl @@ -143,7 +143,7 @@ call_method_codefn(io::IO, codefn, method::ReactionMethod{M, R, P, 5}, vardata, """ get_variables_tuple(method::AbstractReactionMethod) -> (Vector{VariableReaction}, ...) - + println(io, typename(react)) Get all [`VariableReaction`](@ref)s from `method` as a Tuple of `Vector{VariableReaction}` """ get_variables_tuple(@nospecialize(method::ReactionMethod); flatten=true) = Tuple(get_variables(vl; flatten) for vl in method.varlists) @@ -209,7 +209,7 @@ get_rate_stoichiometry(@nospecialize(m::ReactionMethod)) = [] # Pretty printing ############################################ -"compact form" +# compact form function Base.show(io::IO, @nospecialize(method::ReactionMethod)) print( io, @@ -220,3 +220,16 @@ function Base.show(io::IO, @nospecialize(method::ReactionMethod)) ")", ) end + +# multiline form +function Base.show(io::IO, ::MIME"text/plain", @nospecialize(method::ReactionMethod)) + println(io, "ReactionMethod") + println(io, " fullname='", fullname(method), "'") + println(io, " methodfn=", string(method.methodfn)) + println(io, " preparefn=", string(method.preparefn)) + println(io, " domain='", method.domain.name , "'") + println(io, " operatorID=", method.operatorID, "'") + + print(io, " reaction=") + dump_reaction(io, method.reaction; prefix=" ", show_parameters=false) +end \ No newline at end of file