3
$\begingroup$

I am trying to solve a BVP for the system of equations. I need $r(0)$ and $\beta(0)$ to be fixed, and I need $r$ and $z$ to be fixed at the other end. I want $z(0)$ and the end value of $t$ to take any value necessary to have these conditions satisfied. I have been trying to use FindRoot, but it never works for me when I need it to find two variables instead of one. Am I using it wrong? Here's my code:

ClearAll["Global`*"]
sol[(k_)?NumericQ, (z1_)?NumericQ, (tend_)?NumericQ] := {r[tend], z[tend]} /. 
  First[NDSolve[{(k + Derivative[1][β][t])*r[t] + Sin[β[t]] == 0, 
                 Derivative[1][r][t] == Cos[β[t]], 
                 Derivative[1][z][t] == Sin[β[t]], 
                 r[0] == 0.0001, z[0] == z1, β[0] == 0}, 
                 {r, z, β}, {t, 0, tend}]]
FindRoot[{sol[1, z1, tend][[1]] == 1, sol[1, z1, tend][[2]] == 0}, 
         {{tend, 1}, {z1, 1}}]

Also, if there is a better way to approach this problem, please let me know. Thank you!

EDIT 1: It works perfectly fine for one equation and one unknown:

sol1[(tend_)?NumericQ] := z[tend] /. 
  First[NDSolve[{(1.6 + Derivative[1][β][t])*r[t] + Sin[β[t]] == 0, 
                 Derivative[1][r][t] == Cos[β[t]], 
                 Derivative[1][z][t] == Sin[β[t]], 
                 r[0] == 0.0001, z[0] == 2, β[0] == 0}, 
                {r, z, β}, {t, 0, tend}]]
FindRoot[sol1[tend] == 0, {tend, 1}]
(* {tend -> 2.76777} *)
$\endgroup$
2
  • $\begingroup$ Of course if you plug in values in the definition, it will return True or False, however, what I have input there are equations indeed. They have variables in them that I ask FindRoot to solve for. Look at my EDIT 1. It works fine for one unknown. So the issue is not what you mention. $\endgroup$
    – juv95
    Commented Sep 26, 2022 at 5:32
  • 1
    $\begingroup$ It could be an evaluation order issue. let me see. $\endgroup$
    – Nasser
    Commented Sep 26, 2022 at 5:57

1 Answer 1

8
$\begingroup$

As pointed by Nasser, it's a matter of evaluation order. Simplest solution is to add Evaluated -> False:

FindRoot[{sol[1, z1, tend][[1]] == 1, 
  sol[1, z1, tend][[2]] == 0}, {{tend, 1}, {z1, 1}}, Evaluated -> False]

Why does the original attempt fail? As we all know, though FindRoot owns the attribute HoldAll, it will try to analyze its arguments by default. During the analyzation, the arguments will be evaluated. ?NumericQ will stop FindRoot from touching code inside sol, but it won't stop evaluation of expressions like sol[1, z1, tend][[1]]! What will happen then? We know Part ([[]]) works not only on List {}:

fff[aaa, bbb, c343434cc][[3]]
(* c343434cc *)

sol[1, z1, tend][[1]] 
(* 1 *)
sol[1, z1, tend][[2]] 
(* z1 *)

Then sol[1, z1, tend][[1]] == 1 becomes 1 == 1 i.e. True, sol[1, z1, tend][[2]] == 0 becomes z1 == 0.

So, another work-around is to use Indexed instead of Part, because Indexed extract elements only from List:

FindRoot[{Indexed[sol[1, z1, tend], 1] == 1, 
  Indexed[sol[1, z1, tend], 2] == 0}, {{tend, 1}, {z1, 1}}]

… if there is a better way to approach this problem, please let me know.

Then you should not miss ParametricNDSolveValue:

psol = ParametricNDSolveValue[{(k + β'[t]) r[t] + Sin[β[t]] == 0, 
    r'[t] == Cos[β[t]], z'[t] == Sin[β[t]], r[0] == 0.0001, 
    z[0] == z1, β[0] == 0}, {r[tend], z[tend]}, {t, 0, tend}, {k, z1, tend}];

FindRoot[psol[1, z1, tend] == {1, 0}, {{tend, 1}, {z1, 1}}]
(* {tend -> 1.0471, z1 -> 0.267949} *)
$\endgroup$
2
  • $\begingroup$ Thank you for the clear explanation! This solved my issue. $\endgroup$
    – juv95
    Commented Sep 26, 2022 at 6:32
  • 1
    $\begingroup$ @juv95 Forgot to mention ParametricNDSolveValue is a much better tool for attacking the problem. See my edit. $\endgroup$
    – xzczd
    Commented Sep 26, 2022 at 7:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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