<?xml version="1.0" encoding="UTF-8"?>

<rss version="2.0"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:wfw="http://wellformedweb.org/CommentAPI/"
     >
  <channel>
    <atom:link href="http://kitchingroup.cheme.cmu.edu/blog/feed/index.xml" rel="self" type="application/rss+xml" />
    <title>The Kitchin Research Group</title>
    <link>https://kitchingroup.cheme.cmu.edu/blog</link>
    <description>Chemical Engineering at Carnegie Mellon University</description>
    <pubDate>Sat, 01 Nov 2025 13:47:46 GMT</pubDate>
    <generator>Blogofile</generator>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    
    <item>
      <title>Transient heat conduction - partial differential equations</title>
      <link>https://kitchingroup.cheme.cmu.edu/blog/2013/03/07/Transient-heat-conduction-partial-differential-equations</link>
      <pubDate>Thu, 07 Mar 2013 15:54:08 EST</pubDate>
      <category><![CDATA[pde]]></category>
      <guid isPermaLink="false">vYwQTXiPOjKla95AZ51ynjv57Cg=</guid>
      <description>Transient heat conduction - partial differential equations</description>
      <content:encoded><![CDATA[


&lt;p&gt;
&lt;a href="http://matlab.cheme.cmu.edu/2011/08/21/transient-heat-conduction-partial-differential-equations/" &gt;Matlab post&lt;/a&gt;
adapated from &lt;a href="http://msemac.redwoods.edu/~darnold/math55/DEproj/sp02/AbeRichards/slideshowdefinal.pdf" &gt;http://msemac.redwoods.edu/~darnold/math55/DEproj/sp02/AbeRichards/slideshowdefinal.pdf&lt;/a&gt;

&lt;/p&gt;

&lt;p&gt;
We solved a steady state BVP modeling heat conduction. Today we examine the transient behavior of a rod at constant T put between two heat reservoirs at different temperatures, again T1 = 100, and T2 = 200. The rod will start at 150. Over time, we should expect a solution that approaches the steady state solution: a linear temperature profile from one side of the rod to the other.
&lt;/p&gt;

&lt;p&gt;
\(\frac{\partial u}{\partial t} = k \frac{\partial^2 u}{\partial x^2}\)
&lt;/p&gt;

&lt;p&gt;
at \(t=0\), in this example we have \(u_0(x) = 150\) as an initial condition. with boundary conditions \(u(0,t)=100\) and \(u(L,t)=200\).
&lt;/p&gt;

&lt;p&gt;
In Matlab there is the pdepe command. There is not yet a PDE solver in scipy. Instead, we will utilze the method of lines to solve this problem. We discretize the rod into segments, and approximate the second derivative in the spatial dimension as \(\frac{\partial^2 u}{\partial x^2} = (u(x + h) - 2 u(x) + u(x-h))/ h^2\) at each node. This leads to a set of coupled ordinary differential equations that is easy to solve.
&lt;/p&gt;

&lt;p&gt;
Let us say the rod has a length of 1, \(k=0.02\), and solve for the time-dependent temperature profiles.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np
&lt;span style="color: #8b0000;"&gt;from&lt;/span&gt; scipy.integrate &lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; odeint
&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; plt

N = 100  &lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;number of points to discretize&lt;/span&gt;
L = 1.0
X = np.linspace(0, L, N) &lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;position along the rod&lt;/span&gt;
h = L / (N - 1)

k = 0.02

&lt;span style="color: #8b0000;"&gt;def&lt;/span&gt; &lt;span style="color: #8b2323;"&gt;odefunc&lt;/span&gt;(u, t):
    dudt = np.zeros(X.shape)

    dudt[0] = 0 &lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;constant at boundary condition&lt;/span&gt;
    dudt[-1] = 0

    &lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;now for the internal nodes&lt;/span&gt;
    &lt;span style="color: #8b0000;"&gt;for&lt;/span&gt; i &lt;span style="color: #8b0000;"&gt;in&lt;/span&gt; &lt;span style="color: #8b0000;"&gt;range&lt;/span&gt;(1, N-1):
        dudt[i] = k * (u[i + 1] - 2*u[i] + u[i - 1]) / h**2

    &lt;span style="color: #8b0000;"&gt;return&lt;/span&gt; dudt

init = 150.0 * np.ones(X.shape) &lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;initial temperature&lt;/span&gt;
init[0] = 100.0  &lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;one boundary condition&lt;/span&gt;
init[-1] = 200.0 &lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;the other boundary condition&lt;/span&gt;

tspan = np.linspace(0.0, 5.0, 100)
sol = odeint(odefunc, init, tspan)


&lt;span style="color: #8b0000;"&gt;for&lt;/span&gt; i &lt;span style="color: #8b0000;"&gt;in&lt;/span&gt; &lt;span style="color: #8b0000;"&gt;range&lt;/span&gt;(0, &lt;span style="color: #8b0000;"&gt;len&lt;/span&gt;(tspan), 5):
    plt.plot(X, sol[i], label=&lt;span style="color: #228b22;"&gt;'t={0:1.2f}'&lt;/span&gt;.format(tspan[i]))

&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;put legend outside the figure&lt;/span&gt;
plt.legend(loc=&lt;span style="color: #228b22;"&gt;'center left'&lt;/span&gt;, bbox_to_anchor=(1, 0.5))
plt.xlabel(&lt;span style="color: #228b22;"&gt;'X position'&lt;/span&gt;)
plt.ylabel(&lt;span style="color: #228b22;"&gt;'Temperature'&lt;/span&gt;)

&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;adjust figure edges so the legend is in the figure&lt;/span&gt;
plt.subplots_adjust(top=0.89, right=0.77)
plt.savefig(&lt;span style="color: #228b22;"&gt;'images/pde-transient-heat-1.png'&lt;/span&gt;)


&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;Make a 3d figure&lt;/span&gt;
&lt;span style="color: #8b0000;"&gt;from&lt;/span&gt; mpl_toolkits.mplot3d &lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection=&lt;span style="color: #228b22;"&gt;'3d'&lt;/span&gt;)

SX, ST = np.meshgrid(X, tspan)
ax.plot_surface(SX, ST, sol, cmap=&lt;span style="color: #228b22;"&gt;'jet'&lt;/span&gt;)
ax.set_xlabel(&lt;span style="color: #228b22;"&gt;'X'&lt;/span&gt;)
ax.set_ylabel(&lt;span style="color: #228b22;"&gt;'time'&lt;/span&gt;)
ax.set_zlabel(&lt;span style="color: #228b22;"&gt;'T'&lt;/span&gt;)
ax.view_init(elev=15, azim=-124) &lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;adjust view so it is easy to see&lt;/span&gt;
plt.savefig(&lt;span style="color: #228b22;"&gt;'images/pde-transient-heat-3d.png'&lt;/span&gt;)

&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;animated solution. We will use imagemagick for this&lt;/span&gt;

&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;we save each frame as an image, and use the imagemagick convert command to &lt;/span&gt;
&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;make an animated gif&lt;/span&gt;
&lt;span style="color: #8b0000;"&gt;for&lt;/span&gt; i &lt;span style="color: #8b0000;"&gt;in&lt;/span&gt; &lt;span style="color: #8b0000;"&gt;range&lt;/span&gt;(len(tspan)):
    plt.clf()
    plt.plot(X, sol[i])
    plt.xlabel(&lt;span style="color: #228b22;"&gt;'X'&lt;/span&gt;)
    plt.ylabel(&lt;span style="color: #228b22;"&gt;'T(X)'&lt;/span&gt;)
    plt.title(&lt;span style="color: #228b22;"&gt;'t = {0}'&lt;/span&gt;.format(tspan[i]))
    plt.savefig(&lt;span style="color: #228b22;"&gt;'___t{0:03d}.png'&lt;/span&gt;.format(i))

&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; commands
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; commands.getoutput(&lt;span style="color: #228b22;"&gt;'convert -quality 100 ___t*.png images/transient_heat.gif'&lt;/span&gt;)
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; commands.getoutput(&lt;span style="color: #228b22;"&gt;'rm ___t*.png'&lt;/span&gt;) &lt;span style="color: #ff0000; font-weight: bold;"&gt;#&lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;remove temp files&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
&lt;/pre&gt;

&lt;p&gt;
This version of the graphical solution is not that easy to read, although with some study you can see the solution evolves from the initial condition which is flat, to the steady state solution which is a linear temperature ramp.
&lt;p&gt;&lt;img src="/img/./images/pde-transient-heat-1.png"&gt;&lt;p&gt;
&lt;/p&gt;

&lt;p&gt;
The 3d version may be easier to interpret. The temperature profile starts out flat, and gradually changes to the linear ramp.
&lt;p&gt;&lt;img src="/img/./images/pde-transient-heat-3d.png"&gt;&lt;p&gt;
&lt;/p&gt;

&lt;p&gt;
Finally, the animated solution.
&lt;/p&gt;

&lt;p&gt;&lt;img src="/img/./images/transient_heat.gif"&gt;&lt;p&gt;
&lt;p&gt;Copyright (C) 2013 by John Kitchin. See the &lt;a href="/copying.html"&gt;License&lt;/a&gt; for information about copying.&lt;p&gt;&lt;p&gt;&lt;a href="/org/2013/03/07/Transient-heat-conduction---partial-differential-equations.org"&gt;org-mode source&lt;/a&gt;&lt;p&gt;]]></content:encoded>
    </item>
    <item>
      <title>Boundary value problem in heat conduction</title>
      <link>https://kitchingroup.cheme.cmu.edu/blog/2013/03/06/Boundary-value-problem-in-heat-conduction</link>
      <pubDate>Wed, 06 Mar 2013 19:35:39 EST</pubDate>
      <category><![CDATA[bvp]]></category>
      <guid isPermaLink="false">3aI5z4CyumczzU5swqki2i6aDhE=</guid>
      <description>Boundary value problem in heat conduction</description>
      <content:encoded><![CDATA[


&lt;p&gt;
&lt;a href="http://matlab.cheme.cmu.edu/2011/08/11/boundary-value-problem-in-heat-conduction/" &gt;Matlab post&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
For steady state heat conduction the temperature distribution in one-dimension is governed by the Laplace equation:
&lt;/p&gt;

&lt;p&gt;
$$ \nabla^2 T = 0$$
&lt;/p&gt;

&lt;p&gt;
with boundary conditions that at \(T(x=a) = T_A\) and \(T(x=L) = T_B\).
&lt;/p&gt;

&lt;p&gt;
The analytical solution is not difficult here: \(T = T_A-\frac{T_A-T_B}{L}x\), but we will solve this by finite differences.
&lt;/p&gt;

&lt;p&gt;
For this problem, lets consider a slab that is defined by x=0 to x=L, with \(T(x=0) = 100\), and \(T(x=L) = 200\). We want to find the function T(x) inside the slab.
&lt;/p&gt;

&lt;p&gt;
We approximate the second derivative by finite differences as
&lt;/p&gt;

&lt;p&gt;
\( f''(x) \approx \frac{f(x-h) - 2 f(x) + f(x+h)}{h^2} \)
&lt;/p&gt;

&lt;p&gt;
Since the second derivative in this case is equal to zero, we have at each discretized node \(0 = T_{i-1} - 2 T_i + T_{i+1}\). We know the values of \(T_{x=0} = \alpha\) and \(T_{x=L} = \beta\).
&lt;/p&gt;

&lt;p&gt;
\[A = \left [ \begin{array}{ccccc} %
 -2         &amp; 1 &amp; 0                    &amp; 0 &amp; 0 \\
1           &amp; -2&amp; 1 &amp; 0 &amp; 0 \\
0                    &amp; \ddots               &amp; \ddots               &amp; \ddots &amp; 0 \\
0                    &amp; 0                    &amp; 1 &amp; -2 &amp; 1 \\
0                    &amp; 0                    &amp; 0  &amp; 1  &amp; -2  \end{array} \right ] \]
&lt;/p&gt;

&lt;p&gt;
\[ x = \left [ \begin{array}{c} T_1 \\ \vdots \\ T_N \end{array} \right ] \]
&lt;/p&gt;

&lt;p&gt;
\[ b = \left [ \begin{array}{c} -T(x=0) \\
0 \\
\vdots \\
0 \\
-T(x=L) \end{array} \right] \]
&lt;/p&gt;

&lt;p&gt;
These are linear equations in the unknowns \(x\) that we can easily solve. Here, we evaluate the solution.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np

&lt;span style="color: #ff0000; font-weight: bold;"&gt;#&lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;we use the notation T(x1) = alpha and T(x2) = beta&lt;/span&gt;
x1 = 0; alpha = 100
x2 = 5; beta = 200

npoints = 100

&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;preallocate and shape the b vector and A-matrix&lt;/span&gt;
b = np.zeros((npoints, 1));
b[0] = -alpha
b[-1] = -beta

A = np.zeros((npoints, npoints));

&lt;span style="color: #ff0000; font-weight: bold;"&gt;#&lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;now we populate the A-matrix and b vector elements&lt;/span&gt;
&lt;span style="color: #8b0000;"&gt;for&lt;/span&gt; i &lt;span style="color: #8b0000;"&gt;in&lt;/span&gt; &lt;span style="color: #8b0000;"&gt;range&lt;/span&gt;(npoints ):
    &lt;span style="color: #8b0000;"&gt;for&lt;/span&gt; j &lt;span style="color: #8b0000;"&gt;in&lt;/span&gt; &lt;span style="color: #8b0000;"&gt;range&lt;/span&gt;(npoints):
        &lt;span style="color: #8b0000;"&gt;if&lt;/span&gt; j == i: &lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;the diagonal&lt;/span&gt;
            A[i,j] = -2
        &lt;span style="color: #8b0000;"&gt;elif&lt;/span&gt; j == i - 1: &lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;left of the diagonal&lt;/span&gt;
            A[i,j] = 1
        &lt;span style="color: #8b0000;"&gt;elif&lt;/span&gt; j == i + 1: &lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;right of the diagonal&lt;/span&gt;
            A[i,j] = 1
 
&lt;span style="color: #ff0000; font-weight: bold;"&gt;# &lt;/span&gt;&lt;span style="color: #ff0000; font-weight: bold;"&gt;solve the equations A*y = b for Y&lt;/span&gt;
Y = np.linalg.solve(A,b)

x = np.linspace(x1, x2, npoints + 2)
y = np.hstack([alpha, Y[:,0], beta])

&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; plt

plt.plot(x, y)

plt.plot(x, alpha + (beta - alpha)/(x2 - x1) * x, &lt;span style="color: #228b22;"&gt;'r--'&lt;/span&gt;)

plt.xlabel(&lt;span style="color: #228b22;"&gt;'X'&lt;/span&gt;)
plt.ylabel(&lt;span style="color: #228b22;"&gt;'T(X)'&lt;/span&gt;)
plt.legend((&lt;span style="color: #228b22;"&gt;'finite difference'&lt;/span&gt;, &lt;span style="color: #228b22;"&gt;'analytical soln'&lt;/span&gt;), loc=&lt;span style="color: #228b22;"&gt;'best'&lt;/span&gt;)
plt.savefig(&lt;span style="color: #228b22;"&gt;'images/bvp-heat-conduction-1d.png'&lt;/span&gt;)
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;img src="/img/./images/bvp-heat-conduction-1d.png"&gt;&lt;p&gt;
&lt;p&gt;Copyright (C) 2013 by John Kitchin. See the &lt;a href="/copying.html"&gt;License&lt;/a&gt; for information about copying.&lt;p&gt;&lt;p&gt;&lt;a href="/org/2013/03/06/Boundary-value-problem-in-heat-conduction.org"&gt;org-mode source&lt;/a&gt;&lt;p&gt;]]></content:encoded>
    </item>
    <item>
      <title>Finding the nth root of a periodic function</title>
      <link>https://kitchingroup.cheme.cmu.edu/blog/2013/03/05/Finding-the-nth-root-of-a-periodic-function</link>
      <pubDate>Tue, 05 Mar 2013 14:06:04 EST</pubDate>
      <category><![CDATA[nonlinear algebra]]></category>
      <guid isPermaLink="false">TjQQYRtTLiik-QWmqbwfFnxpj5M=</guid>
      <description>Finding the nth root of a periodic function</description>
      <content:encoded><![CDATA[



&lt;p&gt;
There is a heat transfer problem where one needs to find the n^th root of the following equation: \(x J_1(x) - Bi J_0(x)=0\) where \(J_0\) and \(J_1\) are the Bessel functions of zero and first order, and \(Bi\) is the Biot number. We examine an approach to finding these roots. 
&lt;/p&gt;

&lt;p&gt;
First,  we plot the function.
&lt;/p&gt;
&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;from&lt;/span&gt; scipy.special &lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; jn, jn_zeros
&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; plt
&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np

Bi = 1

&lt;span style="color: #8b0000;"&gt;def&lt;/span&gt; &lt;span style="color: #8b2323;"&gt;f&lt;/span&gt;(x):
    &lt;span style="color: #8b0000;"&gt;return&lt;/span&gt; x * jn(1, x) - Bi * jn(0, x)

X = np.linspace(0, 30, 200)
plt.plot(X, f(X))
plt.savefig(&lt;span style="color: #228b22;"&gt;'images/heat-transfer-roots-1.png'&lt;/span&gt;)
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;img src="/img/./images/heat-transfer-roots-1.png"&gt;&lt;p&gt;

&lt;p&gt;
You can see there are many roots to this equation, and we want to be sure we get the n^{th} root. This function is pretty well behaved, so if you make a good guess about the solution you will get an answer, but if you make a bad guess, you may get the wrong root. We examine next a way to do it without guessing the solution. What we want is the solution to \(f(x) = 0\), but we want all the solutions in a given interval. We derive a new equation, \(f'(x) = 0\), with initial condition \(f(0) = f0\), and integrate the ODE with an event function that identifies all zeros of \(f\) for us. The derivative of our function is \(df/dx = d/dx(x J_1(x)) - Bi J'_0(x)\). It is known (&lt;a href="http://www.markrobrien.com/besselfunct.pdf" &gt;http://www.markrobrien.com/besselfunct.pdf&lt;/a&gt;) that \(d/dx(x J_1(x)) = x J_0(x)\), and \(J'_0(x) = -J_1(x)\). All we have to do now is set up the problem and run it.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;

&lt;pre class="src src-python"&gt;&lt;span style="color: #8b0000;"&gt;from&lt;/span&gt; pycse &lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; *  &lt;span style="color: #ff0000; font-weight: bold;"&gt;# contains the ode integrator with events&lt;/span&gt;

&lt;span style="color: #8b0000;"&gt;from&lt;/span&gt; scipy.special &lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; jn, jn_zeros
&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; plt
&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np

Bi = 1

&lt;span style="color: #8b0000;"&gt;def&lt;/span&gt; &lt;span style="color: #8b2323;"&gt;f&lt;/span&gt;(x):
    &lt;span style="color: #228b22;"&gt;"function we want roots for"&lt;/span&gt;
    &lt;span style="color: #8b0000;"&gt;return&lt;/span&gt; x * jn(1, x) - Bi * jn(0, x)

&lt;span style="color: #8b0000;"&gt;def&lt;/span&gt; &lt;span style="color: #8b2323;"&gt;fprime&lt;/span&gt;(f, x):
    &lt;span style="color: #228b22;"&gt;"df/dx"&lt;/span&gt;
    &lt;span style="color: #8b0000;"&gt;return&lt;/span&gt; x * jn(0, x) - Bi * (-jn(1, x))

&lt;span style="color: #8b0000;"&gt;def&lt;/span&gt; &lt;span style="color: #8b2323;"&gt;e1&lt;/span&gt;(f, x):
    &lt;span style="color: #228b22;"&gt;"event function to find zeros of f"&lt;/span&gt;
    isterminal = &lt;span style="color: #8b0000;"&gt;False&lt;/span&gt;
    value = f
    direction = 0
    &lt;span style="color: #8b0000;"&gt;return&lt;/span&gt; value, isterminal, direction

f0 = f(0)
xspan = np.linspace(0, 30, 200)

x, fsol, XE, FE, IE = odelay(fprime, f0, xspan, events=[e1])

plt.plot(x, fsol, &lt;span style="color: #228b22;"&gt;'.-'&lt;/span&gt;, label=&lt;span style="color: #228b22;"&gt;'Numerical solution'&lt;/span&gt;)
plt.plot(xspan, f(xspan), &lt;span style="color: #228b22;"&gt;'--'&lt;/span&gt;, label=&lt;span style="color: #228b22;"&gt;'Analytical function'&lt;/span&gt;)
plt.plot(XE, FE, &lt;span style="color: #228b22;"&gt;'ro'&lt;/span&gt;, label=&lt;span style="color: #228b22;"&gt;'roots'&lt;/span&gt;)
plt.legend(loc=&lt;span style="color: #228b22;"&gt;'best'&lt;/span&gt;)
plt.savefig(&lt;span style="color: #228b22;"&gt;'images/heat-transfer-roots-2.png'&lt;/span&gt;)

&lt;span style="color: #8b0000;"&gt;for&lt;/span&gt; i, root &lt;span style="color: #8b0000;"&gt;in&lt;/span&gt; &lt;span style="color: #8b0000;"&gt;enumerate&lt;/span&gt;(XE):
    &lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; &lt;span style="color: #228b22;"&gt;'root {0} is at {1}'&lt;/span&gt;.format(i, root)

plt.show()
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
root 0 is at 1.25578377377
root 1 is at 4.07947743741
root 2 is at 7.15579904465
root 3 is at 10.2709851256
root 4 is at 13.3983973869
root 5 is at 16.5311587137
root 6 is at 19.6667276775
root 7 is at 22.8039503455
root 8 is at 25.9422288192
root 9 is at 29.081221492
&lt;/pre&gt;

&lt;p&gt;&lt;img src="/img/./images/heat-transfer-roots-2.png"&gt;&lt;p&gt;

&lt;p&gt;
You can work this out once, and then you have all the roots in the interval and you can select the one you want.
&lt;/p&gt;
&lt;p&gt;Copyright (C) 2013 by John Kitchin. See the &lt;a href="/copying.html"&gt;License&lt;/a&gt; for information about copying.&lt;p&gt;&lt;p&gt;&lt;a href="/org/2013/03/05/Finding-the-nth-root-of-a-periodic-function.org"&gt;org-mode source&lt;/a&gt;&lt;p&gt;]]></content:encoded>
    </item>
  </channel>
</rss>
