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