Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I'm trying to use the new WhenEvent functionality of NDSolve in Mathematica 9, in order to perform an action when a variable in the system reaches a certain value. I would like this variable to come from an external variable, like so:

var = y; (* this could come from somewhere else *)
list = {};

(* keep track of values of x for which y[x] == 1 *)
NDSolve[{y''[x] == -y[x], y[0] == 1, y'[0] == 0, 
  WhenEvent[Round[var[x], 0.1] == 1, AppendTo[list, x]]},
  y, {x, 0, 10}]

But this produces the errors

NDSolve::nbnum1: The function value Round[y[0.],0.1]==1 is not True or False when the arguments are {0.,1.,0.,0.,-1.}. >>

NDSolve::nbnum1: The function value Round[y[0.000143737],0.1]==1 is not True or False when the arguments are {0.000143737,1.,-0.000143737,-0.000143737,-1.}. >>

NDSolve::nbnum1: The function value Round[y[0.000287473],0.1]==1 is not True or False when the arguments are {0.000287473,1.,-0.000287473,-0.000287473,-1.}. >>

General::stop: Further output of NDSolve::nbnum1 will be suppressed during this calculation. >>

How can I use an "external" variable to specify which variable to watch in WhenEvent?

share|improve this question
add comment

1 Answer

up vote 8 down vote accepted

The problem is that WhenEvent has the attribute HoldAll, so var is never translated to y. Here's a standard trick to inject the actual value of var into the code:

var = y;
Reap[NDSolve[{y''[x] == -y[x], y[0] == 1, y'[0] == 0, 
  WhenEvent[Round[#[x], 0.1] == 1, Sow[x]]},
  y, {x, 0, 10}]]&[var]

(* Out: {{{y->InterpolatingFunction[{{0.,10.}},<>]}},{{5.99762}}} *)

Also, I replaced your AppendTo with a Reap/Sow combination, which is generally a bit more efficient.

There are other ways to inject the variable value into the code as well. For example:

var = y;
Reap[NDSolve[{y''[x] == -y[x], y[0] == 1, y'[0] == 0, 
  WhenEvent[Round[var2[x], 0.1] == 1, Sow[x]] /. var2 -> var},
  y, {x, 0, 10}]]

The ever popular Evaluate (although placement of the Evaluate is a bit tricky):

var = y;
Reap[NDSolve[{y''[x] == -y[x], y[0] == 1, y'[0] == 0, 
  WhenEvent[Evaluate[Round[var[x], 0.1] == 1], Sow[x]]},
  y, {x, 0, 10}]]

And, my personal favorite:

var = y;
With[{var=var},
  Reap[NDSolve[{y''[x] == -y[x], y[0] == 1, y'[0] == 0, 
    WhenEvent[Round[var[x], 0.1] == 1, Sow[x]]},
    y, {x, 0, 10}]]]
share|improve this answer
    
My personal favourite is a replacement rule but the other way around, var /. var_ :> Reap[... –  Rojo Dec 13 '12 at 8:36
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.