spline_aj = [[s], [s, p]] c = LFC(gd, spline_aj, cut=True, forces=True) c.set_positions(spos_ac) C_ani = c.dict(3, zero=True) if 1 in C_ani: C_ani[1][:, 1:] = np.eye(3) psi = gd.zeros(3) c.add(psi, C_ani) c.integrate(psi, C_ani) if 1 in C_ani: d = C_ani[1][:, 1:].diagonal() assert d.ptp() < 4e-6 C_ani[1][:, 1:] -= np.diag(d) assert abs(C_ani[1]).max() < 5e-17 d_aniv = c.dict(3, derivative=True) c.derivative(psi, d_aniv) if 1 in d_aniv: for v in range(3): assert abs(d_aniv[1][v - 1, 0, v] + 0.2144) < 5e-5 d_aniv[1][v - 1, 0, v] = 0 assert abs(d_aniv[1]).max() < 3e-16 eps = 0.0001 pos_av = np.dot(spos_ac, gd.cell_cv) for v in range(3): pos_av[0, v] += eps c.set_positions(np.dot(pos_av, gd.icell_cv.T)) c.integrate(psi, C_ani) if 0 in d_aniv: C0_n = C_ani[0][:, 0].copy() pos_av[0, v] -= 2 * eps c.set_positions(np.dot(pos_av, gd.icell_cv.T))
class WaveFunctions: """Class for wave-function related stuff (e.g. projectors).""" def __init__(self, nbands, kpt_u, setups, kd, gd, dtype=float): """Store and initialize required attributes. Parameters ---------- nbands: int Number of occupied bands. kpt_u: list of KPoints List of KPoint instances from a ground-state calculation (i.e. the attribute ``calc.wfs.kpt_u``). setups: Setups LocalizedFunctionsCollection setups. kd: KPointDescriptor K-point and symmetry related stuff. gd: GridDescriptor Descriptor for the coarse grid. dtype: dtype This is the ``dtype`` for the wave-function derivatives (same as the ``dtype`` for the ground-state wave-functions). """ self.dtype = dtype # K-point related attributes self.kd = kd # Number of occupied bands self.nbands = nbands # Projectors self.pt = LFC(gd, [setup.pt_j for setup in setups], kd, dtype=self.dtype) # Store grid self.gd = gd # Unfold the irreducible BZ to the full BZ # List of KPointContainers for the k-points in the full BZ self.kpt_u = [] # No symmetries or only time-reversal symmetry used assert kd.symmetry.point_group == False if kd.symmetry.time_reversal == False: # For now, time-reversal symmetry not allowed assert len(kpt_u) == kd.nbzkpts for k in range(kd.nbzkpts): kpt_ = kpt_u[k] psit_nG = gd.empty(nbands, dtype=self.dtype) for n, psit_G in enumerate(psit_nG): psit_G[:] = kpt_.psit_nG[n] # psit_0 = psit_G[0, 0, 0] # psit_G *= psit_0.conj() / (abs(psit_0)) # Strip off KPoint attributes and store in the KPointContainer # Note, only the occupied GS wave-functions are retained here ! kpt = KPointContainer(weight=kpt_.weight, k=kpt_.k, s=kpt_.s, phase_cd=kpt_.phase_cd, eps_n=kpt_.eps_n[:nbands], psit_nG=psit_nG, psit1_nG=None, P_ani=None, dP_aniv=None) # q=kpt.q, # f_n=kpt.f_n[:nbands]) self.kpt_u.append(kpt) else: assert len(kpt_u) == kd.nibzkpts for k, k_c in enumerate(kd.bzk_kc): # Index of symmetry related point in the irreducible BZ ik = kd.bz2ibz_k[k] # Index of point group operation s = kd.sym_k[k] # Time-reversal symmetry used time_reversal = kd.time_reversal_k[k] # Coordinates of symmetry related point in the irreducible BZ ik_c = kd.ibzk_kc[ik] # Point group operation op_cc = kd.symmetry.op_scc[s] # KPoint from ground-state calculation kpt_ = kpt_u[ik] weight = 1. / kd.nbzkpts * (2 - kpt_.s) phase_cd = np.exp(2j * pi * gd.sdisp_cd * k_c[:, np.newaxis]) psit_nG = gd.empty(nbands, dtype=self.dtype) for n, psit_G in enumerate(psit_nG): #XXX Seems to corrupt my memory somehow ??? psit_G[:] = kd.symmetry.symmetrize_wavefunction( kpt_.psit_nG[n], ik_c, k_c, op_cc, time_reversal) # Choose gauge # psit_0 = psit_G[0, 0, 0] # psit_G *= psit_0.conj() / (abs(psit_0)) kpt = KPointContainer(weight=weight, k=k, s=kpt_.s, phase_cd=phase_cd, eps_n=kpt_.eps_n[:nbands], psit_nG=psit_nG, psit1_nG=None, P_ani=None, dP_aniv=None) self.kpt_u.append(kpt) def initialize(self, spos_ac): """Initialize projectors according to the ``gamma`` attribute.""" # Set positions on LFC's self.pt.set_positions(spos_ac) # Calculate projector coefficients for the GS wave-functions self.calculate_projector_coef() def reset(self): """Make fresh arrays for wave-function derivatives.""" for kpt in self.kpt_u: kpt.psit1_nG = self.gd.zeros(n=self.nbands, dtype=self.dtype) def calculate_projector_coef(self): """Coefficients for the derivative of the non-local part of the PP. Parameters ---------- k: int Index of the k-point of the Bloch state on which the non-local potential operates on. The calculated coefficients are the following (except for an overall sign of -1; see ``derivative`` member function of class ``LFC``): 1. Coefficients from the projector functions:: / a P_ani = | dG p (G) Psi (G) , / i n 2. Coefficients from the derivative of the projector functions:: / a dP_aniv = | dG dp (G) Psi (G) , / iv n where:: a d a dp (G) = --- Phi (G) . iv a i dR """ n = self.nbands for kpt in self.kpt_u: # K-point index and wave-functions k = kpt.k psit_nG = kpt.psit_nG # Integration dicts P_ani = self.pt.dict(shape=n) dP_aniv = self.pt.dict(shape=n, derivative=True) # 1) Integrate with projectors self.pt.integrate(psit_nG, P_ani, q=k) kpt.P_ani = P_ani # 2) Integrate with derivative of projectors self.pt.derivative(psit_nG, dP_aniv, q=k) kpt.dP_aniv = dP_aniv
class WaveFunctions: """Class for wave-function related stuff (e.g. projectors).""" def __init__(self, nbands, kpt_u, setups, kd, gd, dtype=float): """Store and initialize required attributes. Parameters ---------- nbands: int Number of occupied bands. kpt_u: list of KPoints List of KPoint instances from a ground-state calculation (i.e. the attribute ``calc.wfs.kpt_u``). setups: Setups LocalizedFunctionsCollection setups. kd: KPointDescriptor K-point and symmetry related stuff. gd: GridDescriptor Descriptor for the coarse grid. dtype: dtype This is the ``dtype`` for the wave-function derivatives (same as the ``dtype`` for the ground-state wave-functions). """ self.dtype = dtype # K-point related attributes self.kd = kd # Number of occupied bands self.nbands = nbands # Projectors self.pt = LFC(gd, [setup.pt_j for setup in setups], dtype=self.dtype) # Store grid self.gd = gd # Unfold the irreducible BZ to the full BZ # List of KPointContainers for the k-points in the full BZ self.kpt_u = [] # No symmetries or only time-reversal symmetry used if kd.symmetry is None: # For now, time-reversal symmetry not allowed assert len(kpt_u) == kd.nbzkpts for k in range(kd.nbzkpts): kpt_ = kpt_u[k] psit_nG = gd.empty(nbands, dtype=self.dtype) for n, psit_G in enumerate(psit_nG): psit_G[:] = kpt_.psit_nG[n] # psit_0 = psit_G[0, 0, 0] # psit_G *= psit_0.conj() / (abs(psit_0)) # Strip off KPoint attributes and store in the KPointContainer # Note, only the occupied GS wave-functions are retained here ! kpt = KPointContainer(weight=kpt_.weight, k=kpt_.k, s=kpt_.s, phase_cd=kpt_.phase_cd, eps_n=kpt_.eps_n[:nbands], psit_nG=psit_nG, psit1_nG=None, P_ani=None, dP_aniv=None) # q=kpt.q, # f_n=kpt.f_n[:nbands]) self.kpt_u.append(kpt) else: assert len(kpt_u) == kd.nibzkpts for k, k_c in enumerate(kd.bzk_kc): # Index of symmetry related point in the irreducible BZ ik = kd.kibz_k[k] # Index of point group operation s = kd.sym_k[k] # Time-reversal symmetry used time_reversal = kd.time_reversal_k[k] # Coordinates of symmetry related point in the irreducible BZ ik_c = kd.ibzk_kc[ik] # Point group operation op_cc = kd.symmetry.op_scc[s] # KPoint from ground-state calculation kpt_ = kpt_u[ik] weight = 1. / kd.nbzkpts * (2 - kpt_.s) phase_cd = np.exp(2j * pi * gd.sdisp_cd * k_c[:, np.newaxis]) psit_nG = gd.empty(nbands, dtype=self.dtype) for n, psit_G in enumerate(psit_nG): #XXX Seems to corrupt my memory somehow ??? psit_G[:] = kd.symmetry.symmetrize_wavefunction( kpt_.psit_nG[n], ik_c, k_c, op_cc, time_reversal) # Choose gauge # psit_0 = psit_G[0, 0, 0] # psit_G *= psit_0.conj() / (abs(psit_0)) kpt = KPointContainer(weight=weight, k=k, s=kpt_.s, phase_cd=phase_cd, eps_n=kpt_.eps_n[:nbands], psit_nG=psit_nG, psit1_nG=None, P_ani=None, dP_aniv=None) self.kpt_u.append(kpt) def initialize(self, spos_ac): """Initialize projectors according to the ``gamma`` attribute.""" # Set positions on LFC's self.pt.set_positions(spos_ac) if not self.kd.gamma: # Set k-vectors and update self.pt.set_k_points(self.kd.ibzk_kc) self.pt._update(spos_ac) # Calculate projector coefficients for the GS wave-functions self.calculate_projector_coef() def reset(self): """Make fresh arrays for wave-function derivatives.""" for kpt in self.kpt_u: kpt.psit1_nG = self.gd.zeros(n=self.nbands, dtype=self.dtype) def calculate_projector_coef(self): """Coefficients for the derivative of the non-local part of the PP. Parameters ---------- k: int Index of the k-point of the Bloch state on which the non-local potential operates on. The calculated coefficients are the following (except for an overall sign of -1; see ``derivative`` member function of class ``LFC``): 1. Coefficients from the projector functions:: / a P_ani = | dG p (G) Psi (G) , / i n 2. Coefficients from the derivative of the projector functions:: / a dP_aniv = | dG dp (G) Psi (G) , / iv n where:: a d a dp (G) = --- Phi (G) . iv a i dR """ n = self.nbands for kpt in self.kpt_u: # K-point index and wave-functions k = kpt.k psit_nG = kpt.psit_nG # Integration dicts P_ani = self.pt.dict(shape=n) dP_aniv = self.pt.dict(shape=n, derivative=True) # 1) Integrate with projectors self.pt.integrate(psit_nG, P_ani, q=k) kpt.P_ani = P_ani # 2) Integrate with derivative of projectors self.pt.derivative(psit_nG, dP_aniv, q=k) kpt.dP_aniv = dP_aniv
lmax = 2 b = 8.0 m = (lmax + 1)**2 gd = GridDescriptor([n, n, n], [a, a, a]) r = np.linspace(0, rc, 200) g = np.exp(-(r / rc * b)**2) splines = [Spline(l=l, rmax=rc, f_g=g) for l in range(lmax + 1)] c = LFC(gd, [splines]) c.set_positions([(0, 0, 0)]) psi = gd.zeros(m) d0 = c.dict(m) if 0 in d0: d0[0] = np.identity(m) c.add(psi, d0) d1 = c.dict(m, derivative=True) c.derivative(psi, d1) class TestSetup(Setup): l_j = range(lmax + 1) nj = lmax + 1 ni = m def __init__(self): pass rgd = RadialGridDescriptor(r, np.ones_like(r) * r[1]) g = [np.exp(-(r / rc * b)**2) * r**l for l in range(lmax + 1)] d2 = TestSetup().get_derivative_integrals(rgd, g, np.zeros_like(g)) if 0 in d1:
psi = gd.zeros() c.add(psi, c_ai) d_avv = dict([(a, np.zeros((3, 3))) for a in c.my_atom_indices]) c.second_derivative(psi, d_avv) if 0 in d_avv: print(d_avv[0]) eps = 0.000001 d_aiv = c.dict(derivative=True) pos_av = np.dot(spos_ac, gd.cell_cv) for v in range(3): pos_av[0, v] += eps c.set_positions(np.dot(pos_av, gd.icell_cv.T)) c.derivative(psi, d_aiv) if 0 in d_aiv: d0_v = d_aiv[0][0].copy() pos_av[0, v] -= 2 * eps c.set_positions(np.dot(pos_av, gd.icell_cv.T)) c.derivative(psi, d_aiv) if 0 in d_aiv: d0_v -= d_aiv[0][0] d0_v /= -2 * eps print(d0_v) d_avv[0][v] -= d0_v pos_av[0, v] += eps if 0 in d_avv: assert np.abs(d_avv[0]).max() < 1e-10
class FDWaveFunctions(FDPWWaveFunctions): def __init__(self, stencil, diagksl, orthoksl, initksl, gd, nvalence, setups, bd, dtype, world, kd, timer=None): FDPWWaveFunctions.__init__(self, diagksl, orthoksl, initksl, gd, nvalence, setups, bd, dtype, world, kd, timer) self.wd = self.gd # wave function descriptor # Kinetic energy operator: self.kin = Laplace(self.gd, -0.5, stencil, self.dtype, allocate=False) self.matrixoperator = MatrixOperator(orthoksl) def set_setups(self, setups): self.pt = LFC(self.gd, [setup.pt_j for setup in setups], self.kpt_comm, dtype=self.dtype, forces=True) FDPWWaveFunctions.set_setups(self, setups) def set_positions(self, spos_ac): if not self.kin.is_allocated(): self.kin.allocate() FDPWWaveFunctions.set_positions(self, spos_ac) def summary(self, fd): fd.write('Mode: Finite-difference\n') def make_preconditioner(self, block=1): return Preconditioner(self.gd, self.kin, self.dtype, block) def apply_pseudo_hamiltonian(self, kpt, hamiltonian, psit_xG, Htpsit_xG): self.kin.apply(psit_xG, Htpsit_xG, kpt.phase_cd) hamiltonian.apply_local_potential(psit_xG, Htpsit_xG, kpt.s) def add_orbital_density(self, nt_G, kpt, n): if self.dtype == float: axpy(1.0, kpt.psit_nG[n]**2, nt_G) else: axpy(1.0, kpt.psit_nG[n].real**2, nt_G) axpy(1.0, kpt.psit_nG[n].imag**2, nt_G) def add_to_density_from_k_point_with_occupation(self, nt_sG, kpt, f_n): # Used in calculation of response part of GLLB-potential nt_G = nt_sG[kpt.s] if self.dtype == float: for f, psit_G in zip(f_n, kpt.psit_nG): axpy(f, psit_G**2, nt_G) else: for f, psit_G in zip(f_n, kpt.psit_nG): axpy(f, psit_G.real**2, nt_G) axpy(f, psit_G.imag**2, nt_G) # Hack used in delta-scf calculations: if hasattr(kpt, 'c_on'): assert self.bd.comm.size == 1 d_nn = np.zeros((self.bd.mynbands, self.bd.mynbands), dtype=complex) for ne, c_n in zip(kpt.ne_o, kpt.c_on): d_nn += ne * np.outer(c_n.conj(), c_n) for d_n, psi0_G in zip(d_nn, kpt.psit_nG): for d, psi_G in zip(d_n, kpt.psit_nG): if abs(d) > 1.e-12: nt_G += (psi0_G.conj() * d * psi_G).real def calculate_kinetic_energy_density(self, tauct, grad_v): assert not hasattr(self.kpt_u[0], 'c_on') if isinstance(self.kpt_u[0].psit_nG, TarFileReference): raise RuntimeError('Wavefunctions have not been initialized.') taut_sG = self.gd.zeros(self.nspins) dpsit_G = self.gd.empty(dtype=self.dtype) for kpt in self.kpt_u: for f, psit_G in zip(kpt.f_n, kpt.psit_nG): for v in range(3): grad_v[v](psit_G, dpsit_G, kpt.phase_cd) axpy(0.5 * f, abs(dpsit_G)**2, taut_sG[kpt.s]) self.kpt_comm.sum(taut_sG) self.band_comm.sum(taut_sG) return taut_sG def calculate_forces(self, hamiltonian, F_av): # Calculate force-contribution from k-points: F_av.fill(0.0) F_aniv = self.pt.dict(self.bd.mynbands, derivative=True) for kpt in self.kpt_u: self.pt.derivative(kpt.psit_nG, F_aniv, kpt.q) for a, F_niv in F_aniv.items(): F_niv = F_niv.conj() F_niv *= kpt.f_n[:, np.newaxis, np.newaxis] dH_ii = unpack(hamiltonian.dH_asp[a][kpt.s]) P_ni = kpt.P_ani[a] F_vii = np.dot(np.dot(F_niv.transpose(), P_ni), dH_ii) F_niv *= kpt.eps_n[:, np.newaxis, np.newaxis] dO_ii = hamiltonian.setups[a].dO_ii F_vii -= np.dot(np.dot(F_niv.transpose(), P_ni), dO_ii) F_av[a] += 2 * F_vii.real.trace(0, 1, 2) # Hack used in delta-scf calculations: if hasattr(kpt, 'c_on'): assert self.bd.comm.size == 1 self.pt.derivative(kpt.psit_nG, F_aniv, kpt.q) #XXX again d_nn = np.zeros((self.bd.mynbands, self.bd.mynbands), dtype=complex) for ne, c_n in zip(kpt.ne_o, kpt.c_on): d_nn += ne * np.outer(c_n.conj(), c_n) for a, F_niv in F_aniv.items(): F_niv = F_niv.conj() dH_ii = unpack(hamiltonian.dH_asp[a][kpt.s]) Q_ni = np.dot(d_nn, kpt.P_ani[a]) F_vii = np.dot(np.dot(F_niv.transpose(), Q_ni), dH_ii) F_niv *= kpt.eps_n[:, np.newaxis, np.newaxis] dO_ii = hamiltonian.setups[a].dO_ii F_vii -= np.dot(np.dot(F_niv.transpose(), Q_ni), dO_ii) F_av[a] += 2 * F_vii.real.trace(0, 1, 2) self.bd.comm.sum(F_av, 0) if self.bd.comm.rank == 0: self.kpt_comm.sum(F_av, 0) def estimate_memory(self, mem): FDPWWaveFunctions.estimate_memory(self, mem) self.kin.estimate_memory(mem.subnode('Kinetic operator'))
class FDWaveFunctions(FDPWWaveFunctions): def __init__(self, stencil, diagksl, orthoksl, initksl, gd, nvalence, setups, bd, dtype, world, kd, timer=None): FDPWWaveFunctions.__init__(self, diagksl, orthoksl, initksl, gd, nvalence, setups, bd, dtype, world, kd, timer) self.wd = self.gd # wave function descriptor # Kinetic energy operator: self.kin = Laplace(self.gd, -0.5, stencil, self.dtype, allocate=False) self.matrixoperator = MatrixOperator(orthoksl) def set_setups(self, setups): self.pt = LFC(self.gd, [setup.pt_j for setup in setups], self.kpt_comm, dtype=self.dtype, forces=True) FDPWWaveFunctions.set_setups(self, setups) def set_positions(self, spos_ac): if not self.kin.is_allocated(): self.kin.allocate() FDPWWaveFunctions.set_positions(self, spos_ac) def summary(self, fd): fd.write('Mode: Finite-difference\n') def make_preconditioner(self, block=1): return Preconditioner(self.gd, self.kin, self.dtype, block) def apply_pseudo_hamiltonian(self, kpt, hamiltonian, psit_xG, Htpsit_xG): self.kin.apply(psit_xG, Htpsit_xG, kpt.phase_cd) hamiltonian.apply_local_potential(psit_xG, Htpsit_xG, kpt.s) def add_orbital_density(self, nt_G, kpt, n): if self.dtype == float: axpy(1.0, kpt.psit_nG[n]**2, nt_G) else: axpy(1.0, kpt.psit_nG[n].real**2, nt_G) axpy(1.0, kpt.psit_nG[n].imag**2, nt_G) def add_to_density_from_k_point_with_occupation(self, nt_sG, kpt, f_n): # Used in calculation of response part of GLLB-potential nt_G = nt_sG[kpt.s] if self.dtype == float: for f, psit_G in zip(f_n, kpt.psit_nG): axpy(f, psit_G**2, nt_G) else: for f, psit_G in zip(f_n, kpt.psit_nG): axpy(f, psit_G.real**2, nt_G) axpy(f, psit_G.imag**2, nt_G) # Hack used in delta-scf calculations: if hasattr(kpt, 'c_on'): assert self.bd.comm.size == 1 d_nn = np.zeros((self.bd.mynbands, self.bd.mynbands), dtype=complex) for ne, c_n in zip(kpt.ne_o, kpt.c_on): d_nn += ne * np.outer(c_n.conj(), c_n) for d_n, psi0_G in zip(d_nn, kpt.psit_nG): for d, psi_G in zip(d_n, kpt.psit_nG): if abs(d) > 1.e-12: nt_G += (psi0_G.conj() * d * psi_G).real def calculate_kinetic_energy_density(self, tauct, grad_v): assert not hasattr(self.kpt_u[0], 'c_on') if isinstance(self.kpt_u[0].psit_nG, TarFileReference): raise RuntimeError('Wavefunctions have not been initialized.') taut_sG = self.gd.zeros(self.nspins) dpsit_G = self.gd.empty(dtype=self.dtype) for kpt in self.kpt_u: for f, psit_G in zip(kpt.f_n, kpt.psit_nG): for v in range(3): grad_v[v](psit_G, dpsit_G, kpt.phase_cd) axpy(0.5 * f, abs(dpsit_G)**2, taut_sG[kpt.s]) self.kpt_comm.sum(taut_sG) self.band_comm.sum(taut_sG) return taut_sG def calculate_forces(self, hamiltonian, F_av): # Calculate force-contribution from k-points: F_av.fill(0.0) F_aniv = self.pt.dict(self.bd.mynbands, derivative=True) for kpt in self.kpt_u: self.pt.derivative(kpt.psit_nG, F_aniv, kpt.q) for a, F_niv in F_aniv.items(): F_niv = F_niv.conj() F_niv *= kpt.f_n[:, np.newaxis, np.newaxis] dH_ii = unpack(hamiltonian.dH_asp[a][kpt.s]) P_ni = kpt.P_ani[a] F_vii = np.dot(np.dot(F_niv.transpose(), P_ni), dH_ii) F_niv *= kpt.eps_n[:, np.newaxis, np.newaxis] dO_ii = hamiltonian.setups[a].dO_ii F_vii -= np.dot(np.dot(F_niv.transpose(), P_ni), dO_ii) F_av[a] += 2 * F_vii.real.trace(0, 1, 2) # Hack used in delta-scf calculations: if hasattr(kpt, 'c_on'): assert self.bd.comm.size == 1 self.pt.derivative(kpt.psit_nG, F_aniv, kpt.q) #XXX again d_nn = np.zeros((self.bd.mynbands, self.bd.mynbands), dtype=complex) for ne, c_n in zip(kpt.ne_o, kpt.c_on): d_nn += ne * np.outer(c_n.conj(), c_n) for a, F_niv in F_aniv.items(): F_niv = F_niv.conj() dH_ii = unpack(hamiltonian.dH_asp[a][kpt.s]) Q_ni = np.dot(d_nn, kpt.P_ani[a]) F_vii = np.dot(np.dot(F_niv.transpose(), Q_ni), dH_ii) F_niv *= kpt.eps_n[:, np.newaxis, np.newaxis] dO_ii = hamiltonian.setups[a].dO_ii F_vii -= np.dot(np.dot(F_niv.transpose(), Q_ni), dO_ii) F_av[a] += 2 * F_vii.real.trace(0, 1, 2) self.bd.comm.sum(F_av, 0) if self.bd.comm.rank == 0: self.kpt_comm.sum(F_av, 0) def estimate_memory(self, mem): FDPWWaveFunctions.estimate_memory(self, mem) self.kin.estimate_memory(mem.subnode('Kinetic operator'))
lmax = 2 b = 8.0 m = (lmax + 1)**2 gd = GridDescriptor([n, n, n], [a, a, a]) r = np.linspace(0, rc, 200) g = np.exp(-(r / rc * b)**2) splines = [Spline(l=l, rmax=rc, f_g=g) for l in range(lmax + 1)] c = LFC(gd, [splines]) c.set_positions([(0, 0, 0)]) psi = gd.zeros(m) d0 = c.dict(m) if 0 in d0: d0[0] = np.identity(m) c.add(psi, d0) d1 = c.dict(m, derivative=True) c.derivative(psi, d1) class TestSetup(Setup): l_j = range(lmax + 1) nj = lmax + 1 ni = m def __init__(self): pass rgd = EquidistantRadialGridDescriptor(r[1], len(r)) g = [np.exp(-(r / rc * b)**2) * r**l for l in range(lmax + 1)] d2 = TestSetup().get_derivative_integrals(rgd, g, np.zeros_like(g)) if 0 in d1: print abs(d1[0] - d2).max() assert abs(d1[0] - d2).max() < 2e-6