5

Is it possible to use an anonymous function as an event function in Matlab. What I want to do is basically

opt = odeset('Events', @(t,y) (deal(y(end)-t^2,1,0)));
[T,Y] = ode45(@odefun,[tstart tend],y0,opt);

However, this returns an error complaining that the number of outputs to deal must be matched exactly. Is there some other way to make the anonymous function return multiple arguments?

3 Answers3

2

I noticed this post looking for the answer to the same question. This means that for some people the question may be still valid. Since finally I found the solution by myself, I'd like to give a little bit "outdated" answer.

Actually, yes - it's possible but not straightforward. Try this:

evnt_fun = @(t, f)subsref({'some stop condition', 1, 0}, struct('type', '{}', 'subs', {{':'}}));

I'm not able to fully check the backward-compatibility of the code. However, it works with R2011 and later MATLAB versions.

Jacek
  • 21
  • 2
1

No, you can't do it. Anonymous functions in Matlab only ever return one value.

Instead, you could define a thin wrapper around deal and pass your wrapper as a handle:

function [a b c] = wrapper(t,y)
    [a b c] = deal('some stop condition', 1, 0);
end

opt = odeset('Events', @wrapper);

[T, Y] = ode45(@odefun, [tstart tend], y0, opt);
Chris Taylor
  • 46,912
  • 15
  • 110
  • 154
  • 1
    The point is that I would like to avoid a wrapper function. Using deal, you CAN actually get the anonymous function to return three values (since deal just returns its arguments). However, the ODE-solver seems to be expecting a varying number of return values while deal must be matched exactly. – The input-validating guy Feb 19 '13 at 12:39
  • You're totally right. I'll have another look at this when I get a change. I suspect that it may be related to the fact that `ode45` passes a variable number of arguments to the event handler. – Chris Taylor Feb 19 '13 at 15:05
  • I suspect, that it's due to the function being evaluated with a single output in `odeevents` and with a output triplet in `odezero`. The number of output args of an anonymous function, however, is either one *or* three, but it cannot handle both. – embert Nov 23 '14 at 08:44
0

Also (this is very late in the game to be adding to this, but this frustrates me). Here is a solution with nested functions:

function [ dealfunchandle ] = dealwithit( arrayfunc )
% Takes as input an event function of (t,z) that returns a 3 array (in same order as event syntax).

    function [a, b, c] = dealfunc(t,z)
       output = arrayfunc(t,z);
       a = output(:,1);
       b = output(:,2);
       c = output(:,3);
    end

dealfunchandle = @dealfunc;
end

This function only has to be written once (handy if you have to use lots of different event functions). This can be used to generate an anonymous event function within the code as follows:

arrayfunc = @(t,y) [y(1), 0, 1];
events = dealwithit(arrayfunc);

opts = odeset('Events', events);

And then ode45 as per normal.

corjos
  • 16
  • 1