3
$\begingroup$

My problem

I have a large system of differential equations which is automatically created, but to give you an easy example let's just say it is

eqs = {f'[x] == a[x]*g[x], g'[x] == -a[x]*f[x]};

As you can see, the system of equations contains the still undetermined function a[x]. I want to numerically solve these equations for different functions a[x], what I wrote is something like

solveMyEquation[a_] := Module[{foo, bar},
  foo = Flatten[{Evaluate[eqs], f[0] == 0, g[0] == 1}];
  bar = NDSolve[foo, {f, g}, {x, 0, 10}];
  Plot[Evaluate[{f[x], g[x]} /. bar], {x, 0, 10}]]

If I try to solve this using e.g. solveMyEquation[1 &], I get a huge load of error messages, starting with

NDSolve::underdet: There are more dependent variables, {a[x],f[x],g[x]}, than equations, so the system is underdetermined.
ReplaceAll::reps: {NDSolve[{(f^\[Prime])[x]==a[x] g[x],(g^\[Prime])[x]==-a[x] f[x],f[0]==0,g[0]==1},{f,g},{x,0,10}]} is neither a list of replacement rules nor a valid dispatch table, and so cannot be used for replacing.
NDSolve::dsvar: 0.0002042857142857143` cannot be used as a variable.

What I have tried

The problem seems to be that the function a[x] is not inserted into eqs. That's what I was trying to achieve with the Evaluate, but apparently it doesn't work the way I thought it did.

The following obviously works fine:

solveMyEquation[a_] := Module[{foo, bar},
  foo = Flatten[{{f'[x] == a[x]*g[x], g'[x] == -a[x]*f[x]}, f[0] == 0, g[0] == 1}];
  bar = NDSolve[foo, {f, g}, {x, 0, 10}];
  Plot[Evaluate[{f[x], g[x]} /. bar], {x, 0, 10}]]
solveMyEquation[1 &]

But in my actual problem, the expression for eqs fills several pages and I don't like copy-pasting it (even though it does work).

$\endgroup$
  • 1
    $\begingroup$ Related thread here $\endgroup$ – Stitch Dec 13 '16 at 16:00
2
$\begingroup$

Your local variable a is taking precedence over the global a defined in eqs. There are multiple solutions suggested in this thread. For the sake of completeness, I show here how to use one of the ideas by using Symbol:

solveMyEquation[a_] :=  Module[{foo, bar}, 
 foo = Flatten[{Evaluate[eqs], f[0] == 0, g[0] == 1}];
 bar = NDSolve[foo /. Symbol@"a" -> a, {f, g}, {x, 0, 10}];
 Plot[Evaluate[{f[x], g[x]} /. bar], {x, 0, 10}]]

EDIT:

Of course, it would be better to have eqs such that we don't have to deal with variable conflicts, so if there is no way to influence how eqs is generated, we can season it a bit by converting to a pure function which we can then use inside our Module. To do this, we can make a simple function:

fixeqs[eq_] := Function[eq /. a -> #];
solveMyEquation[a_] := 
  Module[{foo, bar}, 
  foo = Flatten[{fixeqs[eqs]@a, f[0] == 0, g[0] == 1}];
  bar = NDSolve[foo, {f, g}, {x, 0, 10}];
  Plot[Evaluate[{f[x], g[x]} /. bar], {x, 0, 10}]]
$\endgroup$
  • $\begingroup$ I was hoping there is a nicer way, but I guess I'll go with this. Thanks! $\endgroup$ – Noiralef Dec 13 '16 at 16:07
  • 1
    $\begingroup$ I agree, it is best to not have a variable overlap to begin with. Updated the answer to reflect a new way. $\endgroup$ – Stitch Dec 13 '16 at 17:08
1
$\begingroup$

Simple solution: turn your eqs into a function of a, f, and g: the following works for me

eqns[a_, f_, g_] := {f'[x] == a[x]*g[x], g'[x] == -a[x]*f[x]};
solveMyEquation[a_] := 
 Module[{foo, bar}, 
  foo = Flatten[{eqns[a, f, g], f[0] == 0, g[0] == 1}];
  bar = NDSolve[foo, {f, g}, {x, 0, 10}];
  Plot[Evaluate[{f[x], g[x]} /. bar], {x, 0, 10}]]
solveMyEquation[1 &]
$\endgroup$
  • $\begingroup$ Thanks for the reply! In my actual problem, it would be a quite long parameter list to eqs as well as to several other functions I use for constructing eqs, though. I guess it would work, but I'd consider it ugly... I'll leave the question open for a while in hope for something else. $\endgroup$ – Noiralef Dec 13 '16 at 16:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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