You have good answers already, but as I was nitpicking about your terminology I wanted to explain why. The strength of Mathematica compared to e.g. a pocket calculator is that it provides a powerful programming language and what you actually do when making good use of it is writing programs -- and for doing that it is in general very helpful to be precise about the concepts and terminology you are using. There are two reasons why it pays off to make a deliberate distinction between independent variables and parameters in this case:
It keeps you out of Trouble
I think your originial question arouse because you didn't know how to formulate a partial derivative with respect to one of two variables. b.gatessucks has shown how you can do that and then solve your system symbolically with DSolve
. Had you made your code reflect the destinction between parameters and independent variables, that problem wouldn't even have bothered you as it is of course not actually necessary to write partial derivatives for an ODE.
It lets you do more with less Effort
When solving symbolically, the distinction between parameters and independent variables doesn't look like very important as the nature of the symbolic solution is that it is valid for all parameters. Still I would suggest to rewrite the symbolic solution in a form that reflects that we are solving an ODE for a set of parameters and the result is a (mathematical) function of only one independent variable:
Block[{a, b, th, x},
symbolic[a_, b_, th_] = x /. First[DSolve[
{(x'')[t] == -a x'[t],
x'[0] == b Cos[th], x[0] == 0}, x, t]]
]
For the moment the way I've defined the symbolic solution looks just like minor syntatic sugar. Here is how you can use it to create e.g. a plot of the result:
Plot[symbolic[0.2/2.3, 10.2, 0][t], {t, 0, 10},
PlotRange -> {-100, 100}, Frame -> True]
There are subtleties to be explained: I define a function (computer sience terminology) which accepts three arguments (the parameters) and returns the abstraction of a mathematical function in the form of a Mathematica pure Function
. As the symbolic solution is valid for all possible settings of the parameters we only need to find that solution once and can then just insert the parameters. This is why we can use Set
(=
) and don't need SetDelayed
(:=
): that way DSolve
will only be called once at the time we define symbolic
. To prevent possible problems with existing definitions for any of the symbols used as parameters and variables I'm making that definition within a Block
.
For a majority of real world problems you will unfortunately not be able to find a symbolic solution and have to use numeric methods. That means that you will have to solve a different differential equation for every different set of parameters. Here is how you can do that:
numeric[a_?NumericQ, b_?NumericQ, th_?NumericQ] := Block[{x},
x /. First[
NDSolve[{x''[t] == -a*x'[t], x'[0] == b*Cos[th],
x[0] == 0}, {x}, {t, 0, 2}
]]
]
Most important is that I now have to use SetDelayed
(:=
) as now I have to make a new call to NDSolve
for every new set of parameters. As NDSolve
can only do its work when all parameters are given in numeric form it makes sense to only accept those arguments when they are numeric, thus the _?NumcericQ
patterns. Again I use a Block
to avoid possible problems with predefined variables, but this time that protection is not needed at the time numeric
is defined but at the time when it is called, which is why the Block
now is on the right hand side of the definition and not enclosing it. Again numeric
is a (CS term.) function which returns a mathematical function but this time in the form of a Mathematica InterpolatingFunction
. Fortunately we can use that almost everywhere in the same way as we could use the Function
that was returned for the symbolic solution. This shows how you can make a plot for the numeric solution:
Plot[Evaluate[numeric[0.2/2.3, 10.2, 0][t]], {t, 0, 10},
PlotRange -> {-100, 100}, Frame -> True]
Note that this is almost exactly the same as for the symbolic solution. Being able to access similar things in an uniform way is a great advantage when writing programs (== using Mathematica). I just added an Evaluate
for performance reasons: that way the solution (in form of an InterpolatingFunction
) is only calculated once and not afresh for every point for which Plot
evaluates the solution. As the call to NDSolve
is very fast in this case, it hardly makes a difference here but will make a huge difference for more complicated cases.
Finaly there is -- as Daniel Lichtblau has shown -- ParametricNDSolve
, which provides a new way to solve parametrized differential equations in version 9. It can be used like this:
parametric = x /. First[ParametricNDSolve[
{x''[t] == -a*x'[t], x'[0] == b*Cos[th], x[0] == 0}, {x}, {t, 0,
2}, {a, b, th}
]]
now the symbol parametric
is set to a ParametricFunction
object which does the same thing as the above definitions: given a set of parameters it will return a mathematical function (in the form of an InterpolatingFunction
). As the ParametericFunction
objects knows that it's always solving the same system just with different parameters it can do that in some cases in a more efficient way than a independent NDSolve
. I have not yet much experience in how much difference that makes in practice, but it is a promising functionality. The nice thing is: with the above definitions, you can use the symbolic, the numeric and the parametric solutions in very much the same way, which makes it very easy to write something like this Manipulate
which compares the three results (and shows that the numeric solutions are indeed very good approximations to the exact solution):
Manipulate[
Plot[Evaluate[method[a, b, th][t]], {t, 0, 10},
PlotRange -> {-100, 100}, Frame -> True, FrameLabel -> {"t", "x"}],
{th, 0, Pi}, {{a, 0.2/2.3}, 0.01, 0.1}, {{b, 10.8}, 1, 20},
{{method, symbolic}, {symbolic -> "symbolic", numeric -> "numeric",
parametric -> "parametric"}}
]
So making your code and syntax reflect the abstraction of what you are actually doing will make it easier to read, to understand and to use (as in the above Manipulate
or when you need to exchange parts of your calculation at a later time).
x'[t,θ]
should beD[x[t,θ], x]
andx''[t,θ]
should beD[x[t,θ], {x, 2]
. $\endgroup$