<?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>A differentiable ODE integrator for sensitivity analysis</title>
      <link>https://kitchingroup.cheme.cmu.edu/blog/2018/10/11/A-differentiable-ODE-integrator-for-sensitivity-analysis</link>
      <pubDate>Thu, 11 Oct 2018 12:13:01 EDT</pubDate>
      <category><![CDATA[autograd]]></category>
      <category><![CDATA[sensitivity]]></category>
      <category><![CDATA[ode]]></category>
      <guid isPermaLink="false">x1b-cquyAyl6Ic4uE4zs0jj8a6U=</guid>
      <description>A differentiable ODE integrator for sensitivity analysis</description>
      <content:encoded><![CDATA[


&lt;p&gt;
&lt;a href="http://kitchingroup.cheme.cmu.edu/blog/2018/10/10/Autograd-and-the-derivative-of-an-integral-function/"&gt;Last time&lt;/a&gt; I wrote about using automatic differentiation to find the derivative of an integral function. A related topic is finding derivatives of functions that are defined by differential equations. We typically use a numerical integrator to find solutions to these functions. Those leave us with numeric solutions which we then have to use to approximate derivatives. What if the integrator itself was differentiable? It is after all, just a program, and automatic differentiation should be able to tell us the derivatives of functions that use them. This is not a new idea, there is already a differentiable ODE solver in &lt;a href="https://www.tensorflow.org/versions/r1.1/api_docs/python/tf/contrib/integrate/odeint"&gt;Tensorflow&lt;/a&gt;. Here I will implement a simple Runge Kutta integrator and then show how we can use automatic differentiation to do &lt;i&gt;sensitivity analysis&lt;/i&gt; on the numeric solution.
&lt;/p&gt;

&lt;p&gt;
I previously used autograd for sensitivity analysis on &lt;i&gt;analytical&lt;/i&gt; solutions in this &lt;a href="http://kitchingroup.cheme.cmu.edu/blog/2017/11/15/Sensitivity-analysis-using-automatic-differentiation-in-Python/"&gt;post&lt;/a&gt;. Here I will compare those results to the results from sensitivity analysis on the &lt;i&gt;numerical solutions&lt;/i&gt;.
&lt;/p&gt;

&lt;p&gt;
First, we need an autograd compatible ODE integrator. Here is one implementation of a simple, fourth order Runge-Kutta integrator. Usually, I would use indexing to do this, but that was not compatible with autograd, so I just accumulate the solution. This is a limitation of autograd, and it is probably not an issue with Tensorflow, for example, or probably pytorch. Those are more sophisticated, and more difficult to use packages than autograd. Here I am just prototyping an idea, so we stick with autograd.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-ipython"&gt;&lt;span style="color: #0000FF;"&gt;import&lt;/span&gt; autograd.numpy &lt;span style="color: #0000FF;"&gt;as&lt;/span&gt; np
&lt;span style="color: #0000FF;"&gt;from&lt;/span&gt; autograd &lt;span style="color: #0000FF;"&gt;import&lt;/span&gt; grad
%matplotlib inline
&lt;span style="color: #0000FF;"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color: #0000FF;"&gt;as&lt;/span&gt; plt

&lt;span style="color: #0000FF;"&gt;def&lt;/span&gt; &lt;span style="color: #006699;"&gt;rk4&lt;/span&gt;(f, tspan, y0, N=50):
&lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #BA36A5;"&gt;x&lt;/span&gt;, &lt;span style="color: #BA36A5;"&gt;h&lt;/span&gt; = np.linspace(*tspan, N, retstep=&lt;span style="color: #D0372D;"&gt;True&lt;/span&gt;)
&lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #BA36A5;"&gt;y&lt;/span&gt; = []
&lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #BA36A5;"&gt;y&lt;/span&gt; = y + [y0]
&lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #0000FF;"&gt;for&lt;/span&gt; i &lt;span style="color: #0000FF;"&gt;in&lt;/span&gt; &lt;span style="color: #006FE0;"&gt;range&lt;/span&gt;(0, &lt;span style="color: #006FE0;"&gt;len&lt;/span&gt;(x) - 1):
&lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #BA36A5;"&gt;k1&lt;/span&gt; = h * f(x[i], y[i])
&lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #BA36A5;"&gt;k2&lt;/span&gt; = h * f(x[i] + h / 2, y[i] + k1 / 2)
&lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #BA36A5;"&gt;k3&lt;/span&gt; = h * f(x[i] + h / 2, y[i] + k2 / 2)
&lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #BA36A5;"&gt;k4&lt;/span&gt; = h * f(x[i + 1], y[i] + k3)
&lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #BA36A5;"&gt;y&lt;/span&gt; += [y[-1] + (k1 + (2 * k2) + (2 * k3) + k4) / 6]
&lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #0000FF;"&gt;return&lt;/span&gt; x, y
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Now, we just check that it works as expected:
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-ipython"&gt;&lt;span style="color: #BA36A5;"&gt;Ca0&lt;/span&gt; = 1.0
&lt;span style="color: #BA36A5;"&gt;k1&lt;/span&gt; = &lt;span style="color: #BA36A5;"&gt;k_1&lt;/span&gt; = 3.0

&lt;span style="color: #0000FF;"&gt;def&lt;/span&gt; &lt;span style="color: #006699;"&gt;dCdt&lt;/span&gt;(t, Ca):
&lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #0000FF;"&gt;return&lt;/span&gt; -k1 * Ca + k_1 * (Ca0 - Ca)

&lt;span style="color: #BA36A5;"&gt;t&lt;/span&gt;, &lt;span style="color: #BA36A5;"&gt;Ca&lt;/span&gt; = rk4(dCdt, (0, 0.5), Ca0)

&lt;span style="color: #0000FF;"&gt;def&lt;/span&gt; &lt;span style="color: #006699;"&gt;analytical_A&lt;/span&gt;(t, k1, k_1):
&lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #0000FF;"&gt;return&lt;/span&gt; Ca0 / (k1 + k_1) * (k1 * np.exp(-(k1 + k_1) * t) + k_1)

plt.plot(t, Ca, label=&lt;span style="color: #008000;"&gt;'RK4'&lt;/span&gt;)
plt.plot(t, analytical_A(t, k1, k_1), &lt;span style="color: #008000;"&gt;'r--'&lt;/span&gt;, label=&lt;span style="color: #008000;"&gt;'analytical'&lt;/span&gt;)
plt.xlabel(&lt;span style="color: #008000;"&gt;'t'&lt;/span&gt;)
plt.ylabel(&lt;span style="color: #008000;"&gt;'[A]'&lt;/span&gt;)
plt.xlim([0, 0.5])
plt.ylim([0.5, 1])
plt.legend()
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
&lt;img src="/media/6a1c5e4c896d855655b8da8b54214af3-90490Zdl.png"&gt; 
&lt;/p&gt;

&lt;p&gt;
That looks fine, we cannot visually distinguish the two solutions, and they both look like Figure 1 in this &lt;a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.428.6699&amp;amp;rep=rep1&amp;amp;type=pdf"&gt;paper&lt;/a&gt;. Note the analytical solution is not that complex, but it would not take much variation of the rate law to make this solution difficult to derive.
&lt;/p&gt;

&lt;p&gt;
Next, to do sensitivity analysis, we need to define a function for \(A\) that depends on the rate constants, so we can take a derivative of it with respect to the parameters we want the sensitivity from. We seek the derivatives: \(\frac{dC_A}{dk_1}\) and \(\frac{dC_A}{dk_{-1}}\). Here is a function that does that. It will return the value of [A] at \(t\) given an initial concentration and the rate constants.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-ipython"&gt;&lt;span style="color: #0000FF;"&gt;def&lt;/span&gt; &lt;span style="color: #006699;"&gt;A&lt;/span&gt;(Ca0, k1, k_1, t):
&lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #0000FF;"&gt;def&lt;/span&gt; &lt;span style="color: #006699;"&gt;dCdt&lt;/span&gt;(t, Ca):
&lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #0000FF;"&gt;return&lt;/span&gt; -k1 * Ca + k_1 * (Ca0 - Ca)
&lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #BA36A5;"&gt;t&lt;/span&gt;, &lt;span style="color: #BA36A5;"&gt;Ca_&lt;/span&gt; = rk4(dCdt, (0, t), Ca0)
&lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #0000FF;"&gt;return&lt;/span&gt; Ca_[-1]

&lt;span style="color: #8D8D84;"&gt;# &lt;/span&gt;&lt;span style="color: #8D8D84; font-style: italic;"&gt;Here are the two derivatives we seek.&lt;/span&gt;
&lt;span style="color: #BA36A5;"&gt;dCadk1&lt;/span&gt; = grad(A, 1)
&lt;span style="color: #BA36A5;"&gt;dCadk_1&lt;/span&gt; = grad(A, 2)
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
We also use autograd to get the derivatives from the analytical solution for comparison.
&lt;/p&gt;
&lt;div class="org-src-container"&gt;
&lt;pre class="src src-ipython"&gt;&lt;span style="color: #BA36A5;"&gt;dAdk1&lt;/span&gt; = grad(analytical_A, 1)
&lt;span style="color: #BA36A5;"&gt;dAdk_1&lt;/span&gt; = grad(analytical_A, 2)
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Now, we can plot the sensitivities over the time range and compare them. I use the list comprehensions here because the AD functions aren't vectorized.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-ipython"&gt;&lt;span style="color: #BA36A5;"&gt;tspan&lt;/span&gt; = np.linspace(0, 0.5)

&lt;span style="color: #8D8D84;"&gt;# &lt;/span&gt;&lt;span style="color: #8D8D84; font-style: italic;"&gt;From the numerical solutions&lt;/span&gt;
&lt;span style="color: #BA36A5;"&gt;k1_sensitivity&lt;/span&gt; = [dCadk1(1.0, 3.0, 3.0, t) &lt;span style="color: #0000FF;"&gt;for&lt;/span&gt; t &lt;span style="color: #0000FF;"&gt;in&lt;/span&gt; tspan]
&lt;span style="color: #BA36A5;"&gt;k_1_sensitivity&lt;/span&gt; = [dCadk_1(1.0, 3.0, 3.0, t) &lt;span style="color: #0000FF;"&gt;for&lt;/span&gt; t &lt;span style="color: #0000FF;"&gt;in&lt;/span&gt; tspan]

&lt;span style="color: #8D8D84;"&gt;# &lt;/span&gt;&lt;span style="color: #8D8D84; font-style: italic;"&gt;from the analytical solutions&lt;/span&gt;
&lt;span style="color: #BA36A5;"&gt;ak1_sensitivity&lt;/span&gt; = [dAdk1(t, 3.0, 3.0) &lt;span style="color: #0000FF;"&gt;for&lt;/span&gt; t &lt;span style="color: #0000FF;"&gt;in&lt;/span&gt; tspan]
&lt;span style="color: #BA36A5;"&gt;ak_1_sensitivity&lt;/span&gt; = [dAdk_1(t, 3.0, 3.0) &lt;span style="color: #0000FF;"&gt;for&lt;/span&gt; t &lt;span style="color: #0000FF;"&gt;in&lt;/span&gt; tspan]

plt.plot(tspan, np.&lt;span style="color: #006FE0;"&gt;abs&lt;/span&gt;(ak1_sensitivity), &lt;span style="color: #008000;"&gt;'b-'&lt;/span&gt;, label=&lt;span style="color: #008000;"&gt;'k1 analytical'&lt;/span&gt;)
plt.plot(tspan, np.&lt;span style="color: #006FE0;"&gt;abs&lt;/span&gt;(k1_sensitivity), &lt;span style="color: #008000;"&gt;'y--'&lt;/span&gt;, label=&lt;span style="color: #008000;"&gt;'k1 numerical'&lt;/span&gt;)

plt.plot(tspan, np.&lt;span style="color: #006FE0;"&gt;abs&lt;/span&gt;(ak_1_sensitivity), &lt;span style="color: #008000;"&gt;'r-'&lt;/span&gt;, label=&lt;span style="color: #008000;"&gt;'k_1 analytical'&lt;/span&gt;)
plt.plot(tspan, np.&lt;span style="color: #006FE0;"&gt;abs&lt;/span&gt;(k_1_sensitivity), &lt;span style="color: #008000;"&gt;'k--'&lt;/span&gt;, label=&lt;span style="color: #008000;"&gt;'k_1 numerical'&lt;/span&gt;)

plt.xlim([0, 0.5])
plt.ylim([0, 0.1])
plt.legend()
plt.xlabel(&lt;span style="color: #008000;"&gt;'t'&lt;/span&gt;)
plt.ylabel(&lt;span style="color: #008000;"&gt;'sensitivity'&lt;/span&gt;)
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
&lt;img src="/media/6a1c5e4c896d855655b8da8b54214af3-90490mnr.png"&gt; 
&lt;/p&gt;



&lt;p&gt;
The two approaches are indistinguishable on paper. I will note that it takes a lot longer to make the graph from the numerical solution than from the analytical solution because at each point you have to reintegrate the solution from the beginning, which is certainly not efficient. That is an implementation detail that could probably be solved, at the expense of making the code look different than the way I would normally think about the problem.
&lt;/p&gt;

&lt;p&gt;
On the other hand, it is remarkable we get derivatives from the numerical solution, &lt;i&gt;and they look really good&lt;/i&gt;! That means we could do sensitivity analysis on more complex reactions, and still have a reasonable way to get sensitivity. The work here is a long way from that. My simple Runge-Kutta integrator isn't directly useful for systems of ODEs, it wouldn't work well on stiff problems, the step size isn't adaptive, etc. The Tensorflow implementation might be more suitable for this though, and maybe this post is motivation to learn how to use it!
&lt;/p&gt;
&lt;p&gt;Copyright (C) 2018 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/2018/10/11/A-differentiable-ODE-integrator-for-sensitivity-analysis.org"&gt;org-mode source&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Org-mode version = 9.1.13&lt;/p&gt;]]></content:encoded>
    </item>
    <item>
      <title>Sensitivity analysis using automatic differentiation in Python</title>
      <link>https://kitchingroup.cheme.cmu.edu/blog/2017/11/15/Sensitivity-analysis-using-automatic-differentiation-in-Python</link>
      <pubDate>Wed, 15 Nov 2017 08:34:29 EST</pubDate>
      <category><![CDATA[autograd]]></category>
      <category><![CDATA[sensitivity]]></category>
      <category><![CDATA[python]]></category>
      <guid isPermaLink="false">9AFJlEwYc2VNT6Wwisg6LlYD3KY=</guid>
      <description>Sensitivity analysis using automatic differentiation in Python</description>
      <content:encoded><![CDATA[


&lt;p&gt;
This &lt;a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.428.6699&amp;amp;rep=rep1&amp;amp;type=pdf"&gt;paper&lt;/a&gt; describes how sensitivity analysis requires access to the derivatives of a function. Say, for example we have a function describing the time evolution of the concentration of species A:
&lt;/p&gt;

&lt;p&gt;
\([A] = \frac{[A]_0}{k_1 + k_{-1}} (k_1 e^{(-(k_1 _ k_{-1})t)} + k_{-1})\)
&lt;/p&gt;

&lt;p&gt;
The local sensitivity of the concentration of A to the parameters \(k1\) and \(k_1\) are defined as \(\frac{\partial A}{\partial k1}\) and \(\frac{\partial A}{\partial k_1}\). Our goal is to plot the sensitivity as a function of time. We could derive those derivatives, but we will use auto-differentiation instead through the autograd package. Here we import numpy from the autograd package and plot the function above.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-ipython" id="org5d5b53b"&gt;&lt;span style="color: #0000FF;"&gt;import&lt;/span&gt; autograd.numpy &lt;span style="color: #0000FF;"&gt;as&lt;/span&gt; np

&lt;span style="color: #BA36A5;"&gt;A0&lt;/span&gt; = 1.0

&lt;span style="color: #0000FF;"&gt;def&lt;/span&gt; &lt;span style="color: #006699;"&gt;A&lt;/span&gt;(t, k1, k_1):
&lt;span style="color: #9B9B9B; background-color: #EDEDED;"&gt; &lt;/span&gt;   &lt;span style="color: #0000FF;"&gt;return&lt;/span&gt; A0 / (k1 + k_1) * (k1 * np.exp(-(k1 + k_1) * t) + k_1)

%matplotlib inline
&lt;span style="color: #0000FF;"&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style="color: #0000FF;"&gt;as&lt;/span&gt; plt

&lt;span style="color: #BA36A5;"&gt;t&lt;/span&gt; = np.linspace(0, 0.5)

&lt;span style="color: #BA36A5;"&gt;k1&lt;/span&gt; = 3.0
&lt;span style="color: #BA36A5;"&gt;k_1&lt;/span&gt; = 3.0
plt.plot(t, A(t, k1, k_1))
plt.xlim([0, 0.5])
plt.ylim([0, 1])
plt.xlabel(&lt;span style="color: #008000;"&gt;'t'&lt;/span&gt;)
plt.ylabel(&lt;span style="color: #008000;"&gt;'A'&lt;/span&gt;)
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
&lt;img src="/media/ob-ipython-09dd39779fdcdb6e3f00397800ec05e6.png"&gt; 
&lt;/p&gt;

&lt;p&gt;
The figure above reproduces Fig. 1 from the paper referenced above.  Next, we use autograd to get the derivatives. This is subtly different than our previous &lt;a href="http://kitchingroup.cheme.cmu.edu/blog/2017/11/14/Forces-by-automatic-differentiation-in-molecular-simulation/"&gt;post&lt;/a&gt;. First, we need the derivative of the function with respect to the second and third arguments; the default is the first argument. Second, we want to evaluate this derivative at each time value. We use the jacobian function in autograd to get these. This is different than grad, which will sum up the derivatives at each time. That might be useful for regression, but not for sensitivity analysis. Finally, to reproduce Figure 2a, we plot the absolute value of the sensitivities.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-ipython" id="org194abad"&gt;&lt;span style="color: #0000FF;"&gt;from&lt;/span&gt; autograd &lt;span style="color: #0000FF;"&gt;import&lt;/span&gt; jacobian

&lt;span style="color: #BA36A5;"&gt;dAdk1&lt;/span&gt; = jacobian(A, 1)
&lt;span style="color: #BA36A5;"&gt;dAdk_1&lt;/span&gt; = jacobian(A, 2)

plt.plot(t, np.&lt;span style="color: #006FE0;"&gt;abs&lt;/span&gt;(dAdk1(t, k1, k_1)))
plt.plot(t, np.&lt;span style="color: #006FE0;"&gt;abs&lt;/span&gt;(dAdk_1(t, k1, k_1)))
plt.xlim([0, 0.5])
plt.ylim([0, 0.1])
plt.xlabel(&lt;span style="color: #008000;"&gt;'t'&lt;/span&gt;)
plt.legend([&lt;span style="color: #008000;"&gt;'$S_{k1}$'&lt;/span&gt;, &lt;span style="color: #008000;"&gt;'$S_{k\_1}$'&lt;/span&gt;])
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
&lt;img src="/media/ob-ipython-f3534f038e5e3a7c77041501838e9fdb.png"&gt; 
&lt;/p&gt;

&lt;p&gt;
That looks like the figure in the paper. To summarize the main takeaway, autograd enabled us to readily compute derivatives without having to derive them manually. There was a little subtlety in choosing jacobian over grad or elementwise_grad but once you know what these do, it seems reasonable. It is important to import the wrapped numpy first, to enable autograd to do its work. All the functions here are pretty standard, so everything worked out of the box. We should probably be using autograd, or something like it for more things in science!
&lt;/p&gt;
&lt;p&gt;Copyright (C) 2017 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/2017/11/15/Sensitivity-analysis-using-automatic-differentiation-in-Python.org"&gt;org-mode source&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Org-mode version = 9.1.2&lt;/p&gt;]]></content:encoded>
    </item>
  </channel>
</rss>
