Function in notebook vs function in package?

Hi all,

I started to write a package for my project, where I put all the useful functions and then import the package to use them. Problems arise, so here is the function:

The function is used to generate odes to use in NDSolve

MakeSystem[var_, vart_, sys_]:=
Module[{v, vt, S, St, Sf},
v = var;
vt = vart;
S = sys;
St = S/.Thread[v-> vt]; 
Thread[D[vart, t] == St]]

This is an example to use the function:

dndt = r * (1 - k * n) * n - c * n * p;

dpdt = c * n * p;

var = {n, p};

vart = {n[t], p[t]}

system = {dndt, dpdt};

MakeSystem[var, vart, system]

If I put the function in the notebook, it produces exactly what I want:

n'[t] == r * (1 - k * n[t]) * n[t] - c * n[t] * p[t]

p'[t] == c * n[t] * p[t]

But if I put the function in the package, the D[vart, t] produces zeros, so the output is

0 == r * (1 - k * n[t]) * n[t] - c * n[t] * p[t]

0 == c * n[t] * p[t]

Any help?

Your variable t is the problem. It shows up “raw” in several places. When you put your MakeSystem definition inside of a package, that t will not be in the Global' context, but in whatever context your package uses, so it might be something like Test'Private't (btw, all of the ’ should be backticks) You end up producing a derivative of an expression with respect to a variable that isn’t in that expression, and such a derivative will evaluate to 0.

One fix would be to ask the caller to provide the symbol, so add a fourth argument to MakeSystem that is expected to be the symbol/variable with respect to which we’re going to take the derivative. The problem with this is that you need to make sure you use the same variable in vart, but that’s also a good thing, because it makes the intent very explcit.

Actually, you could just get rid of vart altogether–it can be constructed from var and the new argument. I would have called the new argument var, but… :slight_smile:

And since I started making refactoring suggestions, I guess I’ll continue… You also don’t need Module. A couple of simplifications would lead to:

MakeSystem[fnNames_List, var_, rhs_List] :=
 With[
  {fns = Through[fnNames[var]]},
  Thread[Equal[D[fns, var], rhs /. Thread[fnNames -> fns]]]]

Thanks a lot Eric for the solution.

Yup, that’s what I also suspect about the parameter t. I’m just not sure how to handle it.

The code I posted above handles it. I could make it clearer by using pattern matching on var:

MakeSystem[fnNames_List, var_Symbol, rhs_List] := 
 With[{fns = Through[fnNames[var]]}, 
  Thread[Equal[D[fns, var], rhs /. Thread[fnNames -> fns]]]]

Now using your data:

MakeSystem[{n, p}, t, {r*(1 - k*n)*n - c*n*p, c*n*p}]
(*{Derivative[1][n][t] == r n[t] (1 - k n[t]) - c n[t] p[t], Derivative[1][p][t] == c n[t] p[t]} *)