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 am trying to add a time dependent fraction to a parameter in NDSolve, i.e. when 10 < t< 20, add s to k1...

Manipulate[ sol = NDSolve[{A'[t] == k1*A[t], A[0] == 10, 
                           WhenEvent[ 10 < t < 20, k1 -> (k1 + s)]},
                           A, {t, 0, 100}],
            {k1, 0.0, 1.0}, {s, 0.0, 1.0}]

But I cannot get the code to work, and get the following error message. Does anyone have any suggestions, or can find the error in the code?

NDSolve::wenset: Warning: the rule FE`k1$$16->FE`k1$$16+FE`s$$16 will not
directly set the state because the left-hand side is not a list of state variables. >>
share|improve this question

4 Answers 4

up vote 1 down vote accepted

I don't think you can use WhenEvent to do what you want. The value of k1 is passed in the DE in NDSolve, not the symbol. WhenEvent has the attribute HoldAll, so that it deals with k1 and s as Symbols. Perhaps you could use ParametricNDSolve (see below).

Perhaps you want something like this?

kparam[t_?NumericQ, k1_, s_] := If[10 < t < 20, k1 + s, k1];
Manipulate[
 sol = NDSolve[{A'[t] == kparam[t, k1, s]*A[t], A[0] == 10}, A, {t, 0, 100}],
 {k1, 0.0, 1.0}, {s, 0.0, 1.0}]

The solution (for k1 == 0.1, s == 0.2) looks like this:

Plot[Evaluate[A[t] /. sol], {t, 0, 30}]

Plot of a solution

This accomplishes the same thing with ParametricNDSolve (if you have v9.0.1):

psol = ParametricNDSolve[{A'[t] == k1*A[t], A[0] == 10, 
   WhenEvent[t < 10, k1 -> (k1 + s)], 
   WhenEvent[t < 20, k1 -> (k1 - s)]}, 
  A, {t, 0, 100}, {k1 \[Element] Reals, s \[Element] Reals}];

Plot[Evaluate[A[0.1, 0.2][t] /. psol], {t, 0, 30}]
  (* output same as above *)
share|improve this answer
    
Thanks, all solutions are great! –  tarhawk Apr 29 '13 at 2:04

I'd like to extend the solution offered by Michael E2:

psol = ParametricNDSolve[{A'[t] == k1*A[t], A[0] == 10, 
    WhenEvent[t < 10, k1 -> (k1 + s)], 
    WhenEvent[t < 20, k1 -> (k1 - s)]}, 
   A, {t, 0, 100}, {k1 \[Element] Reals, s \[Element] Reals}];
(*Plot[Evaluate[A[0.1, 0.2][t] /. psol], {t, 0, 30}]*)

Note that even in the case the DE has two WhenEvents one can find the sensitivity of k1:

Plot[Evaluate[(A[0.1, 0.2][t] + {0, .1, -.1} D[A[k1, 0.2], k1][t] /. 
     k1 -> 0.1) /. psol], {t, 0, 30}, Filling -> {2 -> {3}}]

That's pretty cool!

enter image description here

share|improve this answer

You don't need WhenEvent[] for this:

Manipulate[Plot[(A/. NDSolve[{A'[t] == (k1 + s HeavisidePi[1/10 (t - 15)]) A[t], A[0] == 10},
                              A, {t, 0, 100}] [[1]] )[x], {x, 0, 30}], 
{k1, 0.0, 1.0}, {s, 0.0, 1.0}]

enter image description here

share|improve this answer

You do not need WhenEvent here as stated. You can use it though but you have to treat k as a function of t, that is a discrete state variable k[t].

Manipulate[
 DynamicModule[{
   sol = NDSolveValue[{
      y'[t] == k[t] y[t],
      y[0] == 10, k[0] == k0,
      WhenEvent[t > 10, k[t] -> k[t] + s],
      WhenEvent[t < 20, k[t] -> k[t] - s]
      }, y, {t, 0, 100},
     DiscreteVariables -> k]},
  Plot[sol[t], {t, 0, 30}]],
 {{k0, .1}, 0, 1}, {{s, .2}, 0, 1}]

(* similar output *)
share|improve this answer

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.