Skip to main content

differential equations - Finding the "least" singular solution for NDSolve


I need to solve a ODE for a function $f_\sigma(x)$, where $\sigma$ is a free parameter to tune. All the solutions are supposed to be singular for some value of $x$, except one for a given value $\sigma=\sigma^*$. $f_\sigma(x)$ behaves nicely for every $x$, and as I get close to $\sigma^*$, the value at which $f(x)$ diverges moves further away (i.e. to larger $x$).


I need to find $\sigma^*$. My idea would be to do a iterative procedure in which I compute $f_\sigma(x)$ for different values $\sigma$, and then focus on the range of values for which the singularity happens the latest (the largest $x$). However I do not know how to extract this information from NDSolve.


kd = (2^(d - 1) π^(d/2) Gamma[d/2]);
d = 3;
ext = 100;
s2[σ_] :=

NDSolve[{f''[p] - 2 f[p] f'[p] + (1 + d/2) f[p] + (1 - d/2) p f'[p] == 0,
f'[0] == σ,
f[0] == 0
}, f[p], {p, 0, ext}
]

Doing for example s2[-.3], Mathematica tells me


NDSolve::ndsz: At p == 4.160343901296758`, step size is effectively zero; singularity or stiff system suspected. >>

From this I would like to extract the value p=4.1603....., but I do not know how to do this.



Any tips?



Answer



Although the overall conclusions of this answer are unchanged, details have been edited substantially.


I surmise from the question and comments that the OP is seeking a solution to the ODE that does not grow exponentially at large p. Two solutions already identified are f[p] = 0 and f[p] = p. In addition to these trivial solutions, another exists near σ = -0.228601, and other answers have focused on obtaining more accurate values for this σ. Unfortunately, even with highly accurate values for σ, f[p] has been computed only for modest values of p. This answer takes a different approach, finding the desired f[p] directly and determining the corresponding σ only as a byproduct.


If f[p] is not to explode in magnitude for large p, f''[p] must be small compared to other terms in the ODE. So, let us drop this term from the ODE to obtain an asymptotic equation, which can be solved for f'[p].


Solve[- 2 f[p] f'[p] + (1 + d/2) f[p] + (1 - d/2) p f'[p] == 0, f'[p]][[1, 1]]
(* f'[p] -> (5 f[p])/(p + 4 f[p]) *)

As shall be seen, f[p] is approximately equal to p for large p, so, f'[p] approaches 1 asymptotically. This is sufficient information to obtain the desired solution, computed out to pmax = 10000.


pmax = 10000; 

{a1, a2} = NDSolveValue[{f''[p] - 2 f[p] f'[p] + (1 + d/2) f[p] + (1 - d/2) p f'[p] == 0,
f[0] == 0, - 2 f[pmax] f'[pmax] + (1 + d/2) f[pmax] + (1 - d/2) pmax f'[pmax] == 0},
{f, f'}, {p, 0, pmax}, WorkingPrecision -> 30, MaxSteps -> 10^6,
Method -> {"Shooting", "StartingInitialConditions" -> {f[pmax] == pmax - 1754/100,
- 2 f[pmax] f'[pmax] + (1 + d/2) f[pmax] + (1 - d/2) pmax f'[pmax] == 0}}];

Plot[{a1[p], a2[p]}, {p, 0, 10.4}, AxesLabel -> {p, "f, f'"}, PlotRange -> {All, {-1, 7}}]

enter image description here


which agrees with the plot in my earlier answer for as far as the former is valid. However, the current answer is valid to p -> 10000. As an accuracy test (as suggested by Michael E2),



a1[0]
(* -1.43919293846595796615*10^-11 *)
σ = a2[0]
(* -0.22859820245788122180105821189 *)

The accuracy of σ, although good, agrees with Michael E2's value only to ten significant figures. However, that is beside the point. By integrating from large p to small p rather than the reverse, an excellent value for σ is not needed.


To plot the solution over the entire range, {p, 0, 10000}, it is convenient to do so in terms of a new dependent variable.


g[p] = f[p] - p
LogLogPlot[{-b1[p] + p, -b2[p] + 1, b2'[p]}, {p, .01, pmax},
AxesLabel -> {p, "-g, -g', g''"}]


enter image description here


where the blue and orange curves are -g[p] and -g'[p], and the green curve is g''[p]. As expected, f''[p] = g''[p] is very small asymptotically, and g[p] = f[p] - p is much less than p.


As an aside, the asymptotic ODE can be solved to obtain the asymptotic solution. First, substitute g for f,


Simplify[Unevaluated[D[f[p], p, p] - 2 f[p] D[f[p], p] + (1 + d/2) f[p] + 
(1 - d/2) p D[f[p], p] ] /. f[p] -> p + g[p]]
(* 1/2 (g[p] - 5 p g'[p] - 4 g[p] g'[p] + 2 g''[p] *)

drop the second derivative term, and solve using DSolve.


dsol = DSolveValue[g[p] - 5 p g'[p] - 4 g[p] g'[p] == 0, g[p], p] /. C[1] -> Log[c]

(* Root[-c p - c #1 + #1^5 &, 1] *)

The constant c can be determined by fitting the asymptotic solution to the full solution above.


FindRoot[(dsol /. p -> pmax) == a1[pmax] - pmax, {c, -167}][[1]]
(* c -> -166.625 *)

The same calculation for pmax = 1000 yields c -> -166.457, indicating that the asymptotic state has indeed been reached.


Comments

Popular posts from this blog

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...

dynamic - How can I make a clickable ArrayPlot that returns input?

I would like to create a dynamic ArrayPlot so that the rectangles, when clicked, provide the input. Can I use ArrayPlot for this? Or is there something else I should have to use? Answer ArrayPlot is much more than just a simple array like Grid : it represents a ranged 2D dataset, and its visualization can be finetuned by options like DataReversed and DataRange . These features make it quite complicated to reproduce the same layout and order with Grid . Here I offer AnnotatedArrayPlot which comes in handy when your dataset is more than just a flat 2D array. The dynamic interface allows highlighting individual cells and possibly interacting with them. AnnotatedArrayPlot works the same way as ArrayPlot and accepts the same options plus Enabled , HighlightCoordinates , HighlightStyle and HighlightElementFunction . data = {{Missing["HasSomeMoreData"], GrayLevel[ 1], {RGBColor[0, 1, 1], RGBColor[0, 0, 1], GrayLevel[1]}, RGBColor[0, 1, 0]}, {GrayLevel[0], GrayLevel...

list manipulation - Selecting multiple columns from a matrix?

Sample data: data = { {{2013, 1, 1}, 24.13, 167.67, 231.82}, {{2013, 1, 2}, 32.15, 170.92, 225.99}, {{2013, 1, 3}, 35.43, 172.68, 221.67}, {{2013, 1, 4}, 36.73, 173.05, 218.32}, {{2013, 1, 5}, 58.19, 165.96, 197.05}, {{2013, 1, 6}, 69.99, 163.50, 187.52}, {{2013, 1, 7}, 71.37, 154.21, 175.58}, {{2013, 1, 8}, 72.51, 149.66, 163.25}}; I want a DateListPlot with three graphs, so for a matrix formed by columns 1 and 2, one for columns 1 and 3, and 1 for columns 1 and 4. At the moment I'm using this code: data2 = Transpose[{data[[All, 1]], data[[All, 2]]}]; data3 = Transpose[{data[[All, 1]], data[[All, 3]]}]; data4 = Transpose[{data[[All, 1]], data[[All, 4]]}]; DateListPlot[{data2, data3, data4}, Joined -> True, Filling -> {3 -> {1}}] but I have a hunch that this can be done more efficiently. I don't like the Transpose s in particular. Any ideas? edit (for extra credit) What if I need to multiply the second column by 2, which in my solution is simp...