I think there are two misunderstandings here, both are somewhat subtle. First, giving the "Event" option as you did doesn't work because it is immediately evaluated, so that NDSolve does only see this:
flag = False;
And[! flag, y'[t] == 0]
(*
==> Derivative[1][y][t] == 0
*)
meaning it never even sees that the event should depend on flag at all. This can be circumvented by using RuleDelayed (:>) instead of Rule (->). Unfortunately the result will still not be what you expect. The reason is that y'[t]==0 will only fire if at any step y'[t]==0 evaluates to True, which will only happen by chance and/or if the step size is small enough. It is much better/more reliable to let NDSolve check for changes in sign and the combination of these changes will make your example work as I think you expected:
flag = False; piHalf =.;
NDSolve[{y''[t] == -y[t], y[0] == 0, y'[0] == 1}, y, {t, 0, 20},
Method -> {
"EventLocator",
"Event" :> And[! flag, y'[t] >= 0],
"EventAction" :> (flag = True; piHalf = t;)
}
];
piHalf
I just have seen Nassers answer and wanted to add some remarks about it:
1) Nassers WhenEvent basically is equivalent to these "EventLocator" settings:
flag = False; piHalf =.;
NDSolve[{y''[t] == -y[t], y[0] == 0, y'[0] == 1}, y, {t, 0, 20},
Method -> {
"EventLocator",
"Event" -> y'[t],
"EventAction" :> (If[! flag, piHalf = t]; flag = True;)
}
];
piHalf
which is somewhat different: the "EventAction" is in this case evaluated at every sign change of y'[t], but only the first time piHalf is set. The other solution will only evaluate "EventAction" once. For the example at hand the net result (value of piHalf) is of course the same.
2) WhenEvent has the attribute HoldAll, which makes it behave more like the RuleDelayed case of the "Event" setting which solves the evaluation problem. Using a predicate in WhenEvent which is just refering to a global variable seems to cause kernel crashes, but there is a very elegant way to achieve that the event will only be triggered once without even bothering with a global variable:
NDSolve[{y''[t] == -y[t], y[0] == 0, y'[0] == 1,
WhenEvent[y'[t] == 0, piHalf = t; "RemoveEvent"]}, y, {t, 0, 20}
];
piHalf
3) if you decide to go with the "EventLocator" method you might also want to have a look at the option "Direction" which lets you discriminate between sign changes from below vs. from above.