In [1]:
from sympy import *
from collections import defaultdict
from IPython.display import display
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
init_printing()

Bspline basis


In [2]:
xs = Symbol('x')
knots = [0,1,2,3,4,5,6]

# Third-order bspline
sym_basis = bspline_basis_set(3, knots, xs)
# Form for one basis function
sym_basis[0]


Out[2]:
$$\begin{cases} \frac{x^{3}}{6} & \text{for}\: x \geq 0 \wedge x < 1 \\- \frac{x^{3}}{2} + 2 x^{2} - 2 x + \frac{2}{3} & \text{for}\: x \geq 1 \wedge x < 2 \\\frac{x^{3}}{2} - 4 x^{2} + 10 x - \frac{22}{3} & \text{for}\: x \geq 2 \wedge x < 3 \\- \frac{x^{3}}{6} + 2 x^{2} - 8 x + \frac{32}{3} & \text{for}\: x \geq 3 \wedge x \leq 4 \\0 & \text{otherwise} \end{cases}$$

In [3]:
# Plot some basis functions
nbasis_to_plot = 3
npoints_to_plot = 40
basis_y = np.zeros((nbasis_to_plot, npoints_to_plot))
xvals = np.zeros(npoints_to_plot)
for i in range(npoints_to_plot):
    xv = i*.1 + 1.0
    for j in range(3):
        basis_y[j,i] = sym_basis[j].subs(xs,xv)
    xvals[i] = xv
plt.plot(xvals, basis_y[0,:], xvals, basis_y[1,:], xvals, basis_y[2,:])


Out[3]:
[<matplotlib.lines.Line2D at 0x7f2ee8e8d150>,
 <matplotlib.lines.Line2D at 0x7f2ee8e8d350>,
 <matplotlib.lines.Line2D at 0x7f2ee8e8da10>]

Function approximation

To fully represent an interval (say, 0.0 - 5.0, with a knot spacing of 1.0), we need parts of basis functions outside the interval as well. To approximate a function, we evaluate at the M knots (there are 6 knots for this example). There will be M+2 basis functions.


In [4]:
# Need knot values outside the target interval to generate the right set of basis functions.
knots = [0,1,2,3,4,5]
all_knots = [-3,-2,-1,0,1,2,3,4,5,6,7,8]

# Third-order bspline
sym_basis = bspline_basis_set(3, all_knots, xs)
print("Number of basis functions = ",len(sym_basis))
sym_basis


('Number of basis functions = ', 8)
Out[4]:
$$\left [ \begin{cases} \frac{x^{3}}{6} + \frac{3 x^{2}}{2} + \frac{9 x}{2} + \frac{9}{2} & \text{for}\: x \geq -3 \wedge x < -2 \\- \frac{x^{3}}{2} - \frac{5 x^{2}}{2} - \frac{7 x}{2} - \frac{5}{6} & \text{for}\: x \geq -2 \wedge x < -1 \\\frac{x^{3}}{2} + \frac{x^{2}}{2} - \frac{x}{2} + \frac{1}{6} & \text{for}\: x \geq -1 \wedge x < 0 \\- \frac{x^{3}}{6} + \frac{x^{2}}{2} - \frac{x}{2} + \frac{1}{6} & \text{for}\: x \geq 0 \wedge x \leq 1 \\0 & \text{otherwise} \end{cases}, \quad \begin{cases} \frac{x^{3}}{6} + x^{2} + 2 x + \frac{4}{3} & \text{for}\: x \geq -2 \wedge x < -1 \\- \frac{x^{3}}{2} - x^{2} + \frac{2}{3} & \text{for}\: x \geq -1 \wedge x < 0 \\\frac{x^{3}}{2} - x^{2} + \frac{2}{3} & \text{for}\: x \geq 0 \wedge x < 1 \\- \frac{x^{3}}{6} + x^{2} - 2 x + \frac{4}{3} & \text{for}\: x \geq 1 \wedge x \leq 2 \\0 & \text{otherwise} \end{cases}, \quad \begin{cases} \frac{x^{3}}{6} + \frac{x^{2}}{2} + \frac{x}{2} + \frac{1}{6} & \text{for}\: x \geq -1 \wedge x < 0 \\- \frac{x^{3}}{2} + \frac{x^{2}}{2} + \frac{x}{2} + \frac{1}{6} & \text{for}\: x \geq 0 \wedge x < 1 \\\frac{x^{3}}{2} - \frac{5 x^{2}}{2} + \frac{7 x}{2} - \frac{5}{6} & \text{for}\: x \geq 1 \wedge x < 2 \\- \frac{x^{3}}{6} + \frac{3 x^{2}}{2} - \frac{9 x}{2} + \frac{9}{2} & \text{for}\: x \geq 2 \wedge x \leq 3 \\0 & \text{otherwise} \end{cases}, \quad \begin{cases} \frac{x^{3}}{6} & \text{for}\: x \geq 0 \wedge x < 1 \\- \frac{x^{3}}{2} + 2 x^{2} - 2 x + \frac{2}{3} & \text{for}\: x \geq 1 \wedge x < 2 \\\frac{x^{3}}{2} - 4 x^{2} + 10 x - \frac{22}{3} & \text{for}\: x \geq 2 \wedge x < 3 \\- \frac{x^{3}}{6} + 2 x^{2} - 8 x + \frac{32}{3} & \text{for}\: x \geq 3 \wedge x \leq 4 \\0 & \text{otherwise} \end{cases}, \quad \begin{cases} \frac{x^{3}}{6} - \frac{x^{2}}{2} + \frac{x}{2} - \frac{1}{6} & \text{for}\: x \geq 1 \wedge x < 2 \\- \frac{x^{3}}{2} + \frac{7 x^{2}}{2} - \frac{15 x}{2} + \frac{31}{6} & \text{for}\: x \geq 2 \wedge x < 3 \\\frac{x^{3}}{2} - \frac{11 x^{2}}{2} + \frac{39 x}{2} - \frac{131}{6} & \text{for}\: x \geq 3 \wedge x < 4 \\- \frac{x^{3}}{6} + \frac{5 x^{2}}{2} - \frac{25 x}{2} + \frac{125}{6} & \text{for}\: x \geq 4 \wedge x \leq 5 \\0 & \text{otherwise} \end{cases}, \quad \begin{cases} \frac{x^{3}}{6} - x^{2} + 2 x - \frac{4}{3} & \text{for}\: x \geq 2 \wedge x < 3 \\- \frac{x^{3}}{2} + 5 x^{2} - 16 x + \frac{50}{3} & \text{for}\: x \geq 3 \wedge x < 4 \\\frac{x^{3}}{2} - 7 x^{2} + 32 x - \frac{142}{3} & \text{for}\: x \geq 4 \wedge x < 5 \\- \frac{x^{3}}{6} + 3 x^{2} - 18 x + 36 & \text{for}\: x \geq 5 \wedge x \leq 6 \\0 & \text{otherwise} \end{cases}, \quad \begin{cases} \frac{x^{3}}{6} - \frac{3 x^{2}}{2} + \frac{9 x}{2} - \frac{9}{2} & \text{for}\: x \geq 3 \wedge x < 4 \\- \frac{x^{3}}{2} + \frac{13 x^{2}}{2} - \frac{55 x}{2} + \frac{229}{6} & \text{for}\: x \geq 4 \wedge x < 5 \\\frac{x^{3}}{2} - \frac{17 x^{2}}{2} + \frac{95 x}{2} - \frac{521}{6} & \text{for}\: x \geq 5 \wedge x < 6 \\- \frac{x^{3}}{6} + \frac{7 x^{2}}{2} - \frac{49 x}{2} + \frac{343}{6} & \text{for}\: x \geq 6 \wedge x \leq 7 \\0 & \text{otherwise} \end{cases}, \quad \begin{cases} \frac{x^{3}}{6} - 2 x^{2} + 8 x - \frac{32}{3} & \text{for}\: x \geq 4 \wedge x < 5 \\- \frac{x^{3}}{2} + 8 x^{2} - 42 x + \frac{218}{3} & \text{for}\: x \geq 5 \wedge x < 6 \\\frac{x^{3}}{2} - 10 x^{2} + 66 x - \frac{430}{3} & \text{for}\: x \geq 6 \wedge x < 7 \\- \frac{x^{3}}{6} + 4 x^{2} - 32 x + \frac{256}{3} & \text{for}\: x \geq 7 \wedge x \leq 8 \\0 & \text{otherwise} \end{cases}\right ]$$

To approximate a function we need coefficients for each basis function $$ f(x) = \sum_0^{M+2} c_i B_i(x) $$ The values of the function at the knots provides $M$ constraints. We still need 2 more to fully specify the coefficients. This is where the boundary conditions come into play.

$$ \sum_0^{M+2} c_i B_i(x_j) = g(x_j) $$

In [5]:
# Fill out the coefficient matrix
mat = Matrix.eye(len(knots)+2)
for i,k in enumerate(knots):
    for j,basis in enumerate(sym_basis):
        bv = basis.subs(xs,k)
        mat[i+1,j] = bv

# Natural boundary conditions - set 2nd derivative at end of range to zero
dd_spline = [diff(bs, xs, 2) for bs in sym_basis]

row0 = [dds.subs(xs, 0) for dds in dd_spline]
rowN = [dds.subs(xs, knots[-1]) for dds in dd_spline]
display(row0)
display(rowN)
for i in range(len(row0)):
    mat[0,i] = row0[i]
    mat[-1,i] = rowN[i]
mat


$$\left [ 1, \quad -2, \quad 1, \quad 0, \quad 0, \quad 0, \quad 0, \quad 0\right ]$$
$$\left [ 0, \quad 0, \quad 0, \quad 0, \quad 0, \quad 1, \quad -2, \quad 1\right ]$$
Out[5]:
$$\left[\begin{matrix}1 & -2 & 1 & 0 & 0 & 0 & 0 & 0\\\frac{1}{6} & \frac{2}{3} & \frac{1}{6} & 0 & 0 & 0 & 0 & 0\\0 & \frac{1}{6} & \frac{2}{3} & \frac{1}{6} & 0 & 0 & 0 & 0\\0 & 0 & \frac{1}{6} & \frac{2}{3} & \frac{1}{6} & 0 & 0 & 0\\0 & 0 & 0 & \frac{1}{6} & \frac{2}{3} & \frac{1}{6} & 0 & 0\\0 & 0 & 0 & 0 & \frac{1}{6} & \frac{2}{3} & \frac{1}{6} & 0\\0 & 0 & 0 & 0 & 0 & \frac{1}{6} & \frac{2}{3} & \frac{1}{6}\\0 & 0 & 0 & 0 & 0 & 1 & -2 & 1\end{matrix}\right]$$

In [6]:
# Let us assume a simple quadratic function for interpolation
func_to_approx = [k*k for k in knots]
func_to_approx


Out[6]:
$$\left [ 0, \quad 1, \quad 4, \quad 9, \quad 16, \quad 25\right ]$$

Solve for coefficients


In [7]:
lhs_vals = [0] + func_to_approx + [0]  # Zeros are the value of the second derivative
coeffs = mat.LUsolve(Matrix(len(lhs_vals), 1, lhs_vals))
coeffs.T.tolist()[0]


Out[7]:
$$\left [ - \frac{11}{19}, \quad 0, \quad \frac{11}{19}, \quad \frac{70}{19}, \quad \frac{165}{19}, \quad \frac{296}{19}, \quad 25, \quad \frac{654}{19}\right ]$$

Evaluate the spline


In [8]:
def spline_eval(basis, coeffs, x):
    val = 0.0
    for c,bs in zip(coeffs, basis):
        val += c*bs.subs(xs,x)
    return val

In [9]:
# check that it reproduces the knots
for k,v in zip(knots,func_to_approx):
    print(k,spline_eval(sym_basis, coeffs, k),v)


(0, 0, 0)
(1, 1, 1)
(2, 4, 4)
(3, 9, 9)
(4, 16, 16)
(5, 25, 25)

In [10]:
# Now check elsewhere
xvals = []
yvals = []
for i in range(50):
    x = .1*i
    val = spline_eval(sym_basis, coeffs, x)
    xvals.append(x)
    yvals.append(val)
plt.plot(xvals, yvals)
#plt.plot(xvals, yvals, knots, func_to_approx)


Out[10]:
[<matplotlib.lines.Line2D at 0x7f2ee8c677d0>]

Matching Einspline

The einspline code collects the values of each power of x in each interval. The current form of the basis functions is a piecewise interval on the inside, and multiplication by the coefficients on the outside. We would like to transpose this representation so that the intervals are on the outside, and the constributions from each coefficient are on the inside. This will require some examination of the Sympy representation for intervals.


In [11]:
def to_interval(ival):
    """Convert relational expression to an Interval"""
    min_val = None
    lower_open = False
    max_val = None
    upper_open = True
    if isinstance(ival, And):
        for rel in ival.args:
            #print('rel ',rel, type(rel), rel.args[1])
            if isinstance(rel, StrictGreaterThan):
                min_val = rel.args[1]
                #lower_open = True
            elif isinstance(rel, GreaterThan):
                min_val = rel.args[1]
                #lower_open = False
            elif isinstance(rel, StrictLessThan):
                max_val = rel.args[1]
                #upper_open = True
            elif isinstance(rel, LessThan):
                max_val = rel.args[1]
                #upper_open = False
            else:
                print('unhandled ',rel)

    if min_val == None or max_val == None:
        print('error',ival)
    return Interval(min_val, max_val, lower_open, upper_open)

In [12]:
# Transpose the interval and coefficients
#  Note that interval [0,1) has the polynomial coefficients found in the einspline code
#  The other intervals could be shifted, and they would also have the same polynomials
def transpose_interval_and_coefficients(sym_basis):
    cond_map = defaultdict(list)

    i1 = Interval(0,5, False, False) # interval for evaluation
    for idx, s0 in enumerate(sym_basis):
        for expr, cond in s0.args:
            if cond != True:
                i2 = to_interval(cond)
                if not i1.is_disjoint(i2):
                    cond_map[i2].append( (idx, expr) )
    return cond_map

cond_map = transpose_interval_and_coefficients(sym_basis)
for cond, expr in cond_map.items():
    #print(cond, [e.subs(x, x-cond.args[0]) for e in expr])
    print("Interval = ",cond)
    # Shift interval to a common start - see that the polynomial coefficients are all the same
    #e2 = [expand(e[1].subs(xs, xs+cond.args[0])) for e in expr]
    e2 = [(idx,expand(e)) for idx, e in expr]
    display(e2)


('Interval = ', Interval.Ropen(0, 1))
$$\left [ \left ( 0, \quad - \frac{x^{3}}{6} + \frac{x^{2}}{2} - \frac{x}{2} + \frac{1}{6}\right ), \quad \left ( 1, \quad \frac{x^{3}}{2} - x^{2} + \frac{2}{3}\right ), \quad \left ( 2, \quad - \frac{x^{3}}{2} + \frac{x^{2}}{2} + \frac{x}{2} + \frac{1}{6}\right ), \quad \left ( 3, \quad \frac{x^{3}}{6}\right )\right ]$$
('Interval = ', Interval.Ropen(1, 2))
$$\left [ \left ( 1, \quad - \frac{x^{3}}{6} + x^{2} - 2 x + \frac{4}{3}\right ), \quad \left ( 2, \quad \frac{x^{3}}{2} - \frac{5 x^{2}}{2} + \frac{7 x}{2} - \frac{5}{6}\right ), \quad \left ( 3, \quad - \frac{x^{3}}{2} + 2 x^{2} - 2 x + \frac{2}{3}\right ), \quad \left ( 4, \quad \frac{x^{3}}{6} - \frac{x^{2}}{2} + \frac{x}{2} - \frac{1}{6}\right )\right ]$$
('Interval = ', Interval.Ropen(3, 4))
$$\left [ \left ( 3, \quad - \frac{x^{3}}{6} + 2 x^{2} - 8 x + \frac{32}{3}\right ), \quad \left ( 4, \quad \frac{x^{3}}{2} - \frac{11 x^{2}}{2} + \frac{39 x}{2} - \frac{131}{6}\right ), \quad \left ( 5, \quad - \frac{x^{3}}{2} + 5 x^{2} - 16 x + \frac{50}{3}\right ), \quad \left ( 6, \quad \frac{x^{3}}{6} - \frac{3 x^{2}}{2} + \frac{9 x}{2} - \frac{9}{2}\right )\right ]$$
('Interval = ', Interval.Ropen(2, 3))
$$\left [ \left ( 2, \quad - \frac{x^{3}}{6} + \frac{3 x^{2}}{2} - \frac{9 x}{2} + \frac{9}{2}\right ), \quad \left ( 3, \quad \frac{x^{3}}{2} - 4 x^{2} + 10 x - \frac{22}{3}\right ), \quad \left ( 4, \quad - \frac{x^{3}}{2} + \frac{7 x^{2}}{2} - \frac{15 x}{2} + \frac{31}{6}\right ), \quad \left ( 5, \quad \frac{x^{3}}{6} - x^{2} + 2 x - \frac{4}{3}\right )\right ]$$
('Interval = ', Interval.Ropen(4, 5))
$$\left [ \left ( 4, \quad - \frac{x^{3}}{6} + \frac{5 x^{2}}{2} - \frac{25 x}{2} + \frac{125}{6}\right ), \quad \left ( 5, \quad \frac{x^{3}}{2} - 7 x^{2} + 32 x - \frac{142}{3}\right ), \quad \left ( 6, \quad - \frac{x^{3}}{2} + \frac{13 x^{2}}{2} - \frac{55 x}{2} + \frac{229}{6}\right ), \quad \left ( 7, \quad \frac{x^{3}}{6} - 2 x^{2} + 8 x - \frac{32}{3}\right )\right ]$$
('Interval = ', Interval.Ropen(5, 6))
$$\left [ \left ( 5, \quad - \frac{x^{3}}{6} + 3 x^{2} - 18 x + 36\right ), \quad \left ( 6, \quad \frac{x^{3}}{2} - \frac{17 x^{2}}{2} + \frac{95 x}{2} - \frac{521}{6}\right ), \quad \left ( 7, \quad - \frac{x^{3}}{2} + 8 x^{2} - 42 x + \frac{218}{3}\right )\right ]$$

In [13]:
# Create piecewise expression from the transposed intervals
def recreate_piecewise(basis_map, c):
    args = []
    for cond, exprs in basis_map.items():
        e = 0
        for idx, b in exprs:
            e += c[idx] * b
        args.append( (e, cond.as_relational(xs)))
    return Piecewise(*args)

c = IndexedBase('c')
spline = recreate_piecewise(cond_map, c)
spline


Out[13]:
$$\begin{cases} \frac{x^{3} c_{3}}{6} + \left(\frac{x^{3}}{2} - x^{2} + \frac{2}{3}\right) c_{1} + \left(- \frac{x^{3}}{2} + \frac{x^{2}}{2} + \frac{x}{2} + \frac{1}{6}\right) c_{2} + \left(- \frac{x^{3}}{6} + \frac{x^{2}}{2} - \frac{x}{2} + \frac{1}{6}\right) c_{0} & \text{for}\: 0 \leq x \wedge x < 1 \\\left(- \frac{x^{3}}{2} + 2 x^{2} - 2 x + \frac{2}{3}\right) c_{3} + \left(- \frac{x^{3}}{6} + x^{2} - 2 x + \frac{4}{3}\right) c_{1} + \left(\frac{x^{3}}{6} - \frac{x^{2}}{2} + \frac{x}{2} - \frac{1}{6}\right) c_{4} + \left(\frac{x^{3}}{2} - \frac{5 x^{2}}{2} + \frac{7 x}{2} - \frac{5}{6}\right) c_{2} & \text{for}\: 1 \leq x \wedge x < 2 \\\left(- \frac{x^{3}}{2} + 5 x^{2} - 16 x + \frac{50}{3}\right) c_{5} + \left(- \frac{x^{3}}{6} + 2 x^{2} - 8 x + \frac{32}{3}\right) c_{3} + \left(\frac{x^{3}}{6} - \frac{3 x^{2}}{2} + \frac{9 x}{2} - \frac{9}{2}\right) c_{6} + \left(\frac{x^{3}}{2} - \frac{11 x^{2}}{2} + \frac{39 x}{2} - \frac{131}{6}\right) c_{4} & \text{for}\: 3 \leq x \wedge x < 4 \\\left(- \frac{x^{3}}{2} + \frac{7 x^{2}}{2} - \frac{15 x}{2} + \frac{31}{6}\right) c_{4} + \left(- \frac{x^{3}}{6} + \frac{3 x^{2}}{2} - \frac{9 x}{2} + \frac{9}{2}\right) c_{2} + \left(\frac{x^{3}}{6} - x^{2} + 2 x - \frac{4}{3}\right) c_{5} + \left(\frac{x^{3}}{2} - 4 x^{2} + 10 x - \frac{22}{3}\right) c_{3} & \text{for}\: 2 \leq x \wedge x < 3 \\\left(- \frac{x^{3}}{2} + \frac{13 x^{2}}{2} - \frac{55 x}{2} + \frac{229}{6}\right) c_{6} + \left(- \frac{x^{3}}{6} + \frac{5 x^{2}}{2} - \frac{25 x}{2} + \frac{125}{6}\right) c_{4} + \left(\frac{x^{3}}{6} - 2 x^{2} + 8 x - \frac{32}{3}\right) c_{7} + \left(\frac{x^{3}}{2} - 7 x^{2} + 32 x - \frac{142}{3}\right) c_{5} & \text{for}\: 4 \leq x \wedge x < 5 \\\left(- \frac{x^{3}}{2} + 8 x^{2} - 42 x + \frac{218}{3}\right) c_{7} + \left(- \frac{x^{3}}{6} + 3 x^{2} - 18 x + 36\right) c_{5} + \left(\frac{x^{3}}{2} - \frac{17 x^{2}}{2} + \frac{95 x}{2} - \frac{521}{6}\right) c_{6} & \text{for}\: 5 \leq x \wedge x < 6 \end{cases}$$

In [14]:
def spline_eval2(spline, coeffs, x):
    """Evaluate spline using transposed expression"""
    val = 0.0
    c = IndexedBase('c')
    to_sub = {}
    for i,cf in enumerate(coeffs):
        to_sub[c[i]] = cf
    to_sub[xs] = x
    return spline.subs(to_sub)

In [15]:
for k in knots:
    val = spline_eval2(spline, coeffs, k)
    print(k,val)


(0, 0)
(1, 1)
(2, 4)
(3, 9)
(4, 16)
(5, 25)

Bspline for Jastrow

For the radial part of the Jastrow factor, the derivative at $r=0$ is fixed by the cusp condition. At $r=r_{cut}$, the value and derivatives are zero.

Also add the grid spacing, $\Delta$, to the knots.


In [16]:
Delta = Symbol('Delta',positive=True)
#knots = [0,1*Delta,2*Delta,3*Delta,4*Delta,5*Delta]
nknots = 6
knots = [i*Delta for i in range(nknots)]
display('knots = ',knots)
#all_knots = [-3*Delta,-2*Delta,-1*Delta,0,1*Delta,2*Delta,3*Delta,4*Delta,5*Delta,6*Delta,7*Delta,8*Delta]
all_knots = [i*Delta for i in range(-3,nknots+3)]
#display('all knots',all_knots)
rcut = (nknots-1)*Delta

# Third-order bspline
jastrow_sym_basis = bspline_basis_set(3, all_knots, xs)
print("Number of basis functions = ",len(jastrow_sym_basis))
#jastrow_sym_basis


'knots = '
$$\left [ 0, \quad \Delta, \quad 2 \Delta, \quad 3 \Delta, \quad 4 \Delta, \quad 5 \Delta\right ]$$
('Number of basis functions = ', 8)

In [17]:
# Now create the spline from the basis functions
jastrow_cond_map = transpose_interval_and_coefficients(jastrow_sym_basis)
c = IndexedBase('c',shape=(nknots+3))
#c = MatrixSymbol('c',nknots+3,1)
jastrow_spline = recreate_piecewise(jastrow_cond_map, c)
jastrow_spline


Out[17]:
$$\begin{cases} \left(- \frac{521}{6} + \frac{95 x}{2 \Delta} - \frac{17 x^{2}}{2 \Delta^{2}} + \frac{x^{3}}{2 \Delta^{3}}\right) c_{6} + \left(36 - \frac{18 x}{\Delta} + \frac{3 x^{2}}{\Delta^{2}} - \frac{x^{3}}{6 \Delta^{3}}\right) c_{5} + \left(\frac{218}{3} - \frac{42 x}{\Delta} + \frac{8 x^{2}}{\Delta^{2}} - \frac{x^{3}}{2 \Delta^{3}}\right) c_{7} & \text{for}\: 5 \Delta \leq x \wedge x < 6 \Delta \\\left(- \frac{131}{6} + \frac{39 x}{2 \Delta} - \frac{11 x^{2}}{2 \Delta^{2}} + \frac{x^{3}}{2 \Delta^{3}}\right) c_{4} + \left(- \frac{9}{2} + \frac{9 x}{2 \Delta} - \frac{3 x^{2}}{2 \Delta^{2}} + \frac{x^{3}}{6 \Delta^{3}}\right) c_{6} + \left(\frac{32}{3} - \frac{8 x}{\Delta} + \frac{2 x^{2}}{\Delta^{2}} - \frac{x^{3}}{6 \Delta^{3}}\right) c_{3} + \left(\frac{50}{3} - \frac{16 x}{\Delta} + \frac{5 x^{2}}{\Delta^{2}} - \frac{x^{3}}{2 \Delta^{3}}\right) c_{5} & \text{for}\: 3 \Delta \leq x \wedge x < 4 \Delta \\\left(- \frac{430}{3} + \frac{66 x}{\Delta} - \frac{10 x^{2}}{\Delta^{2}} + \frac{x^{3}}{2 \Delta^{3}}\right) c_{7} + \left(\frac{343}{6} - \frac{49 x}{2 \Delta} + \frac{7 x^{2}}{2 \Delta^{2}} - \frac{x^{3}}{6 \Delta^{3}}\right) c_{6} & \text{for}\: 6 \Delta \leq x \wedge x < 7 \Delta \\\left(\frac{2}{3} - \frac{x^{2}}{\Delta^{2}} + \frac{x^{3}}{2 \Delta^{3}}\right) c_{1} + \left(\frac{1}{6} - \frac{x}{2 \Delta} + \frac{x^{2}}{2 \Delta^{2}} - \frac{x^{3}}{6 \Delta^{3}}\right) c_{0} + \left(\frac{1}{6} + \frac{x}{2 \Delta} + \frac{x^{2}}{2 \Delta^{2}} - \frac{x^{3}}{2 \Delta^{3}}\right) c_{2} + \frac{x^{3} c_{3}}{6 \Delta^{3}} & \text{for}\: 0 \leq x \wedge x < \Delta \\\left(- \frac{22}{3} + \frac{10 x}{\Delta} - \frac{4 x^{2}}{\Delta^{2}} + \frac{x^{3}}{2 \Delta^{3}}\right) c_{3} + \left(- \frac{4}{3} + \frac{2 x}{\Delta} - \frac{x^{2}}{\Delta^{2}} + \frac{x^{3}}{6 \Delta^{3}}\right) c_{5} + \left(\frac{9}{2} - \frac{9 x}{2 \Delta} + \frac{3 x^{2}}{2 \Delta^{2}} - \frac{x^{3}}{6 \Delta^{3}}\right) c_{2} + \left(\frac{31}{6} - \frac{15 x}{2 \Delta} + \frac{7 x^{2}}{2 \Delta^{2}} - \frac{x^{3}}{2 \Delta^{3}}\right) c_{4} & \text{for}\: 2 \Delta \leq x \wedge x < 3 \Delta \\\left(- \frac{5}{6} - \frac{7 x}{2 \Delta} - \frac{5 x^{2}}{2 \Delta^{2}} - \frac{x^{3}}{2 \Delta^{3}}\right) c_{0} + \left(\frac{4}{3} + \frac{2 x}{\Delta} + \frac{x^{2}}{\Delta^{2}} + \frac{x^{3}}{6 \Delta^{3}}\right) c_{1} & \text{for}\: - 2 \Delta \leq x \wedge x < - \Delta \\\left(\frac{2}{3} - \frac{x^{2}}{\Delta^{2}} - \frac{x^{3}}{2 \Delta^{3}}\right) c_{1} + \left(\frac{1}{6} - \frac{x}{2 \Delta} + \frac{x^{2}}{2 \Delta^{2}} + \frac{x^{3}}{2 \Delta^{3}}\right) c_{0} + \left(\frac{1}{6} + \frac{x}{2 \Delta} + \frac{x^{2}}{2 \Delta^{2}} + \frac{x^{3}}{6 \Delta^{3}}\right) c_{2} & \text{for}\: - \Delta \leq x \wedge x < 0 \\\left(\frac{9}{2} + \frac{9 x}{2 \Delta} + \frac{3 x^{2}}{2 \Delta^{2}} + \frac{x^{3}}{6 \Delta^{3}}\right) c_{0} & \text{for}\: - 3 \Delta \leq x \wedge x < - 2 \Delta \\\left(- \frac{142}{3} + \frac{32 x}{\Delta} - \frac{7 x^{2}}{\Delta^{2}} + \frac{x^{3}}{2 \Delta^{3}}\right) c_{5} + \left(- \frac{32}{3} + \frac{8 x}{\Delta} - \frac{2 x^{2}}{\Delta^{2}} + \frac{x^{3}}{6 \Delta^{3}}\right) c_{7} + \left(\frac{125}{6} - \frac{25 x}{2 \Delta} + \frac{5 x^{2}}{2 \Delta^{2}} - \frac{x^{3}}{6 \Delta^{3}}\right) c_{4} + \left(\frac{229}{6} - \frac{55 x}{2 \Delta} + \frac{13 x^{2}}{2 \Delta^{2}} - \frac{x^{3}}{2 \Delta^{3}}\right) c_{6} & \text{for}\: 4 \Delta \leq x \wedge x < 5 \Delta \\\left(\frac{256}{3} - \frac{32 x}{\Delta} + \frac{4 x^{2}}{\Delta^{2}} - \frac{x^{3}}{6 \Delta^{3}}\right) c_{7} & \text{for}\: 7 \Delta \leq x \wedge x < 8 \Delta \\\left(- \frac{5}{6} + \frac{7 x}{2 \Delta} - \frac{5 x^{2}}{2 \Delta^{2}} + \frac{x^{3}}{2 \Delta^{3}}\right) c_{2} + \left(- \frac{1}{6} + \frac{x}{2 \Delta} - \frac{x^{2}}{2 \Delta^{2}} + \frac{x^{3}}{6 \Delta^{3}}\right) c_{4} + \left(\frac{2}{3} - \frac{2 x}{\Delta} + \frac{2 x^{2}}{\Delta^{2}} - \frac{x^{3}}{2 \Delta^{3}}\right) c_{3} + \left(\frac{4}{3} - \frac{2 x}{\Delta} + \frac{x^{2}}{\Delta^{2}} - \frac{x^{3}}{6 \Delta^{3}}\right) c_{1} & \text{for}\: \Delta \leq x \wedge x < 2 \Delta \end{cases}$$

In [18]:
# Boundary conditions at r = 0 with the cusp (first derivative) condition

cusp_val = Symbol('A')
# Evaluate spline derivative at 0
du = diff(jastrow_spline,xs)
du_zero = du.subs(xs, 0)
display(du_zero)

# Solve following equation
display(Eq(du_zero-cusp_val,0))

# solve doesn't seem to work with Indexed value, substitute something else
c0 = Symbol('c0')
soln = solve(du_zero.subs(c[0],c0) - cusp_val, c0)
display(Eq(c0, soln[0]))


$$- \frac{c_{0}}{2 \Delta} + \frac{c_{2}}{2 \Delta}$$
$$- A - \frac{c_{0}}{2 \Delta} + \frac{c_{2}}{2 \Delta} = 0$$
$$c_{0} = - 2 A \Delta + c_{2}$$

In [19]:
# Boundary conditions at r=r_cut.  For smoothness the value and derivatives should be 0.
# Add zero value and derivatives at r_cut
eq_v = jastrow_spline.subs(xs, rcut)
display(Eq(Symbol('u')(xs),eq_v))

eq_dv = diff(jastrow_spline, xs).subs(xs,rcut)
display(Eq(diff(Symbol('u')(xs),xs),eq_dv))

eq_ddv = diff(jastrow_spline, xs, 2).subs(xs,rcut)
display(Eq(diff(Symbol('u')(xs),xs,2),eq_ddv))

#eq_d3v = diff(jastrow_spline, xs, 3).subs(xs, rcut)
#display(eq_d3v)


$$u{\left (x \right )} = \frac{c_{5}}{6} + \frac{2 c_{6}}{3} + \frac{c_{7}}{6}$$
$$\frac{d}{d x} u{\left (x \right )} = - \frac{c_{5}}{2 \Delta} + \frac{c_{7}}{2 \Delta}$$
$$\frac{d^{2}}{d x^{2}} u{\left (x \right )} = \frac{1}{\Delta^{2}} \left(c_{5} - 2 c_{6} + c_{7}\right)$$

In [20]:
# Solve for all these equal to zero
c5 = Symbol('c5')
c6 = Symbol('c6')
c7 = Symbol('c7')
subs_list = {c[5]:c5, c[6]:c6, c[7]:c7}
linsolve([v.subs(subs_list) for v in [eq_v, eq_dv, eq_ddv]], [c5, c6, c7])
# QMCPACK enforces these conditions by setting c5, c6, c7 (the last three coefficients) to 0.


Out[20]:
$$\left\{\left ( c_{7}, \quad - \frac{c_{7}}{2}, \quad c_{7}\right )\right\}$$

In [ ]: