def forces(self, phi=None):
     """
     Calculate the normal force and potential gradient on the path.
         
     Returns
     -------
     F_norm, dV : array_like
     """
     if phi is None: phi = self.phi
     # Let `t` be some variable that parametrizes the points such that
     # t_i = i. Calculate the derivs of phi w/ respect to t.
     dphi = helper_functions.deriv14_const_dx(phi.T).T
     d2phi = helper_functions.deriv23_const_dx(phi.T).T 
     # Let `x` be some variable that parametrizes the path such that
     # |dphi/dx| = 1. Calculate the derivs.
     dphi_abssq = np.sum(dphi*dphi, axis=-1)[:,np.newaxis]
     dphi /= np.sqrt(dphi_abssq) # This is now dphi/dx
     d2phi /= dphi_abssq # = d2phi/dx2 + (dphi/dx)(d2phi/dt2)/(dphi/dt)^2
     d2phi -= np.sum(d2phi*dphi, axis=-1)[:,np.newaxis] * dphi # = d2phi/dx2
     # Calculate the total force.
     dV = self.dV(phi)
     dV_perp = dV - np.sum(dV*dphi, axis=-1)[:,np.newaxis] * dphi
     F_norm = d2phi*self.v2 - dV_perp
     if (self.fix_start):
         F_norm[0] = 0.0
     if (self.fix_end):
         F_norm[-1] = 0.0
     return self._forces_rval(F_norm, dV)
def _pathDeriv(phi):
    """Calculates to 4th order if len(phi) >= 5, otherwise 1st/2nd order."""
    if len(phi) >= 5:
        dphi = helper_functions.deriv14_const_dx(phi.T).T
    elif len(phi) > 2:
        dphi = np.empty_like(phi)
        dphi[1:-1] = 0.5*(phi[2:] - phi[:-2])
        dphi[0] = -1.5*phi[0] + 2*phi[1] - 0.5*phi[2]
        dphi[-1] = +1.5*phi[-1] - 2*phi[-2] + 0.5*phi[-3]
    else:
        dphi = np.empty_like(phi)
        dphi[:] = phi[1]-phi[0]
    return dphi