<?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>Fitting a numerical ODE solution to data</title>
      <link>https://kitchingroup.cheme.cmu.edu/blog/2013/02/18/Fitting-a-numerical-ODE-solution-to-data</link>
      <pubDate>Mon, 18 Feb 2013 09:00:00 EST</pubDate>
      <category><![CDATA[data analysis]]></category>
      <category><![CDATA[nonlinear regression]]></category>
      <guid isPermaLink="false">I6eF5y5GOBd_cm3KASyNO4zNYAI=</guid>
      <description>Fitting a numerical ODE solution to data</description>
      <content:encoded><![CDATA[


&lt;p&gt;
&lt;a href="http://matlab.cheme.cmu.edu/2011/09/29/fitting-a-numerical-ode-solution-to-data/" &gt;Matlab post&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Suppose we know the concentration of A follows this differential equation: \(\frac{dC_A}{dt} = -k C_A\), and we have data we want to fit to it. Here is an example of doing that.
&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.optimize &lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; curve_fit
&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: #ff0000; font-weight: bold;"&gt;# given data we want to fit&lt;/span&gt;
tspan = [0, 0.1, 0.2, 0.4, 0.8, 1]
Ca_data = [2.0081,  1.5512,  1.1903,  0.7160,  0.2562,  0.1495]

&lt;span style="color: #8b0000;"&gt;def&lt;/span&gt; &lt;span style="color: #8b2323;"&gt;fitfunc&lt;/span&gt;(t, k):
    &lt;span style="color: #228b22;"&gt;'Function that returns Ca computed from an ODE for a k'&lt;/span&gt;
    &lt;span style="color: #8b0000;"&gt;def&lt;/span&gt; &lt;span style="color: #8b2323;"&gt;myode&lt;/span&gt;(Ca, t):
        &lt;span style="color: #8b0000;"&gt;return&lt;/span&gt; -k * Ca

    Ca0 = Ca_data[0]
    Casol = odeint(myode, Ca0, t)
    &lt;span style="color: #8b0000;"&gt;return&lt;/span&gt; Casol[:,0]

k_fit, kcov = curve_fit(fitfunc, tspan, Ca_data, p0=1.3)
&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; k_fit

tfit = np.linspace(0,1);
fit = fitfunc(tfit, k_fit)

&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(tspan, Ca_data, &lt;span style="color: #228b22;"&gt;'ro'&lt;/span&gt;, label=&lt;span style="color: #228b22;"&gt;'data'&lt;/span&gt;)
plt.plot(tfit, fit, &lt;span style="color: #228b22;"&gt;'b-'&lt;/span&gt;, label=&lt;span style="color: #228b22;"&gt;'fit'&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/ode-fit.png'&lt;/span&gt;)
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
[ 2.58893455]
&lt;/pre&gt;

&lt;p&gt;&lt;img src="/img/./images/ode-fit.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/02/18/Fitting-a-numerical-ODE-solution-to-data.org"&gt;org-mode source&lt;/a&gt;&lt;p&gt;]]></content:encoded>
    </item>
    <item>
      <title>Nonlinear curve fitting</title>
      <link>https://kitchingroup.cheme.cmu.edu/blog/2013/02/18/Nonlinear-curve-fitting</link>
      <pubDate>Mon, 18 Feb 2013 09:00:00 EST</pubDate>
      <category><![CDATA[data analysis]]></category>
      <category><![CDATA[nonlinear regression]]></category>
      <guid isPermaLink="false">GDPSjpBOJL3Ri1AIDXT92Ywmu0E=</guid>
      <description>Nonlinear curve fitting</description>
      <content:encoded><![CDATA[


&lt;p&gt;
Here is a typical nonlinear function fit to data. you need to provide an initial guess. In this example we fit the Birch-Murnaghan equation of state to energy vs. volume data from density functional theory calculations.
&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.optimize &lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; leastsq
&lt;span style="color: #8b0000;"&gt;import&lt;/span&gt; numpy &lt;span style="color: #8b0000;"&gt;as&lt;/span&gt; np

vols = np.array([13.71, 14.82, 16.0, 17.23, 18.52])

energies = np.array([-56.29, -56.41, -56.46, -56.463, -56.41])

&lt;span style="color: #8b0000;"&gt;def&lt;/span&gt; &lt;span style="color: #8b2323;"&gt;Murnaghan&lt;/span&gt;(parameters, vol):
    &lt;span style="color: #228b22;"&gt;'From Phys. Rev. B 28, 5480 (1983)'&lt;/span&gt;
    E0, B0, BP, V0 = parameters

    E = E0 + B0 * vol / BP * (((V0 / vol)**BP) / (BP - 1) + 1) - V0 * B0 / (BP - 1.0)

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

&lt;span style="color: #8b0000;"&gt;def&lt;/span&gt; &lt;span style="color: #8b2323;"&gt;objective&lt;/span&gt;(pars, y, x):
    &lt;span style="color: #ff0000; font-weight: bold;"&gt;#we will minimize this function&lt;/span&gt;
    err =  y - Murnaghan(pars, x)
    &lt;span style="color: #8b0000;"&gt;return&lt;/span&gt; err

x0 = [ -56.0, 0.54, 2.0, 16.5] &lt;span style="color: #ff0000; font-weight: bold;"&gt;#initial guess of parameters&lt;/span&gt;

plsq = leastsq(objective, x0, args=(energies, vols))

&lt;span style="color: #8b0000;"&gt;print&lt;/span&gt; &lt;span style="color: #228b22;"&gt;'Fitted parameters = {0}'&lt;/span&gt;.format(plsq[0])

&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(vols,energies, &lt;span style="color: #228b22;"&gt;'ro'&lt;/span&gt;)

&lt;span style="color: #ff0000; font-weight: bold;"&gt;#plot the fitted curve on top&lt;/span&gt;
x = np.linspace(&lt;span style="color: #8b0000;"&gt;min&lt;/span&gt;(vols), &lt;span style="color: #8b0000;"&gt;max&lt;/span&gt;(vols), 50)
y = Murnaghan(plsq[0], x)
plt.plot(x, y, &lt;span style="color: #228b22;"&gt;'k-'&lt;/span&gt;)
plt.xlabel(&lt;span style="color: #228b22;"&gt;'Volume'&lt;/span&gt;)
plt.ylabel(&lt;span style="color: #228b22;"&gt;'Energy'&lt;/span&gt;)
plt.savefig(&lt;span style="color: #228b22;"&gt;'images/nonlinear-curve-fitting.png'&lt;/span&gt;)
&lt;/pre&gt;
&lt;/div&gt;

&lt;pre class="example"&gt;
Fitted parameters = [-56.46839641   0.57233217   2.7407944   16.55905648]
&lt;/pre&gt;

&lt;p&gt;&lt;img src="/img/./images/nonlinear-curve-fitting.png"&gt;&lt;p&gt;

&lt;p&gt;
See additional examples at \url{http://docs.scipy.org/doc/scipy/reference/tutorial/optimize.html}.&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/02/18/Nonlinear-curve-fitting.org"&gt;org-mode source&lt;/a&gt;&lt;p&gt;]]></content:encoded>
    </item>
  </channel>
</rss>
