def finite_diff(self, values, order=1, acc=4): """ Compute the derivatives of values by finite differences. Args: values: array-like object with the values of the path. order: Order of the derivative. acc: Accuracy: 4 corresponds to a central difference with 5 points. Returns: ndarray with the derivative. """ values = np.asarray(values) assert len(values) == len(self) # Loop over the lines of the path, extract the data and # differenciate f(s) where s is the distance along the line. ders_on_lines = [] for line in self.lines: vals_on_line = values[line] h = self.ds[line[0]] if not np.allclose(h, self.ds[line[:-1]]): raise ValueError("For finite difference derivatives, the path must be homogeneous!\n" + str(self.ds[line[:-1]])) der = finite_diff(vals_on_line, h, order=order, acc=acc) ders_on_lines.append(der) return np.array(ders_on_lines)
def plot_der_potentials(self, ax=None, order=1, **kwargs): """ Plot the derivatives of vl and vloc potentials on axis ax. Used to analyze the derivative discontinuity introduced by the RRKJ method at rc. """ ax, fig, plt = get_ax_fig_plt(ax) from abipy.tools.derivatives import finite_diff from scipy.interpolate import UnivariateSpline lines, legends = [], [] for l, pot in self.potentials.items(): # Need linear mesh for finite_difference --> Spline input potentials on lin_rmesh lin_rmesh, h = np.linspace(pot.rmesh[0], pot.rmesh[-1], num=len(pot.rmesh) * 4, retstep=True) spline = UnivariateSpline(pot.rmesh, pot.values, s=0) lin_values = spline(lin_rmesh) vder = finite_diff(lin_values, h, order=order, acc=4) line, = ax.plot(lin_rmesh, vder, **self._wf_pltopts(l, "ae")) lines.append(line) if l == -1: legends.append("%s-order derivative Vloc" % order) else: legends.append("$s-order derivative PS l=%s" % str(l)) decorate_ax(ax, xlabel="r [Bohr]", ylabel="$D^%s \phi(r)$" % order, title="Derivative of the ion Pseudopotentials", lines=lines, legends=legends) return fig
def finite_diff(self, values, order=1, acc=4): """ Compute the derivatives of values by finite differences. Args: values: array-like object with the values of the path. order: Order of the derivative. acc: Accuracy: 4 corresponds to a central difference with 5 points. Returns: ndarray with the derivative. """ values = np.asarray(values) assert len(values) == len(self) # Loop over the lines of the path, extract the data and # differenciate f(s) where s is the distance along the line. ders_on_lines = [] for line in self.lines: vals_on_line = values[line] h = self.ds[line[0]] if not np.allclose(h, self.ds[line[:-1]]): raise ValueError( "For finite difference derivatives, the path must be homogeneous!\n" + str(self.ds[line[:-1]])) der = finite_diff(vals_on_line, h, order=order, acc=acc) ders_on_lines.append(der) return np.array(ders_on_lines)
def test_poly(self): """Test derivatives of polynomials.""" x, h = np.linspace(0, 1, 800, retstep=True) orders = [1, 2, 3, 4] accuracies = [2, 4, 6] f = x**4 dpolys = { 1: 4 * x**3, 2: 12 * x**2, 3: 24 * x, 4: 24 * np.ones(len(x)), } decs = { 1: 5, 2: 4, 3: 4, 4: 1, } for order in orders: for acc in accuracies: if order == 4 and acc == 6: continue print("order %s, acc %s" % (order, acc)) yder = finite_diff(f, h, order=order, acc=acc) print(np.max(np.abs(yder - dpolys[order]))) self.assert_almost_equal(yder, dpolys[order], decimal=decs[order])
def plot_der_potentials(self, ax=None, order=1, **kwargs): """ Plot the derivatives of vl and vloc potentials on axis ax. Used to analyze the derivative discontinuity introduced by the RRKJ method at rc. """ ax, fig, plt = get_ax_fig_plt(ax) from abipy.tools.derivatives import finite_diff from scipy.interpolate import UnivariateSpline lines, legends = [], [] for l, pot in self.potentials.items(): # Need linear mesh for finite_difference --> Spline input potentials on lin_rmesh lin_rmesh, h = np.linspace(pot.rmesh[0], pot.rmesh[-1], num=len(pot.rmesh) * 4, retstep=True) spline = UnivariateSpline(pot.rmesh, pot.values, s=0) lin_values = spline(lin_rmesh) vder = finite_diff(lin_values, h, order=order, acc=4) line, = ax.plot(lin_rmesh, vder, **self._wf_pltopts(l, "ae")) lines.append(line) if l == -1: legends.append("%s-order derivative Vloc" % order) else: legends.append("$s-order derivative PS l=%s" % str(l)) decorate_ax(ax, xlabel="r [Bohr]", ylabel="$D^%s \phi(r)$" % order, title="Derivative of the ion Pseudopotentials", lines=lines, legends=legends) return fig
def plot_der_densities(self, ax=None, order=1, **kwargs): """ Plot the derivatives of the densitiers on axis ax. Used to analyze possible derivative discontinuities """ ax, fig, plt = get_ax_fig_plt(ax) from scipy.interpolate import UnivariateSpline lines, legends = [], [] for name, rho in self.densities.items(): if name != "rhoM": continue # Need linear mesh for finite_difference --> Spline input densities on lin_rmesh lin_rmesh, h = np.linspace(rho.rmesh[0], rho.rmesh[-1], num=len(rho.rmesh) * 4, retstep=True) spline = UnivariateSpline(rho.rmesh, rho.values, s=0) lin_values = spline(lin_rmesh) vder = finite_diff(lin_values, h, order=order, acc=4) line, = ax.plot(lin_rmesh, vder) #, **self._wf_pltopts(l, "ae")) lines.append(line) legends.append("%s-order derivative of %s" % (order, name)) decorate_ax(ax, xlabel="r [Bohr]", ylabel="$D^%s \n(r)$" % order, title="Derivative of the charge densities", lines=lines, legends=legends) return fig
def test_poly(self): """Test derivatives of polynomials.""" x, h = np.linspace(0, 1, 800, retstep=True) orders = [1,2,3,4] accuracies = [2,4,6] f = x**4 dpolys = { 1: 4 * x**3, 2: 12 * x**2, 3: 24 * x, 4: 24 * np.ones(len(x)), } decs = { 1: 5, 2: 4, 3: 4, 4: 1, } for order in orders: for acc in accuracies: if order == 4 and acc == 6: continue print("order %s, acc %s" % (order, acc)) yder = finite_diff(f, h, order=order, acc=acc) print(np.max(np.abs(yder - dpolys[order]))) self.assert_almost_equal(yder, dpolys[order], decimal=decs[order])
def plot_der_densities(self, ax=None, order=1, **kwargs): """ Plot the derivatives of the densitiers on axis ax. Used to analyze possible derivative discontinuities """ ax, fig, plt = get_ax_fig_plt(ax) from scipy.interpolate import UnivariateSpline lines, legends = [], [] for name, rho in self.densities.items(): if name != "rhoM": continue # Need linear mesh for finite_difference --> Spline input densities on lin_rmesh lin_rmesh, h = np.linspace(rho.rmesh[0], rho.rmesh[-1], num=len(rho.rmesh) * 4, retstep=True) spline = UnivariateSpline(rho.rmesh, rho.values, s=0) lin_values = spline(lin_rmesh) vder = finite_diff(lin_values, h, order=order, acc=4) line, = ax.plot(lin_rmesh, vder) #, **self._wf_pltopts(l, "ae")) lines.append(line) legends.append("%s-order derivative of %s" % (order, name)) decorate_ax(ax, xlabel="r [Bohr]", ylabel="$D^%s \n(r)$" % order, title="Derivative of the charge densities", lines=lines, legends=legends) return fig
def get_fd_emass_d2(self, enes_kline, acc): d2 = finite_diff(enes_kline, self.dk, order=2, acc=acc, index=self.kpos) emass = 1. / (d2.value * (units.eV_to_Ha / units.bohr_to_ang**2)) return emass, d2
def finite_diff(self, order=1, acc=4): """ Compute the derivatives by finite differences. Args: order: Order of the derivative. acc: Accuracy. 4 is fine in many cases. Returns: new :class:`Function1d` instance with the derivative. """ if self.h is None: raise ValueError("Finite differences with inhomogeneous meshes are not supported") return self.__class__(self.mesh, finite_diff(self.values, self.h, order=order, acc=acc))
def test_exp(self): """Test derivatives of exp(x).""" x, h = np.linspace(0, 2, 800, retstep=True) orders = [1,2,3,4] accuracies = [2,4,6] exp = np.exp(x) decs = { 1: 4, 2: 4, 3: 4, 4: 2, } for order in orders: for acc in accuracies: if order == 4 and acc == 6: continue #print("order %s, acc %s" % (order, acc)) yder = finite_diff(exp, h, order=order, acc=acc) #print(np.max(np.abs(yder - exp))) self.assert_almost_equal(yder, exp, decs[order]) d = finite_diff(exp, h, order=order, acc=acc, index=100) assert yder[100] == d.value
def test_exp(self): """Test derivatives of exp(x).""" x, h = np.linspace(0, 2, 800, retstep=True) orders = [1,2,3,4] accuracies = [2,4,6] exp = np.exp(x) decs = { 1: 4, 2: 4, 3: 4, 4: 2, } for order in orders: for acc in accuracies: if order == 4 and acc == 6: continue print("order %s, acc %s" % (order, acc)) yder = finite_diff(exp, h, order=order, acc=acc) print(np.max(np.abs(yder - exp))) self.assert_almost_equal(yder, exp, decs[order])
def calculate_gruns_finite_differences(phfreqs, eig, iv0, volume, dv): """ Calculates the Gruneisen parameters from finite differences on the phonon frequencies. Uses the eigenvectors to match the frequencies at different volumes. Args: phfreqs: numpy array with the phonon frequencies at different volumes. Shape (nvols, nqpts, 3*natoms) eig: numpy array with the phonon eigenvectors at the different volumes. Shape (nvols, nqpts, 3*natoms, 3*natoms) If None simple ordering will be used. iv0: index of the 0 volume. volume: volume of the structure at the central volume. dv: volume variation. Returns: A numpy array with the gruneisen parameters. Shape (nqpts, 3*natoms) """ phfreqs = phfreqs.copy() nvols = phfreqs.shape[0] if eig is not None: for i in range(nvols): if i == iv0: continue for iq in range(phfreqs.shape[1]): ind = match_eigenvectors(eig[iv0, iq], eig[i, iq]) phfreqs[i, iq] = phfreqs[i, iq][ind] acc = nvols - 1 g = np.zeros_like(phfreqs[0]) for iq in range(phfreqs.shape[1]): for im in range(phfreqs.shape[2]): w = phfreqs[iv0, iq, im] if w == 0: g[iq, im] = 0 else: g[iq, im] = -finite_diff( phfreqs[:, iq, im], dv, order=1, acc=acc)[iv0] * volume / w return g
def calculate_gruns_finite_differences(phfreqs, eig, iv0, volume, dv): """ Calculates the Gruneisen parameters from finite differences on the phonon frequencies. Uses the eigenvectors to match the frequencies at different volumes. Args: phfreqs: numpy array with the phonon frequencies at different volumes. Shape (nvols, nqpts, 3*natoms) eig: numpy array with the phonon eigenvectors at the different volumes. Shape (nvols, nqpts, 3*natoms, 3*natoms) If None simple ordering will be used. iv0: index of the 0 volume. volume: volume of the structure at the central volume. dv: volume variation. Returns: A numpy array with the gruneisen parameters. Shape (nqpts, 3*natoms) """ phfreqs = phfreqs.copy() nvols = phfreqs.shape[0] if eig is not None: for i in range(nvols): if i == iv0: continue for iq in range(phfreqs.shape[1]): ind = match_eigenvectors(eig[iv0, iq], eig[i, iq]) phfreqs[i, iq] = phfreqs[i, iq][ind] acc = nvols - 1 g = np.zeros_like(phfreqs[0]) for iq in range(phfreqs.shape[1]): for im in range(phfreqs.shape[2]): w = phfreqs[iv0, iq, im] if w == 0: g[iq, im] = 0 else: g[iq, im] = - finite_diff(phfreqs[:, iq, im], dv, order=1, acc=acc)[iv0] * volume / w return g
def test_complex(self): """complex functions are not supported""" x, h = np.linspace(0, 1, 800, retstep=True) cf = 1j * x with self.assertRaises(ValueError): return finite_diff(cf, h)
def test_complex(self): """complex functions are not supported""" x, h = np.linspace(0, 1, 800, retstep=True) cf = 1j*x with self.assertRaises(ValueError): return finite_diff(cf, h)