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

Update code for Julia 1.10 #146

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "PEtab"
uuid = "48d54b35-e43e-4a66-a5a1-dde6b987cf69"
authors = ["Viktor Hasselgren", "Sebastian Persson", "Rafael Arutjunjan", "Damiano Ognissanti"]
version = "2.5.3"
version = "2.6.0"

[deps]
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
Expand Down Expand Up @@ -84,7 +84,7 @@ QuasiMonteCarlo = "0.2, 0.3"
Random = "1"
ReverseDiff = "1"
RuntimeGeneratedFunctions = "0.4, 0.5"
SBMLImporter = "0.1"
SBMLImporter = "0.2"
SciMLBase = "2"
SciMLSensitivity = "6 - 7"
StatsBase = "0.33, 0.34"
Expand Down
45 changes: 24 additions & 21 deletions src/PEtabModel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -94,23 +94,16 @@ function PEtabModel(path_yaml::String;
compute_∂σ∂σu! = @RuntimeGeneratedFunction(Meta.parse(∂σ∂u_str))
compute_∂σ∂σp! = @RuntimeGeneratedFunction(Meta.parse(∂σ∂p_str))

path_callback = joinpath(dir_julia, model_name * "_callbacks.jl")
if !isfile(path_callback) || build_julia_files == true
verbose == true && printstyled("[ Info:", color=123, bold=true)
verbose == true && !isfile(path_callback) && print(" Building callback file as it does not exist ...")
verbose == true && isfile(path_callback) && print(" By user option rebuilds callback file ...")
b_build = @elapsed callback_str, tstops_str = create_callbacks_SBML(ode_system, parameter_map,
state_map, model_SBML, model_name, path_yaml, dir_julia, custom_parameter_values=custom_parameter_values,
write_to_file=write_to_file)
verbose == true && @printf(" done. Time = %.1es\n", b_build)
else
verbose == true && printstyled("[ Info:", color=123, bold=true)
verbose == true && print(" Callback file exists and will not be rebuilt\n")
callback_str, tstops_str = get_function_str(path_callback, 2)
verbose == true && printstyled("[ Info:", color=123, bold=true)
verbose == true && print(" Building model callbacks ...")
b_build = @elapsed begin
cbset, compute_tstops, check_cb_active, convert_tspan = create_callbacks_SBML(ode_system, parameter_map,
state_map, model_SBML,
model_name, path_yaml, dir_julia,
custom_parameter_values=custom_parameter_values,
write_to_file=write_to_file)
end
get_callback_function = @RuntimeGeneratedFunction(Meta.parse(callback_str))
cbset, check_cb_active, convert_tspan = get_callback_function("https://xkcd.com/2694/") # Argument needed by @RuntimeGeneratedFunction
compute_tstops = @RuntimeGeneratedFunction(Meta.parse(tstops_str))
verbose == true && @printf(" done. Time = %.1es\n", b_build)

petab_model = PEtabModel(model_name,
compute_h,
Expand Down Expand Up @@ -146,16 +139,26 @@ end

# For reading the run-time generated PEtab-related functions which via Meta.parse are passed
# on to @RuntimeGeneratedFunction to build the PEtab related functions without world-problems.
function get_function_str(file_path::AbstractString, n_functions::Int64)::Vector{String}
function get_function_str(file_path::AbstractString, n_functions::Int64; as_str::Bool=false)::Vector{String}

f_start, f_end = zeros(Int64, n_functions), zeros(Int64, n_functions)
i_function = 1
in_function::Bool = false
n_lines = open(file_path, "r") do f countlines(f) end
if as_str == false
n_lines = open(file_path, "r") do f countlines(f) end
else
n_lines = length(split(file_path, '\n'))
end
body_str = Vector{String}(undef, n_lines)

f = open(file_path, "r")
for (i_line, line) in pairs(readlines(f))
if as_str == false
f = open(file_path, "r")
lines = readlines(f)
else
lines = split(file_path, '\n')
end

for (i_line, line) in pairs(lines)

if length(line) ≥ 8 && line[1:8] == "function"
f_start[i_function] = i_line
Expand All @@ -170,7 +173,7 @@ function get_function_str(file_path::AbstractString, n_functions::Int64)::Vector

body_str[i_line] = string(line)
end
close(f)
as_str == false && close(f)

out = Vector{String}(undef, n_functions)
for i in eachindex(out)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,20 +198,10 @@ function _PEtabModel(system,

# For Callbacks. These function are needed by SBML generated PEtab-files, as for those we as an example rewrite
# piecewise expressions into events
if isnothing(events)
write_callbacks_str = "function getCallbacks_" * model_name * "(foo)\n"
write_tstops_str = "\nfunction compute_tstops(u::AbstractVector, p::AbstractVector)\n"
write_tstops_str *= "\t return Float64[]\nend\n"
write_callbacks_str *= "\treturn CallbackSet(), Function[], false\nend"
else
parameter_info = process_parameters(parameters_data)
measurement_info = process_measurements(measurements_data, observables_data)
θ_indices = compute_θ_indices(parameter_info, measurement_info, system, _parameter_map, _state_map, experimental_conditions)
write_callbacks_str, write_tstops_str = process_petab_events(events, system, model_name, θ_indices)
end
get_callback_function = @RuntimeGeneratedFunction(Meta.parse(write_callbacks_str))
cbset, check_cb_active, convert_tspan = get_callback_function("https://xkcd.com/2694/") # Argument needed by @RuntimeGeneratedFunction
compute_tstops = @RuntimeGeneratedFunction(Meta.parse(write_tstops_str))
parameter_info = process_parameters(parameters_data)
measurement_info = process_measurements(measurements_data, observables_data)
θ_indices = compute_θ_indices(parameter_info, measurement_info, system, _parameter_map, _state_map, experimental_conditions)
cbset, compute_tstops, convert_tspan = process_petab_events(events, system, θ_indices)

petab_model = PEtabModel(model_name,
compute_h,
Expand All @@ -238,7 +228,7 @@ function _PEtabModel(system,
"",
"",
cbset,
check_cb_active,
Function[],
true)
return petab_model
end
Expand Down
61 changes: 37 additions & 24 deletions src/Process_PEtab_files/Julia_tables_provided/Parse_input.jl
Original file line number Diff line number Diff line change
Expand Up @@ -441,35 +441,47 @@ function parse_petab_observables(observables::Dict{String, PEtabObservable})::Da
end


function process_petab_events(events::Union{T, Vector{T}},
function process_petab_events(events::Union{T, Vector{T}, Nothing},
system,
model_name::String,
θ_indices::ParameterIndices) where T<:PEtabEvent

# Must be a vector for downstream processing
if events isa PEtabEvent
events = [events]
end

write_callbacks_str = "function getCallbacks_" * model_name * "(foo)\n"
write_tstops_str = "\nfunction computeTstops(u::AbstractVector, p::AbstractVector)\n"
for (i, event) in pairs(events)
event_name = "event" * string(i)
function_str, callback_str = process_petab_event(event, event_name, system)
write_callbacks_str *= function_str * "\n"
write_callbacks_str *= callback_str * "\n"
if !isnothing(events)
callbacks = Vector{SciMLBase.DECallback}(undef, length(events))
write_tstops = "\nfunction computeTstops(u::AbstractVector, p::AbstractVector)\n"
for (i, event) in pairs(events)
event_name = "event" * string(i)
_affect, _condition, _callback = process_petab_event(event, event_name, system)
affect! = @RuntimeGeneratedFunction(Meta.parse(_affect))
condition = @RuntimeGeneratedFunction(Meta.parse(_condition))
callback = @RuntimeGeneratedFunction(Meta.parse(_callback))
callbacks[i] = callback(affect!, condition)
end
_get_cbset = "function get_cbset(cbs)\n\treturn CallbackSet(" * prod("cbs[$i], " for i in 1:length(events))[1:end-2] * ")\nend"
get_cbset = @RuntimeGeneratedFunction(Meta.parse(_get_cbset))
cbset = get_cbset(callbacks)
else
cbset = CallbackSet()
end
callback_names = prod(["cb_event" * string(i) * ", " for i in eachindex(events)])[1:end-2]
_write_tstops_str, convert_tspan = PEtab.create_tstops_function(events, system, θ_indices)
write_tstops_str *= "\treturn" * _write_tstops_str * "\n" * "end"

write_callbacks_str *= "\treturn CallbackSet(" * callback_names * "), Function[], " * string(convert_tspan) * "\nend"
write_tstops = "\nfunction computeTstops(u::AbstractVector, p::AbstractVector)\n"
if !isnothing(events)
_write_tstops, convert_tspan = PEtab.create_tstops_function(events, system, θ_indices)
else
_write_tstops, convert_tspan = "Float64[]", false
end
write_tstops *= "\treturn " * _write_tstops * "\n" * "end"
get_tstops = @RuntimeGeneratedFunction(Meta.parse(write_tstops))

return write_callbacks_str, write_tstops_str
return cbset, get_tstops, convert_tspan
end


function process_petab_event(event::PEtabEvent, event_name, system)::Tuple{String, String}
function process_petab_event(event::PEtabEvent, event_name, system)::Tuple{String, String, String}
state_names = replace.(string.(states(system)), "(t)" => "")
parameter_names = string.(parameters(system))

Expand Down Expand Up @@ -519,7 +531,7 @@ function process_petab_event(event::PEtabEvent, event_name, system)::Tuple{Strin
end
end

condition_has_states = PEtab.check_condition_has_states(condition, state_names)
condition_has_states = check_condition_has_states(condition, state_names)
discrete_event = condition_has_states == false

if discrete_event == true
Expand All @@ -543,12 +555,12 @@ function process_petab_event(event::PEtabEvent, event_name, system)::Tuple{Strin
for i in eachindex(parameter_names)
condition = PEtab.SBMLImporter.replace_variable(condition, parameter_names[i], "integrator.p["*string(i)*"]")
end
condition_str = "\n\tfunction condition_" * event_name * "(u, t, integrator)\n\t\t" * condition * "\n\tend\n"
condition_str = "\nfunction condition_" * event_name * "(u, t, integrator)\n\t" * condition * "\nend\n"

# Build the affect syntax for the event. Note, a tmp variable is used in case of several affects. For example, if the
# event affects u[1] and u[2], then I do not want that a change in u[1] should affect the value for u[2], similar holds
# for parameters
affect_str = "\tfunction affect_" * event_name * "!(integrator)\n\t\tu_tmp = similar(integrator.u)\n\t\tu_tmp .= integrator.u\n\t\tp_tmp = similar(integrator.p)\n\t\tp_tmp .= integrator.p\n\n"
affect_str = "function affect_" * event_name * "!(integrator)\n\tu_tmp = similar(integrator.u)\n\tu_tmp .= integrator.u\n\tp_tmp = similar(integrator.p)\n\tp_tmp .= integrator.p\n\n"
affects = replace.(string.(affects), "(t)" => "")
for (i, affect) in pairs(affects)
_affect = targets[i] * " = " * affect
Expand All @@ -566,21 +578,22 @@ function process_petab_event(event::PEtabEvent, event_name, system)::Tuple{Strin
affect_str *= '\n' * "\tend"

# Build the callback
callback_str = "function get_callback" * event_name * "(affect!, cond)\n"
if discrete_event == false
if affect_equality == true
callback_str = "\tcb_" * event_name * " = ContinuousCallback(" * "condition_" * event_name * ", " * "affect_" * event_name * "!, "
callback_str *= "\tcb = ContinuousCallback(cond, affect!, "
elseif affect_neg == true
callback_str = "\tcb_" * event_name * " = ContinuousCallback(" * "condition_" * event_name * ", nothing, " * "affect_" * event_name * "!, "
callback_str *= "\tcb = ContinuousCallback(cond, nothing, affect!, "
else
callback_str = "\tcb_" * event_name * " = ContinuousCallback(" * "condition_" * event_name * ", " * "affect_" * event_name * "!, nothing, "
callback_str *= "\tcb = ContinuousCallback(cond, affect!, nothing, "
end
else
callback_str = "\tcb_" * event_name * " = DiscreteCallback(" * "condition_" * event_name * ", " * "affect_" * event_name * "!, "
callback_str *= "\tcb = DiscreteCallback(cond, affect!, "
end
callback_str *= "save_positions=(false, false))\n" # So we do not get problems with saveat in the ODE solver
function_str = condition_str * '\n' * affect_str * '\n'
callback_str *= "\treturn cb\nend\n"

return function_str, callback_str
return affect_str, condition_str, callback_str
end


Expand Down
Loading