# Polynomial Hyperelasticity

## Overview

The polynomial hyperelastic model is a model in which the strain energy is a polynomial function of the invariants of the deformation tensor. The polynomial hyperelastic model

• is a phenomenologial model,
• has an arbitrary number of parameters, though most materials use fewer than 4
• is typically fit to uniaxial extension/compression, equibiaxial extension/compression, or shear experimental data
• usually valid for strains less than 100%

## Fundamental Equations

The strain energy in the polynomial hyperelastic model is defined as

$$W = \sum_{i,j=0}^N c_{ij}\left(\overline{I}_1 - 3\right)^i \left(\overline{I}_2 - 3\right)^j + + \frac{1}{D_1}\left(J-1\right)^2$$

where the $c_{ij}$ and $D_1$ are material parameters, the $\overline{I}_i$ are the isochoric invariants of the right Cauchy deformation tensor $\pmb{C} = \pmb{F}^T{\cdot}\pmb{F}$, where $\pmb{F}$ is deformation gradient tensor, and $J$ is the determinant of the deformation gradient.

### The Second Piola-Kirchhoff Stress Tensor

$$\pmb{T} = 2\frac{\partial W}{\partial \pmb{C}}$$

For isotropic hyperelasticity $W=W\left(\overline{I}_1, \overline{I}_2, J\right)$ and

$$\pmb{T} = 2\left(\frac{\partial W}{\partial \overline{I}_1}\frac{\partial \overline{I}_1}{\partial \pmb{C}} + \frac{\partial W}{\partial \overline{I}_2}\frac{\partial \overline{I}_2}{\partial \pmb{C}} + \frac{\partial W}{\partial J}\frac{\partial J}{\partial \pmb{C}}\right) = \pmb{A} \cdot \pmb{B}$$

where

$$\pmb{A} = \left[\frac{\partial W}{\partial \overline{I}_1} \quad \frac{\partial W}{\partial \overline{I}_2} \quad \frac{\partial W}{\partial J}\right]$$

and

\begin{align} \pmb{B} &= \left[ \frac{\partial \overline{I}_1}{\partial \pmb{C}} \quad \frac{\partial \overline{I}_2}{\partial \pmb{C}} \quad \frac{\partial J}{\partial \pmb{C}} \right] \\ &= \left[ J^{-2/3}\left(\pmb{I} - \frac{1}{3}I_1 \pmb{C}^{-1} \right) \quad J^{-4/3}\left( I_1\pmb{I} - \pmb{C} - \frac{2}{3}I_2\pmb{C}^{-1} \right)\quad \frac{1}{2}J\pmb{C}^{-1} \right] \end{align}

Elastic stiffness in the material frame is given by

\begin{align} \mathbb{L} &= 4\frac{\partial^2 W}{\partial\pmb{C}\partial\pmb{C}} = 4\frac{\partial}{\partial \pmb{C}}\left( \pmb{A}\cdot\pmb{B}\right) \\ &= 4\left(\frac{\partial \pmb{A}}{\partial \pmb{C}}\cdot\pmb{B} + \pmb{A}\cdot\frac{\partial \pmb{B}}{\partial \pmb{C}}\right) \end{align}

where

$$\frac{\partial \pmb{A}}{\partial \pmb{C}} = \pmb{H} \cdot \pmb{B}, \quad \pmb{H} = \begin{bmatrix} \frac{\partial^2 W}{\partial \overline{I}_1 \partial\overline{I}_1} & \frac{\partial^2 W}{\partial \overline{I}_1 \partial \overline{I}_2} & \frac{\partial^2 W}{\partial \overline{I}_1 \partial J} \\ \frac{\partial^2 W}{\partial \overline{I}_2 \partial \overline{I}_1} & \frac{\partial^2 W}{\partial \overline{I}_2 \partial \overline{I}_2} & \frac{\partial^2 W}{\partial \overline{I}_2 \partial J} \\ \frac{\partial^2 W}{\partial J \partial \overline{I}_1} & \frac{\partial^2 W}{\partial J \partial \overline{I}_2} & \frac{\partial^2 W}{\partial J \partial J} \end{bmatrix}$$

and

$$\frac{\partial \pmb{B}}{\partial \pmb{C}} = \begin{Bmatrix} \frac{1}{3}J^{-2/3}\left[ \pmb{I}\pmb{C}^{-1} - \pmb{C}^{-1}\pmb{I} - I_1\left( \pmb{C}^{-1}\odot\pmb{C}{^-1} - \frac{1}{3}\pmb{C}^{-1}\pmb{C}{^-1}\right) \right] \\ \frac{2}{3}J^{-4/3}\left[ \frac{3}{2}\left(\mathbb{I}_1 - \mathbb{I}_2\right) + \left(\pmb{C}^{-1}\pmb{C} + \pmb{C}\pmb{C}^{-1} \right) - I_1\left( \pmb{C}^{-1}\pmb{I} + \pmb{I}\pmb{C}^{-1} \right) - I_2\left( \pmb{C}^{-1}\odot\pmb{C}^{-1} - \frac{2}{3}\pmb{C}^{-1}\pmb{C}^{-1} \right) \right] \\ \frac{1}{4} J\left( \pmb{C}^{-1}\pmb{C}^{-1} - 2\pmb{C}^{-1}\odot\pmb{C}^{-1} \right) \end{Bmatrix}$$

The operator $\odot$ is defined such that

$$\mathbb{X}_{ijkl} = \pmb{A} \odot \pmb{B} = (A_{ik} B_{jl} + A_{il} B_{jk}) / 2$$

### Requirements of Objectivity

The constitutive equations for the hyperelastic material evaluate the stress directly in the reference configuration. The components of the stress are identified as the components of the Second Piola-Kirchhoff stress $\pmb{T}$. The push forward of the Second Piola-Kirchhoff stress gives the Cauchy stress $\pmb{\sigma}$ in the spatial configuration, as required by most finite element packages. The push forward of the corresponding material stiffness $\mathbb{L}$ does not, however, correspond to the rate of Cauchy stress but the Truesdell rate of the Cauchy stress. Furthermore, the rate of Cauchy stress is not objective, requiring finite element packages to use other so-called objective stress rates in the incremental solution of the momentum equation. In the following sections, it is demonstrated that the push forward of the material stiffness does not correspond to the rate of Cauchy stress and equations relating the stiffness corresponding to the Jaumann rate of the Kirchhoff stress to the push forward of the material stiffness are developed.

The rate of change of Cauchy stress

\begin{align} \dot{\pmb{\sigma}} &= \frac{d}{dt}\left( \frac{1}{J}\pmb{F}\cdot\pmb{T}\cdot{\pmb{F}}^T \right) \\ &= \frac{1}{J}\left[ -\frac{\dot{J}}{J}\pmb{F}\cdot\pmb{T}\cdot{\pmb{F}}^T + \dot{\pmb{F}}\cdot\pmb{T}\cdot{\pmb{F}}^T + \pmb{F} \cdot\frac{d\pmb{T}}{d\pmb{E}}{:}\dot{\pmb{E}} \cdot{\pmb{F}}^T + \pmb{F}\cdot\pmb{T}\cdot\dot{\pmb{F}}^T \right] \end{align}

With the following identities

$$\mathrm{tr}{\pmb{d}} = \frac{\dot{J}}{J} \quad \dot{\pmb{F}} = \pmb{L}\cdot\pmb{F} \quad \dot{\pmb{E}} = \pmb{F}^T\cdot\pmb{d}\cdot\pmb{F} \quad \dot{\pmb{F}}^T = \pmb{F}^T\cdot\pmb{L}^T$$
\begin{align} \dot{\pmb{\sigma}} &= \frac{1}{J}\left[ -\mathrm{tr}{\pmb{d}}\pmb{\sigma} + \pmb{L}\cdot\pmb{F}\cdot\pmb{T}\cdot{\pmb{F}}^T + \pmb{F}\cdot\mathbb{L}{:}\left( \pmb{F}^T\cdot\pmb{d}\cdot\pmb{F} \right)\cdot\pmb{F}^T + \pmb{F}\cdot\pmb{T}\cdot\pmb{F}^T\cdot\pmb{L}^T \right] \\ &= -\mathrm{tr}{\pmb{d}}\pmb{\sigma} + \pmb{L}\cdot\pmb{\sigma} + \frac{1}{J}\left( \pmb{F}\cdot\pmb{F}\cdot \mathbb{L} \cdot\pmb{F}^T\cdot\pmb{F}^T \right){:}\pmb{d} + \pmb{\sigma}\cdot\pmb{L}^T \\ &= -\mathrm{tr}{\pmb{d}}\pmb{\sigma} + \pmb{L}\cdot\pmb{\sigma} + \mathbb{C}{:}\pmb{d} + \pmb{\sigma}\cdot\pmb{L}^T \end{align}

rearranging

\begin{align} \dot{\pmb{\sigma}} - \pmb{\sigma}\cdot\pmb{L}^T - \pmb{L}\cdot\pmb{\sigma} + \mathrm{tr}{\pmb{d}}\pmb{\sigma} &= \mathbb{C}{:}\pmb{d} \\ \mathring{\pmb{\sigma}} &= \mathbb{C}{:}\pmb{d} \end{align}

where

\begin{align} \mathring{\pmb{\sigma}} = \dot{\pmb{\sigma}} - \pmb{\sigma}\cdot\pmb{L}^T - \pmb{L}\cdot\pmb{\sigma} + \mathrm{tr}{\pmb{d}}\pmb{\sigma} \end{align}

is the Truesdell rate of the Cauchy stress. The Truesdell rate of the Cauchy stress is related to the Lie derivative of the Kirchhoff stress by

$$\mathring{\pmb{\sigma}} = \frac{1}{J}\pmb{F}\cdot\dot{\pmb{T}}\pmb{F}^T = \frac{1}{J}\pmb{F}\cdot\left[\frac{d}{dt}\left( J\pmb{F}^{-1}\cdot\pmb{\sigma}\pmb{F}^{-T} \right)\right]\cdot\pmb{F}^T = \frac{1}{J}\pmb{F}\cdot\left[\frac{d}{dt}\left( \pmb{F}^{-1}\cdot\pmb{\tau}\pmb{F}^{-T} \right)\right]\cdot\pmb{F}^{T} = \frac{1}{J}\mathscr{L}\left({\pmb{\tau}}\right)$$

Thus, the push forward of the material time derivative of $\pmb{T}$ is the Truesdell rate of the Cauchy stress. Correspondingly, the Truesdell rate of the Kirchhoff stress is related to the push forward of the material stiffness $\mathbb{L}$ by

$$\mathscr{L}\left({\pmb{\tau}}\right) = J\mathbb{C}{:}\pmb{d}$$

In many finite element packages, the Jaumann rate of the Kirchhoff stress, and not the Truesdell rate, is required. Thus, the elastic stiffness must correspond to the Jaummann rate.. The Jaumann rate of the Kirchhoff stress is given by

\begin{align} \stackrel{\nabla}{\pmb{\tau}} &= { \dot{\pmb{\tau}} + \pmb{\tau}\cdot\pmb{w} - \pmb{w}\cdot\pmb{\tau} } \\ &= \dot{J}\pmb{\sigma} + J\dot{\pmb{\sigma}} + J\pmb{\sigma}\cdot\pmb{w} - \pmb{w}\cdot J\pmb{\sigma} \\ &= J\left(\mathrm{tr}{\pmb{d}}\pmb{\sigma} + \dot{\pmb{\sigma}} + \pmb{\sigma}\cdot\pmb{w} - \pmb{w}\cdot J\pmb{\sigma}\right) \\ &= J\mathbb{D}{:}\pmb{d} \end{align}

where $\mathbb{D}$ is the stiffness corresponding to the Jaumann rate. Subtracting $\mathring{\pmb{\tau}}$ from $\stackrel{\nabla}{\pmb{\tau}}$, the Jaumann stiffness can be cast in terms of $\mathbb{C}$

\begin{align} \left(\mathbb{D} - \mathbb{C}\right){:}\pmb{d} &= \left(\mathrm{tr}{\pmb{d}}\pmb{\sigma} + \dot{\pmb{\sigma}} + \pmb{\sigma}\cdot\pmb{w} - \pmb{w}\cdot\pmb{\sigma}\right) - \left(\dot{\pmb{\sigma}} - \pmb{\sigma}\cdot{\pmb{L}}^T - \pmb{L}\cdot\pmb{\sigma} + \mathrm{tr}{\pmb{d}}\pmb{\sigma}\right) \\ &= \pmb{\sigma}\cdot\pmb{w} + \pmb{\sigma}\cdot{\pmb{L}}^T + \pmb{L}\cdot\pmb{\sigma} - \pmb{w}\cdot\pmb{\sigma} \\ &= \pmb{\sigma}\cdot\pmb{d} + \pmb{d}\cdot\pmb{\sigma} \\ \end{align}

Using indicial notation, and the fact that $\pmb{d}$ and $\pmb{\sigma}$ are symmetric,

\begin{align} \left(D_{ijkl} - C_{ijkl}\right)d_{kl} &= \sigma_{im}d_{mj} + d_{im}\sigma_{mj} \\ &= \left( \sigma_{ik}\delta_{jl} + \delta_{il}\sigma_{jk} \right)d_{kl} \end{align}

from which

\begin{align} \left( D_{ijkl} - C_{ijkl} - \sigma_{ik}\delta_{jl} - \delta_{il}\sigma_{jk} \right)d_{kl} = 0_{ij} \end{align}

Since the preceding equation must hold for all $d_{kl}$, the stiffness corresponding to the Jaumman rate of the Kirchhoff stress is related to the stiffness corresponding to the Truesdell rate of the Kirchhoff stress as

\begin{align} D_{ijkl} = C_{ijkl} + \sigma_{ik}\delta_{jl} + \delta_{il}\sigma_{jk} \end{align}

Note that the stiffness must be made minor symmetric

\begin{align} D_{ijkl} = C_{ijkl} + \frac{1}{2}\left( \sigma_{ik}\delta_{jl} + \sigma_{il}\delta_{jk} + \delta_{il}\sigma_{jk} + \delta_{ik}\sigma_{jl} \right) \end{align}

In symbolic notation,

$$\mathbb{D} = \mathbb{C} + \pmb{\sigma}\odot\pmb{I} + \pmb{I}\odot\pmb{\sigma}$$

which is the correct stiffness corresponding to the Jaumann rate of the Kirchhoff stress, in terms of the push forward of the material stiffness. Equations relating $\mathbb{C}$ to stiffnesses corresponding to other objective rates are derived similarly.

## Matmodlab Implementation

A polynomial material model is implemented as a standard Matmodlab material in matmodlab2/materials/polyhyper.py as a subclass of Material class. The model defines the following (required) attributes and methods

• name: name by which the model is referenced
• eval: method the updates the material state

Additionally, several helper functions are imported from various locations in Matmodlab:

• matmodlab.materials.tensor

• symsq: Computes $\pmb{F}^T{\cdot}\pmb{F}$ and returns the result as a 6D first order tensor
• det, inv: Computes the determinant and inverse of second order tensors (stored as matrix or array)
• invariants: Computes the invariants of a second order tensor
• push: Performs the push forward operation (for both second and fourth order tensors)
• dyad: Computes the dyadic product of two vectors or second order tensors
• symshuffle: Computes the product $X_{ijkl} = .5 (A_{ik} B_{jl} + A_{il} B_{jk}$)
• II1, II5: Fourth order identity tensors
• I6: Identity tensor stored as an array of length 6

The model implementation can be viewed by executing the following cell.



In [1]:

%pycat ../matmodlab2/materials/polyhyper.py




In [2]:

%pylab inline
from bokeh.io import output_notebook
from bokeh.plotting import *
from matmodlab2 import *
output_notebook()

def create_figure(**kwargs):
TOOLS = ('resize,crosshair,pan,wheel_zoom,box_zoom,'
'reset,box_select,lasso_select')
TOOLS = 'resize,pan,wheel_zoom,box_zoom,reset,save'
return figure(tools=TOOLS, **kwargs)




Populating the interactive namespace from numpy and matplotlib
Setting up the Matmodlab notebook environment

var element = $('#d8d716df-4b0f-4ef8-ad7d-a7c502b98404'); (function(global) { function now() { return new Date(); } var force = true; if (typeof (window._bokeh_onload_callbacks) === "undefined" || force === true) { window._bokeh_onload_callbacks = []; window._bokeh_is_loading = undefined; } if (typeof (window._bokeh_timeout) === "undefined" || force === true) { window._bokeh_timeout = Date.now() + 5000; window._bokeh_failed_load = false; } var NB_LOAD_WARNING = {'data': {'text/html': "<div style='background-color: #fdd'>\n"+ "<p>\n"+ "BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \n"+ "may be due to a slow or bad network connection. Possible fixes:\n"+ "</p>\n"+ "<ul>\n"+ "<li>re-rerun output_notebook() to attempt to load from CDN again, or</li>\n"+ "<li>use INLINE resources instead, as so:</li>\n"+ "</ul>\n"+ "<code>\n"+ "from bokeh.resources import INLINE\n"+ "output_notebook(resources=INLINE)\n"+ "</code>\n"+ "</div>"}}; function display_loaded() { if (window.Bokeh !== undefined) { document.getElementById("3ef2cc5d-a2ea-442a-9678-6fd6d432f258").textContent = "BokehJS successfully loaded."; } else if (Date.now() < window._bokeh_timeout) { setTimeout(display_loaded, 100) } } function run_callbacks() { window._bokeh_onload_callbacks.forEach(function(callback) { callback() }); delete window._bokeh_onload_callbacks console.info("Bokeh: all callbacks have finished"); } function load_libs(js_urls, callback) { window._bokeh_onload_callbacks.push(callback); if (window._bokeh_is_loading > 0) { console.log("Bokeh: BokehJS is being loaded, scheduling callback at", now()); return null; } if (js_urls == null || js_urls.length === 0) { run_callbacks(); return null; } console.log("Bokeh: BokehJS not loaded, scheduling load and callback at", now()); window._bokeh_is_loading = js_urls.length; for (var i = 0; i < js_urls.length; i++) { var url = js_urls[i]; var s = document.createElement('script'); s.src = url; s.async = false; s.onreadystatechange = s.onload = function() { window._bokeh_is_loading--; if (window._bokeh_is_loading === 0) { console.log("Bokeh: all BokehJS libraries loaded"); run_callbacks() } }; s.onerror = function() { console.warn("failed to load library " + url); }; console.log("Bokeh: injecting script tag for BokehJS library: ", url); document.getElementsByTagName("head")[0].appendChild(s); } };var element = document.getElementById("3ef2cc5d-a2ea-442a-9678-6fd6d432f258"); if (element == null) { console.log("Bokeh: ERROR: autoload.js configured with elementid '3ef2cc5d-a2ea-442a-9678-6fd6d432f258' but no matching script tag was found. ") return false; } var js_urls = ["https://cdn.pydata.org/bokeh/release/bokeh-0.12.4.min.js", "https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.4.min.js"]; var inline_js = [ function(Bokeh) { Bokeh.set_log_level("info"); }, function(Bokeh) { document.getElementById("3ef2cc5d-a2ea-442a-9678-6fd6d432f258").textContent = "BokehJS is loading..."; }, function(Bokeh) { console.log("Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-0.12.4.min.css"); Bokeh.embed.inject_css("https://cdn.pydata.org/bokeh/release/bokeh-0.12.4.min.css"); console.log("Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.4.min.css"); Bokeh.embed.inject_css("https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.4.min.css"); } ]; function run_inline_js() { if ((window.Bokeh !== undefined) || (force === true)) { for (var i = 0; i < inline_js.length; i++) { inline_js[i](window.Bokeh); }if (force === true) { display_loaded(); }} else if (Date.now() < window._bokeh_timeout) { setTimeout(run_inline_js, 100); } else if (!window._bokeh_failed_load) { console.log("Bokeh: BokehJS failed to load within specified timeout."); window._bokeh_failed_load = true; } else if (force !== true) { var cell =$(document.getElementById("3ef2cc5d-a2ea-442a-9678-6fd6d432f258")).parents('.cell').data().cell;
}

}

console.log("Bokeh: BokehJS loaded, going straight to plotting");
run_inline_js();
} else {
console.log("Bokeh: BokehJS plotting callback run at", now());
run_inline_js();
});
}
}(this));



## Verification

### Uniaxial Stress

For an incompressible isotropic material, uniaxial stress is produced by the following deformation state

$$[F] = \begin{bmatrix}\lambda && \\ & \frac{1}{\sqrt{\lambda}} & \\ & & \frac{1}{\sqrt{\lambda}} \end{bmatrix}$$

The stress difference $\sigma_{\text{axial}} - \sigma_{\text{lateral}}$ is given by



In [3]:

from sympy import Symbol, Matrix, Rational, symbols, sqrt
lam = Symbol('lambda')
F = Matrix(3, 3, [lam, 0, 0, 0, 1/sqrt(lam), 0, 0, 0, 1/sqrt(lam)])
B = Matrix(3, 3, F.dot(F.T))
Bsq = Matrix(3, 3, B.dot(B))
I = Matrix(3, 3, lambda i,j: 1 if i==j else 0)
I1 = B.trace()
I2 = ((B.trace()) ** 2 - Bsq.trace()) / 2
J = F.det()
X = J ** Rational(1, 3)
C1, C2, D1 = symbols('C10 C01 D1')
I1B = I1 / X ** 2
I2B = I2 / X ** 4

S = 2 / J * (1 / X ** 2 * (C1 + I1B * C2) * B - 1 / X ** 4 * C2 * Bsq) \
+ (2 / D1 * (J - 1) - 2 * (C1 * I1B + 2 * C2 * I2B) / 3) * I
(S[0,0] - S[1,1]).simplify()




Out[3]:

2*C01*lambda - 2*C01/lambda**2 + 2*C10*lambda**2 - 2*C10/lambda



We now exercise the Mooney-Rivlin material model using Matmodlab



In [4]:

# Hyperelastic parameters, D1 set to a large number to force incompressibility
parameters = {'D1': 1.e-5, 'C10': 1e6, 'C01': .1e6}

# stretch to 300%
lam = linspace(.5, 3, 50)

# Set up the simulator
mps = MaterialPointSimulator('test1')
mps.material = PolynomialHyperelasticMaterial(**parameters)

# Drive the *incompressible* material through a path of uniaxial stress by
Fij = lambda x: (x, 0, 0, 0, 1/sqrt(x), 0, 0, 0, 1/sqrt(x))
mps.run_step('F', components=Fij(lam[0]), frames=10)
mps.run_step('F', components=Fij(1), frames=1)
mps.run_step('F', components=Fij(lam[-1]), frames=20)

# plot the analytic solution and the simulation
p = create_figure(x_axis_label='Stretch', y_axis_label='Stress')
C10, C01 = parameters['C10'], parameters['C01']

# analytic solution for true and engineering stress
s = 2*C01*lam - 2*C01/lam**2 + 2*C10*lam**2 - 2*C10/lam

# plot the analytic solutions
p.line(lam, s, color='blue', legend='True', line_width=2)
p.line(lam, s/lam, color='green', legend='Engineering', line_width=2)

lam_ = np.exp(mps.get('E.XX'))
ss = mps.get('S.XX') - mps.get('S.ZZ')
p.circle(lam_, ss, color='orange', legend='Simulation, True')
p.circle(lam_, ss/lam_, color='red', legend='Simulation, Engineering')
p.legend.location = 'top_left'

show(p)

# check the actual solutions
assert abs(amax(ss) - amax(s)) / amax(s) < 1e-6
assert abs(amin(ss) - amin(s)) / amin(s) < 1e-6




(function(global) {
function now() {
return new Date();
}

var force = false;

if (typeof (window._bokeh_onload_callbacks) === "undefined" || force === true) {
}

if (typeof (window._bokeh_timeout) === "undefined" || force === true) {
window._bokeh_timeout = Date.now() + 0;
}

"<div style='background-color: #fdd'>\n"+
"<p>\n"+
"may be due to a slow or bad network connection. Possible fixes:\n"+
"</p>\n"+
"<ul>\n"+
"<li>re-rerun output_notebook() to attempt to load from CDN again, or</li>\n"+
"<li>use INLINE resources instead, as so:</li>\n"+
"</ul>\n"+
"<code>\n"+
"from bokeh.resources import INLINE\n"+
"output_notebook(resources=INLINE)\n"+
"</code>\n"+
"</div>"}};

if (window.Bokeh !== undefined) {
} else if (Date.now() < window._bokeh_timeout) {
}
}

function run_callbacks() {
console.info("Bokeh: all callbacks have finished");
}

console.log("Bokeh: BokehJS is being loaded, scheduling callback at", now());
return null;
}
if (js_urls == null || js_urls.length === 0) {
run_callbacks();
return null;
}
for (var i = 0; i < js_urls.length; i++) {
var url = js_urls[i];
var s = document.createElement('script');
s.src = url;
s.async = false;
run_callbacks()
}
};
s.onerror = function() {
console.warn("failed to load library " + url);
};
console.log("Bokeh: injecting script tag for BokehJS library: ", url);
}
};var element = document.getElementById("87dcd987-6e4a-49b8-b2db-4a45b5501d4c");
if (element == null) {
console.log("Bokeh: ERROR: autoload.js configured with elementid '87dcd987-6e4a-49b8-b2db-4a45b5501d4c' but no matching script tag was found. ")
return false;
}

var js_urls = [];

var inline_js = [
function(Bokeh) {
(function() {
var fn = function() {
var render_items = [{"docid":"d91ee087-2d7c-4936-b74f-e0f8beed5c34","elementid":"87dcd987-6e4a-49b8-b2db-4a45b5501d4c","modelid":"aaa06361-5d65-4707-8c6e-24f41a7b5001"}];

Bokeh.embed.embed_items(docs_json, render_items);
};
})();
},
function(Bokeh) {
}
];

function run_inline_js() {

if ((window.Bokeh !== undefined) || (force === true)) {
for (var i = 0; i < inline_js.length; i++) {
inline_js[i](window.Bokeh);
}if (force === true) {
}} else if (Date.now() < window._bokeh_timeout) {
setTimeout(run_inline_js, 100);
console.log("Bokeh: BokehJS failed to load within specified timeout.");
} else if (force !== true) {
var cell = \$(document.getElementById("87dcd987-6e4a-49b8-b2db-4a45b5501d4c")).parents('.cell').data().cell;
}

}

console.log("Bokeh: BokehJS loaded, going straight to plotting");
run_inline_js();
} else {
console.log("Bokeh: BokehJS plotting callback run at", now());
run_inline_js();
});
}
}(this));




In [ ]: