Registering a time dependent function inside a function in ModelingToolkit.jl

Let’s say that I build my model using functions that, if need be create variables and parameters, and return equations. In the end of the code i put all equations together. Let’s say I have an example block such as

using ModelingToolkit
@variables t            # independent variable (time)
@variables f(t) = 0.0 # external forcing

function external_forcing_equation(; CO2_multiplier = 4, specs...)
    @parameters CO2_multiplier = CO2_multiplier
    @parameters CO2_forcing = 5.35 # 5.35 is A0
    # Register a time-dependent step-like increase of forcing
    CO2_instant_increase(t) = t < 1000 ? 0.0 : CO2_multiplier*CO_forcing
    @register_symbolic CO2_instant_increase(t)
    return f ~ CO2_instant_increase
end

This codeblock won’t work, it yields

ERROR: syntax: Global method definition around C:\Users\gd419\.julia\packages\Symbolics\CNA2l\src\register.jl:91 needs to be placed at the top level, or use "eval".
Stacktrace:
 [1] top-level scope
   @ REPL[31]:1

I am not sure how to proceed from here because putting @eval before @register doesn’t solve the problem either. How can I create a “registered function” within another function?

That won’t work because it has to define a dispatch, so instead you’d define a callable struct outside of the function and instantiate it with values.

But also, this case is easier with just CO2_instant_increase(t) = ifelse(t < 1000,0.0, CO2_multiplier*CO_forcing)

1 Like

Sorry for pinging an old thread, but got an example on defining a callable struct outside of the function?

Perhaps you mean something like this?

struct CO2_function
    CO2_multiplier::Any
    CO2_increase::Any
end
function (f::CO2_function)(t)
    ifelse(t < 1000,0.0, f.CO2_multiplier*f.CO_forcing)
end
@register_symbolic (f::CO2_function)(t)

Yeah does that not work?

Yes it works, just checking if you had something else in mind.

Nope that looks like it’s the correct way to do this.