Beispiel #1
0
def _other_dpss_method(N, NW, Kmax):
    """Returns the Discrete Prolate Spheroidal Sequences of orders [0,Kmax-1]
    for a given frequency-spacing multiple NW and sequence length N. 

    See dpss function that is the official version. This version is indepedant 
    of the C code and relies on Scipy function. However, it is slower by a factor 3

    Tridiagonal form of DPSS calculation from:

    """
    # here we want to set up an optimization problem to find a sequence
    # whose energy is maximally concentrated within band [-W,W].
    # Thus, the measure lambda(T,W) is the ratio between the energy within
    # that band, and the total energy. This leads to the eigen-system
    # (A - (l1)I)v = 0, where the eigenvector corresponding to the largest
    # eigenvalue is the sequence with maximally concentrated energy. The
    # collection of eigenvectors of this system are called Slepian sequences,
    # or discrete prolate spheroidal sequences (DPSS). Only the first K,
    # K = 2NW/dt orders of DPSS will exhibit good spectral concentration
    # [see http://en.wikipedia.org/wiki/Spectral_concentration_problem]
    
    # Here I set up an alternative symmetric tri-diagonal eigenvalue problem
    # such that
    # (B - (l2)I)v = 0, and v are our DPSS (but eigenvalues l2 != l1)
    # the main diagonal = ([N-1-2*t]/2)**2 cos(2PIW), t=[0,1,2,...,N-1]
    # and the first off-diangonal = t(N-t)/2, t=[1,2,...,N-1]
    # [see Percival and Walden, 1993]
    from scipy import linalg as la
    Kmax = int(Kmax)
    W = float(NW)/N
    ab = np.zeros((2,N), 'd')
    nidx = np.arange(N)
    ab[0,1:] = nidx[1:]*(N-nidx[1:])/2.
    ab[1] = ((N-1-2*nidx)/2.)**2 * np.cos(2*np.pi*W)
    # only calculate the highest Kmax-1 eigenvectors
    l,v = la.eig_banded(ab, select='i', select_range=(N-Kmax, N-1))
    dpss = v.transpose()[::-1]

    # By convention (Percival and Walden, 1993 pg 379)
    # * symmetric tapers (k=0,2,4,...) should have a positive average.
    # * antisymmetric tapers should begin with a positive lobe
    fix_symmetric = (dpss[0::2].sum(axis=1) < 0)
    for i, f in enumerate(fix_symmetric):
        if f:
            dpss[2*i] *= -1
    fix_skew = (dpss[1::2,1] < 0)
    for i, f in enumerate(fix_skew):
        if f:
            dpss[2*i+1] *= -1

    # Now find the eigenvalues of the original 
    # Use the autocovariance sequence technique from Percival and Walden, 1993
    # pg 390
    # XXX : why debias false? it's all messed up o.w., even with means
    # on the order of 1e-2
    acvs = _autocov(dpss, debias=False) * N
    r = 4*W*np.sinc(2*W*nidx)
    r[0] = 2*W
    eigvals = np.dot(acvs, r)
    return dpss, eigvals
Beispiel #2
0
 def solve(self, n_eigvals=20):
     print '[S1d_H] start solving'
     t_start = time.clock()
     self.eigvals, self.eigvects = eig_banded(self.Hbanded, select='i',
                                              select_range=[0, n_eigvals])
     t_end = time.clock()
     print '[S1d_H] end solving (%.2f sec)' % (t_end - t_start)
Beispiel #3
0
def lanczos_tridiag_eig(alpha, beta, check_finite=True):
    """Find the eigen-values and -vectors of the Lanczos triadiagonal matrix.

    Parameters
    ----------
    alpha : array of float
        The diagonal.
    beta : array of float
        The k={-1, 1} off-diagonal. Only first ``len(alpha) - 1`` entries used.
    """
    Tk_banded = np.empty((2, alpha.size))
    Tk_banded[1, -1] = 0.0  # sometimes can get nan here? -> breaks eig_banded
    Tk_banded[0, :] = alpha
    Tk_banded[1, :beta.size] = beta

    try:
        tl, tv = scla.eig_banded(Tk_banded,
                                 lower=True,
                                 check_finite=check_finite)

    # sometimes get no convergence -> use dense hermitian method
    except scla.LinAlgError:  # pragma: no cover
        tl, tv = np.linalg.eigh(np.diag(alpha) +
                                np.diag(beta[:alpha.size - 1], -1),
                                UPLO='L')

    return tl, tv
Beispiel #4
0
def _other_dpss_method(N, NW, Kmax):
    """Returns the Discrete Prolate Spheroidal Sequences of orders [0,Kmax-1]
    for a given frequency-spacing multiple NW and sequence length N. 

    See dpss function that is the official version. This version is indepedant 
    of the C code and relies on Scipy function. However, it is slower by a factor 3

    Tridiagonal form of DPSS calculation from:

    """
    # here we want to set up an optimization problem to find a sequence
    # whose energy is maximally concentrated within band [-W,W].
    # Thus, the measure lambda(T,W) is the ratio between the energy within
    # that band, and the total energy. This leads to the eigen-system
    # (A - (l1)I)v = 0, where the eigenvector corresponding to the largest
    # eigenvalue is the sequence with maximally concentrated energy. The
    # collection of eigenvectors of this system are called Slepian sequences,
    # or discrete prolate spheroidal sequences (DPSS). Only the first K,
    # K = 2NW/dt orders of DPSS will exhibit good spectral concentration
    # [see http://en.wikipedia.org/wiki/Spectral_concentration_problem]
    
    # Here I set up an alternative symmetric tri-diagonal eigenvalue problem
    # such that
    # (B - (l2)I)v = 0, and v are our DPSS (but eigenvalues l2 != l1)
    # the main diagonal = ([N-1-2*t]/2)**2 cos(2PIW), t=[0,1,2,...,N-1]
    # and the first off-diangonal = t(N-t)/2, t=[1,2,...,N-1]
    # [see Percival and Walden, 1993]
    from scipy import linalg as la
    Kmax = int(Kmax)
    W = float(NW)/N
    ab = np.zeros((2,N), 'd')
    nidx = np.arange(N)
    ab[0,1:] = nidx[1:]*(N-nidx[1:])/2.
    ab[1] = ((N-1-2*nidx)/2.)**2 * np.cos(2*np.pi*W)
    # only calculate the highest Kmax-1 eigenvectors
    l,v = la.eig_banded(ab, select='i', select_range=(N-Kmax, N-1))
    dpss = v.transpose()[::-1]

    # By convention (Percival and Walden, 1993 pg 379)
    # * symmetric tapers (k=0,2,4,...) should have a positive average.
    # * antisymmetric tapers should begin with a positive lobe
    fix_symmetric = (dpss[0::2].sum(axis=1) < 0)
    for i, f in enumerate(fix_symmetric):
        if f:
            dpss[2*i] *= -1
    fix_skew = (dpss[1::2,1] < 0)
    for i, f in enumerate(fix_skew):
        if f:
            dpss[2*i+1] *= -1

    # Now find the eigenvalues of the original 
    # Use the autocovariance sequence technique from Percival and Walden, 1993
    # pg 390
    # XXX : why debias false? it's all messed up o.w., even with means
    # on the order of 1e-2
    acvs = _autocov(dpss, debias=False) * N
    r = 4*W*np.sinc(2*W*nidx)
    r[0] = 2*W
    eigvals = np.dot(acvs, r)
    return dpss, eigvals
Beispiel #5
0
def groundstate(pm, H):
    r"""Calculates the ground-state of the system for a given potential.

    .. math:: 
    
        \hat{H} \phi_{j} = \varepsilon_{j} \phi_{j}

    parameters
    ----------
    pm : object
        Parameters object
    H : array_like
        2D array of the Hamiltonian matrix in band form, indexed as H[band,space_index]

    returns
    -------
    density : array_like
        1D array of the electron density, indexed as density[space_index]
    orbitals : array_like
        2D array of the Kohn-Sham orbitals, index as orbitals[space_index,orbital_number]
    eigenvalues : array_like
        1D array of the Kohn-Sham eigenvalues, indexed as eigenvalues[orbital_number]
    """
    # Solve the Kohn-Sham equations
    eigenvalues, orbitals = spla.eig_banded(H, lower=True)
 
    # Normalise the orbitals
    orbitals /= np.sqrt(pm.space.delta)

    # Calculate the electron density
    density = electron_density(pm, orbitals)

    return density, orbitals, eigenvalues
Beispiel #6
0
def non_approx(pm):
    r"""Calculates the two lowest non-interacting eigenstates of the system. These can then be 
    expressed in Slater determinant form as an approximation to the exact many-electron wavefunction.

    .. math:: 

        \bigg(-\frac{1}{2} \frac{d^{2}}{dx^{2}} + V_{\mathrm{ext}}(x) \bigg) \phi_{j}(x) 
        = \varepsilon_{j} \phi_{j}(x)

    parameters
    ----------
    pm : object
        Parameters object

    returns array_like and array_like
        1D array of the 1st non-interacting eigenstate, indexed as eigenstate_1[space_index]. 
        1D array of the 2nd non-interacting eigenstate, indexed as eigenstate_2[space_index].
    """
    # Construct the single-electron Hamiltonian
    K = NON.construct_K(pm)
    H = copy.copy(K)
    H[0,:] += pm.space.v_ext[:]

    # Solve the single-electron TISE
    eigenvalues, eigenfunctions = spla.eig_banded(H, lower=True, select='i', select_range=(0,1))

    # Take the two lowest eigenstates
    eigenstate_1 = eigenfunctions[:,0]
    eigenstate_2 = eigenfunctions[:,1]

    return eigenstate_1, eigenstate_2
def gauss_legendre(n):
    # http://www.scientificpython.net/1/post/2012/04/gausslegendre1.html
    k=np.arange(1.0,n)       
    a_band = np.zeros((2,n)) 
    a_band[1,0:n-1] = k/np.sqrt(4*k*k-1) 
    x,V = linalg.eig_banded(a_band,lower=True) 
    w=2*np.real(np.power(V[0,:],2)) 
    return x, w
Beispiel #8
0
	def computeEigenFunctions(self,jRange=None):
		if jRange: sel='i'
		else: sel ='a' 
		#sel = 'a'
		lambdas,basis = eig_banded(self.bandedMatrix,lower=True, check_finite=False,
					overwrite_a_band=True, select=sel, select_range = jRange)
		basis/=np.sqrt(self.dx) #For normalization
		return lambdas,basis
Beispiel #9
0
def gauss_legendre(n):
    # http://www.scientificpython.net/1/post/2012/04/gausslegendre1.html
    k = np.arange(1.0, n)
    a_band = np.zeros((2, n))
    a_band[1, 0:n - 1] = k / np.sqrt(4 * k * k - 1)
    x, V = linalg.eig_banded(a_band, lower=True)
    w = 2 * np.real(np.power(V[0, :], 2))
    return x, w
Beispiel #10
0
 def computeEigenFunctions(self, jRange=None):
     if jRange: sel = 'i'
     else: sel = 'a'
     #sel = 'a'
     lambdas, basis = eig_banded(self.bandedMatrix,
                                 lower=True,
                                 check_finite=False,
                                 overwrite_a_band=True,
                                 select=sel,
                                 select_range=jRange)
     basis /= np.sqrt(self.dx)  #For normalization
     return lambdas, basis
Beispiel #11
0
def diag_banded(A, n=2):
    """A is in upper banded form.
        Returns the smallest n eigenvalue and its corresponding eigenvector.
        """
    try:
        from scipy.linalg import eig_banded
        info("Import of scipy successful", verbosity.high)
    except ImportError:
        raise ValueError(" ")

    d = eig_banded(A, select='i', select_range=(0, n), eigvals_only=True, check_finite=False)

    return d
Beispiel #12
0
 def get_evals_evecs(self):
     """
     get bound states
     """
     H = self.create_H_banded()
     evals, evecs = eig_banded(H,
                               lower=True,
                               select="v",
                               select_range=(self.pot.min(),
                                             self.pot.max()))
     # fix the eigenvector norm to the position space integral
     evecs /= np.sqrt(self.dx)
     return evals, evecs
Beispiel #13
0
def compute_spectrum(hess_vec_prod, size, method="exact", max_steps=10):
    """Returns an array containing sorted eigenvalues and eigenvectors.
       hess_vec_prod takes a vector only"""
    # The slow, N^3 way.
    if method == "exact":
        hessian = matrix_from_mvp(hess_vec_prod, size)
        return np.linalg.eigvals(hessian)
    elif method == "approx":
        a, b = lanczos_iteration(hess_vec_prod, size, max_steps)
        banded = np.concatenate((b[None, :], a[None, :]), axis=0)
        eigvals, eigvects = eig_banded(banded)
        return subset_to_full(eigvals, eigvects[0, :]**2, size)
    else:
        raise ValueError("Unrecognized method {0}".format(method))
Beispiel #14
0
    def h_step(self, H0, H1):
        r"""Performs one minimisation step

        parameters
        ----------
        H0: array_like
          input Hamiltonian to be mixed (banded form)
        H1: array_like
          output Hamiltonian to be mixed (banded form)

        returns
        -------
        H: array_like
          mixed hamiltonian (banded form)
        """
        ## TODO: implement analytic derivative
        #dE_dtheta_0 = 2 * np.sum(self.braket(dirs, H, wfs).real)
        # For the moment, we simply fit the parabola through 3 points
        npt = 3
        lambdas = np.linspace(0, 1, npt)
        energies = np.zeros(npt)

        # self-consistent variant
        for i in range(npt):
            l = lambdas[i]
            Hl = (1 - l) * H0 + l * H1
            enl, wfsl = spla.eig_banded(Hl, lower=True)
            energies[i] = self.total_energy(wfsl)

        # improve numerical stability
        energies -= energies[0]

        p = np.polyfit(lambdas, energies, 2)
        a, b, c = p
        l = -b / (2 * a)

        # don't want step to get too large
        l = np.minimum(1, l)

        #import matplotlib.pyplot as plt
        #fig, axs = plt.subplots(1,1)
        #plt.plot(lambdas, energies)
        ##axs.set_ylim(np.min(total_energies), np.max(total_energies))
        #plt.show()

        Hl = (1 - l) * H0 + l * H1

        return Hl
Beispiel #15
0
def RealWalk(t=7):
  '''Generate the unitary corresponding to our quantum walk evolved to a time t
t       : evolution time
returns : 21x21 (unitary) array'''
  offdiag=[0.466,0.54,0.504,0.515,0.494,0.451,0.508,0.511,0.483,0.505,0.547,\
0.471,0.493,0.499,0.447,0.467,0.544,0.524,0.51,0.503]
  h=numpy.zeros((2,21))
  for i in range(21):
    h[1,i]=2.122
  for i in range(20):
    h[0,i+1]=offdiag[i]
  evals,evecs=linalg.eig_banded(h)
  diag=numpy.zeros((21,21),dtype=complex)
  for i,z in enumerate(numpy.exp(-1j*evals*t)):
    diag[i,i]=z
  return numpy.dot(evecs, numpy.dot(diag, evecs.T.conjugate()))
Beispiel #16
0
    def solve_eigen_problem(self, A, B, solver):
        """Solve the eigen problem"""
        N = A.testfunction[0].N
        s = A.testfunction[0].slice()
        self.V = np.zeros((N, N))
        self.lmbda = np.ones(N)
        if solver == 0:
            self.lmbda[s], self.V[s, s] = scipy_la.eigh(A.diags().toarray(),
                                                        B.diags().toarray())

        elif solver == 1:
            #self.lmbda[s], self.V[s, s] = scipy_la.eigh(B.diags().toarray())
            a = np.zeros((3, N-2))
            a[0, :] = B[0]
            a[2, :-2] = B[2]
            self.lmbda[s], self.V[s, s] = scipy_la.eig_banded(a, lower=True)
def interaction_matrix_div_E0_squared(Jmax,K,M,KMsign,delta_alpha,alpha_perp,diagonalize=True):
     ''' The interaction matrix <JKM|V|J'KM> divided by E_0^2
     (the electric field amplitude squared).
     E_0 is just a constant, so the same interaction matrix
     can be used for all laser pulses by just scaling this one
     with E_0^2 = 2*I/(c*epsilon_0) times a conversion factor
     between polarizability volume and polarizability.
     
     Input is the Jmax, the maximum J state,
     K and M for the state, along with KMsign, the relative sign between K and M,
     and delta_alpha and alpha_perp, the components of the polarizability
     tensor. 
     '''

     try:
         cache = interaction_matrix_div_E0_squared.cache;
     except AttributeError:
         cache = dict();
         interaction_matrix_div_E0_squared.cache = cache;
     try:
         return cache[(Jmax,K,M,KMsign,delta_alpha,alpha_perp,diagonalize)];
     except KeyError:
         pass;


     (U, U0, U1, U2) = MeanCos2Matrix(Jmax,K,M,KMsign);
     
     Jmin = max(K,M);

     tr = numpy.ones(Jmax+1); # Construct identity matrix,
     tr[0:Jmin] = 0;          # but with 0...Jmin zeroed

     V0 = -(delta_alpha*U0+alpha_perp*tr)/4;
     V1 = -delta_alpha*U1/4;
     V2 = -delta_alpha*U2/4;

     if (diagonalize):
         cat = numpy.concatenate;
         a = numpy.vstack((cat(([0,0],V2)),cat(([0],V1)),V0));
         eig,vec = linalg.eig_banded(a);
         vec = numpy.ascontiguousarray(vec);
         V = (V0, V1, V2, eig, vec);
     else:
         V = (V0, V1, V2);

     cache[(Jmax,K,M,KMsign,delta_alpha,alpha_perp,diagonalize)] = V;
     return V;
Beispiel #18
0
    def eigen(self, eigvals_only=False, overwrite_a_band=False, select='a',
              select_range=None, max_ev=0):
        """
        Solve real symmetric or complex hermitian band matrix
        eigenvalue problem.

        Uses scipy.linalg.eig_banded function.
        """
        from scipy.linalg import eig_banded

        w, v = eig_banded(self.ab, lower=self.lower,
                          eigvals_only=eigvals_only,
                          overwrite_a_band=overwrite_a_band,
                          select=select,
                          select_range=select_range,
                          max_ev=max_ev)
        return EigendecompositionOperator(w=w, v=v)
Beispiel #19
0
    def test_eig_banded(self):
        """Compare eigenvalues and eigenvectors of eig_banded
           with those of linalg.eig. """
        w_sym, evec_sym = eig_banded(self.bandmat_sym)
        evec_sym_ = evec_sym[:, argsort(w_sym.real)]
        assert_array_almost_equal(sort(w_sym), self.w_sym_lin)
        assert_array_almost_equal(abs(evec_sym_), abs(self.evec_sym_lin))

        w_herm, evec_herm = eig_banded(self.bandmat_herm)
        evec_herm_ = evec_herm[:, argsort(w_herm.real)]
        assert_array_almost_equal(sort(w_herm), self.w_herm_lin)
        assert_array_almost_equal(abs(evec_herm_), abs(self.evec_herm_lin))

        # extracting eigenvalues with respect to an index range
        ind1 = 2
        ind2 = 6
        w_sym_ind, evec_sym_ind = eig_banded(self.bandmat_sym,
                                             select='i',
                                             select_range=(ind1, ind2))
        assert_array_almost_equal(sort(w_sym_ind),
                                  self.w_sym_lin[ind1:ind2 + 1])
        assert_array_almost_equal(abs(evec_sym_ind),
                                  abs(self.evec_sym_lin[:, ind1:ind2 + 1]))

        w_herm_ind, evec_herm_ind = eig_banded(self.bandmat_herm,
                                               select='i',
                                               select_range=(ind1, ind2))
        assert_array_almost_equal(sort(w_herm_ind),
                                  self.w_herm_lin[ind1:ind2 + 1])
        assert_array_almost_equal(abs(evec_herm_ind),
                                  abs(self.evec_herm_lin[:, ind1:ind2 + 1]))

        # extracting eigenvalues with respect to a value range
        v_lower = self.w_sym_lin[ind1] - 1.0e-5
        v_upper = self.w_sym_lin[ind2] + 1.0e-5
        w_sym_val, evec_sym_val = eig_banded(self.bandmat_sym,
                                             select='v',
                                             select_range=(v_lower, v_upper))
        assert_array_almost_equal(sort(w_sym_val),
                                  self.w_sym_lin[ind1:ind2 + 1])
        assert_array_almost_equal(abs(evec_sym_val),
                                  abs(self.evec_sym_lin[:, ind1:ind2 + 1]))

        v_lower = self.w_herm_lin[ind1] - 1.0e-5
        v_upper = self.w_herm_lin[ind2] + 1.0e-5
        w_herm_val, evec_herm_val = eig_banded(self.bandmat_herm,
                                               select='v',
                                               select_range=(v_lower, v_upper))
        assert_array_almost_equal(sort(w_herm_val),
                                  self.w_herm_lin[ind1:ind2 + 1])
        assert_array_almost_equal(abs(evec_herm_val),
                                  abs(self.evec_herm_lin[:, ind1:ind2 + 1]))
Beispiel #20
0
def _gauss_nodes_weights(a,b):
    r"""Calculate the nodes and weights for given 
    recursion coefficients assuming a normalized 
    weights functions.
    
    
    see Walter Gautschi, Algorithm 726: ORTHPOL; 
    a Package of Routines for Generating Orthogonal 
    Polynomials and Gauss-type Quadrature Rules, 1994 
    """
    assert len(a) == len(b)
    
    a_band = np.vstack((np.sqrt(b),a))
    w, v = eig_banded(a_band)
    
    nodes = w                  # eigenvalues
    weights = b[0] * v[0,:]**2 # first component of each eigenvector
                        # the prefactor b[0] from the original paper
                        # accounts for the weights of unnormalized weight functions
    return nodes, weights
Beispiel #21
0
def _gauss_nodes_weights(a,b):
    r"""Calculate the nodes and weights for given 
    recursion coefficients assuming a normalized 
    weights functions.
    
    
    see Walter Gautschi, Algorithm 726: ORTHPOL; 
    a Package of Routines for Generating Orthogonal 
    Polynomials and Gauss-type Quadrature Rules, 1994 
    """
    assert len(a) == len(b)
    
    a_band = np.vstack((np.sqrt(b),a))
    w, v = eig_banded(a_band)
    
    nodes = w                  # eigenvalues
    weights = b[0] * v[0,:]**2 # first component of each eigenvector
                        # the prefactor b[0] from the original paper
                        # accounts for the weights of unnormalized weight functions
    return nodes, weights
    def test_eig_banded(self):
        """Compare eigenvalues and eigenvectors of eig_banded
           with those of linalg.eig. """
        w_sym, evec_sym = eig_banded(self.bandmat_sym)
        evec_sym_ = evec_sym[:,argsort(w_sym.real)]
        assert_array_almost_equal(sort(w_sym), self.w_sym_lin)
        assert_array_almost_equal(abs(evec_sym_), abs(self.evec_sym_lin))

        w_herm, evec_herm = eig_banded(self.bandmat_herm)
        evec_herm_ = evec_herm[:,argsort(w_herm.real)]
        assert_array_almost_equal(sort(w_herm), self.w_herm_lin)
        assert_array_almost_equal(abs(evec_herm_), abs(self.evec_herm_lin))

        # extracting eigenvalues with respect to an index range
        ind1 = 2
        ind2 = 6
        w_sym_ind, evec_sym_ind = eig_banded(self.bandmat_sym,
                                    select='i', select_range=(ind1, ind2) )
        assert_array_almost_equal(sort(w_sym_ind),
                                  self.w_sym_lin[ind1:ind2+1])
        assert_array_almost_equal(abs(evec_sym_ind),
                                  abs(self.evec_sym_lin[:,ind1:ind2+1]) )

        w_herm_ind, evec_herm_ind = eig_banded(self.bandmat_herm,
                                    select='i', select_range=(ind1, ind2) )
        assert_array_almost_equal(sort(w_herm_ind),
                                  self.w_herm_lin[ind1:ind2+1])
        assert_array_almost_equal(abs(evec_herm_ind),
                                  abs(self.evec_herm_lin[:,ind1:ind2+1]) )

        # extracting eigenvalues with respect to a value range
        v_lower = self.w_sym_lin[ind1] - 1.0e-5
        v_upper = self.w_sym_lin[ind2] + 1.0e-5
        w_sym_val, evec_sym_val = eig_banded(self.bandmat_sym,
                                select='v', select_range=(v_lower, v_upper) )
        assert_array_almost_equal(sort(w_sym_val),
                                  self.w_sym_lin[ind1:ind2+1])
        assert_array_almost_equal(abs(evec_sym_val),
                                  abs(self.evec_sym_lin[:,ind1:ind2+1]) )

        v_lower = self.w_herm_lin[ind1] - 1.0e-5
        v_upper = self.w_herm_lin[ind2] + 1.0e-5
        w_herm_val, evec_herm_val = eig_banded(self.bandmat_herm,
                                select='v', select_range=(v_lower, v_upper) )
        assert_array_almost_equal(sort(w_herm_val),
                                  self.w_herm_lin[ind1:ind2+1])
        assert_array_almost_equal(abs(evec_herm_val),
                                  abs(self.evec_herm_lin[:,ind1:ind2+1]) )
Beispiel #23
0
def nnls_solveh_banded(S, B, X0, niter=50):

    # Number of timebins and units.
    nt = S.shape[1]
    nn = B.shape[1]

    # On first iteration, warm-start from projected least-squares.
    if X0 is None:
        X0 = np.maximum(0, solveh_banded(S, B))

    # Determine Lipshitz constant
    w = eig_banded(S,
                   lower=False,
                   select='i',
                   select_range=(nt - 1, nt - 1),
                   eigvals_only=True)[0]

    # Run projected gradient descent in parallel across neurons.
    _parallel_proj_grad(S, B, X0, 1 / w, niter)

    return X0
Beispiel #24
0
 def svd_eye_minus_hat_matrix(self):
     """
     Following Craven & Wahba find the singular value decomposition of 
         F = D Q R^{-1/2} 
     This function returns the non-zero singular values S and the
     corresponding left singular vectors in U, satisfying
         I - Hp = D U [ si**2 / ( 6(1-p) si**2 + p ) ] U.T D**(-1)
     where si is the ith singular value.
     """
     # TODO: is it indeed faster to take the non-sparse inverse?!
     method = 4
     if method == 0:
         sqrt_invR = sqrtm(spla.inv(self.R).A)
     elif method == 1:
         sqrt_invR = sqrtm(la.inv(self.R.todense()))
     elif method == 2:
         invR = la.inv(self.R.todense())
         eR, oR = la.eigh(invR)
         sqrt_invR = oR.dot(np.diag(np.sqrt(eR))).dot(oR.T)
     elif method == 3:
         eR, oR = la.eigh(self.R.todense())
         sqrt_invR = oR.dot(np.diag(1. / np.sqrt(eR))).dot(oR.T)
     elif method == 4:
         # TODO:
         #     deal with the error
         #     File "splines.py", line 378, in svd_eye_minus_hat_matrix
         #     eR, oR = la.eig_banded(self.R.data[self.R.offsets>=0][::-1])
         #     File "/ph2users/eldada/lib/anaconda/lib/python2.7/site-packages/scipy/linalg/decomp.py",
         #     line 563, in eig_banded
         #     raise LinAlgError("eig algorithm did not converge")
         try:
             eR, oR = la.eig_banded(self.R.data[self.R.offsets >= 0][::-1])
             sqrt_invR = oR.dot(np.diag(1. / np.sqrt(eR))).dot(oR.T)
         except LinAlgError:
             # if eig_banded fails try the eigh
             eR, oR = la.eigh(self.R.todense())
             sqrt_invR = oR.dot(np.diag(1. / np.sqrt(eR))).dot(oR.T)
     U, S, VT = la.svd(self.D * self.Q * sqrt_invR, full_matrices=False)
     return U, S
Beispiel #25
0
def _gauss_from_coefficients_numpy(alpha, beta):
    # assert isinstance(alpha, numpy.ndarray)
    # assert isinstance(beta, numpy.ndarray)
    alpha = alpha.astype(numpy.float64)
    beta = beta.astype(numpy.float64)

    x, V = eig_banded(numpy.vstack((numpy.sqrt(beta), alpha)), lower=False)
    w = beta[0] * scipy.real(scipy.power(V[0, :], 2))
    # eigh_tridiagonal is only available from scipy 1.0.0, and has problems
    # with precision. TODO find out how/why/what
    # try:
    #     from scipy.linalg import eigh_tridiagonal
    # except ImportError:
    #     # Use eig_banded
    #     x, V = \
    #         eig_banded(numpy.vstack((numpy.sqrt(beta), alpha)), lower=False)
    #     w = beta[0]*scipy.real(scipy.power(V[0, :], 2))
    # else:
    #     x, V = eigh_tridiagonal(alpha, numpy.sqrt(beta[1:]))
    #     w = beta[0] * V[0, :]**2

    return x, w
Beispiel #26
0
    def eigen(self,
              eigvals_only=False,
              overwrite_a_band=False,
              select='a',
              select_range=None,
              max_ev=0):
        """
        Solve real symmetric or complex hermitian band matrix
        eigenvalue problem.

        Uses scipy.linalg.eig_banded function.
        """
        from scipy.linalg import eig_banded

        w, v = eig_banded(self.ab,
                          lower=self.lower,
                          eigvals_only=eigvals_only,
                          overwrite_a_band=overwrite_a_band,
                          select=select,
                          select_range=select_range,
                          max_ev=max_ev)
        return EigendecompositionOperator(w=w, v=v)
 def svd_eye_minus_hat_matrix(self):
     """
     Following Craven & Wahba find the singular value decomposition of 
         F = D Q R^{-1/2} 
     This function returns the non-zero singular values S and the
     corresponding left singular vectors in U, satisfying
         I - Hp = D U [ si**2 / ( 6(1-p) si**2 + p ) ] U.T D**(-1)
     where si is the ith singular value.
     """
     # TODO: is it indeed faster to take the non-sparse inverse?!
     method = 4
     if method==0:
         sqrt_invR = sqrtm(spla.inv(self.R).A)
     elif method==1:
         sqrt_invR = sqrtm(la.inv(self.R.todense()))
     elif method==2:
         invR = la.inv(self.R.todense())
         eR, oR = la.eigh(invR)
         sqrt_invR = oR.dot(np.diag(np.sqrt(eR))).dot(oR.T)
     elif method==3:
         eR, oR = la.eigh(self.R.todense())
         sqrt_invR = oR.dot(np.diag(1./np.sqrt(eR))).dot(oR.T)
     elif method==4:
         # TODO: 
         #     deal with the error
         #     File "splines.py", line 378, in svd_eye_minus_hat_matrix
         #     eR, oR = la.eig_banded(self.R.data[self.R.offsets>=0][::-1])
         #     File "/ph2users/eldada/lib/anaconda/lib/python2.7/site-packages/scipy/linalg/decomp.py",
         #     line 563, in eig_banded
         #     raise LinAlgError("eig algorithm did not converge")
         try:
             eR, oR = la.eig_banded(self.R.data[self.R.offsets>=0][::-1])
             sqrt_invR = oR.dot(np.diag(1./np.sqrt(eR))).dot(oR.T)
         except LinAlgError:
             # if eig_banded fails try the eigh
             eR, oR = la.eigh(self.R.todense())
             sqrt_invR = oR.dot(np.diag(1./np.sqrt(eR))).dot(oR.T)
     U, S, VT = la.svd(self.D * self.Q * sqrt_invR, full_matrices=False)
     return U,S
Beispiel #28
0
def solve_gsks_equations(pm, hamiltonian):
    r"""Solves the ground-state Kohn-Sham equations to find the ground-state
    Kohn-Sham eigenfunctions, energies and electron density.

    .. math::

        \hat{H}\phi_{j}(x) = \varepsilon_{j}\phi_{j}(x) \\
        n_{\mathrm{KS}}(x) = \sum_{j=1}^{N}|\phi_{j}(x)|^{2}

    parameters
    ----------
    pm : object
        Parameters object
    hamiltonian : array_like
        2D array of the Hamiltonian matrix, index as
        K[band,space_index]

    returns array_like and array_like and array_like
        2D array of the ground-state Kohn-Sham eigenfunctions, indexed as
        wavefunctions_ks[space_index,eigenfunction]. 1D array containing the
        ground-state Kohn-Sham eigenenergies, indexed as
        energies_ks[eigenenergies]. 1D array of the ground-state Kohn-Sham
        electron density, indexed as density_ks[space_index].
    """
    # Solve the Kohn-Sham equations
    energies_ks, wavefunctions_ks = spla.eig_banded(hamiltonian, lower=True)

    # Normalise the wavefunctions
    for j in range(pm.space.npt):
        norm = np.linalg.norm(wavefunctions_ks[:, j]) * pm.space.delta**0.5
        wavefunctions_ks[:, j] /= norm

    # Calculate the electron density
    density_ks = np.sum(wavefunctions_ks[:, :pm.sys.NE]**2,
                        axis=1,
                        dtype=np.float)

    return wavefunctions_ks, energies_ks, density_ks
Beispiel #29
0
def tensquad(order, dist):
    """Computes the tensor product quadrature rule with recurrence coefficients"""

    if not isinstance(dist, Joint): dist = Joint(dist)

    nbrPts = order + 1
    dim = dist[:].shape[0]
    J = np.zeros((2, nbrPts))
    points = np.zeros((nbrPts, dim))
    weights = np.zeros((nbrPts, dim))

    # Integration points and weights of each variable

    for i in range(dim):

        coef = dist[i].coef(nbrPts)
        J[1] = np.append(np.sqrt(coef[1][1:]), [0])
        J[0] = coef[0]

        val, vec = linalg.eig_banded(J, lower=1)
        weights[:, i] = vec[0, :]**2
        points[:, i] = val.real

    # Places the points and weights in the domain

    point = np.zeros((nbrPts**dim, dim))
    weight = np.zeros((nbrPts**dim, dim))

    for i in range(dim):

        v1 = np.repeat(points[:, i], nbrPts**(dim - 1 - i))
        v2 = np.repeat(weights[:, i], nbrPts**(dim - 1 - i))
        weight[:, i] = np.tile(v2, nbrPts**i)
        point[:, i] = np.tile(v1, nbrPts**i)

    weight = np.prod(weight, axis=1)
    point = np.squeeze(point)
    return point, weight
Beispiel #30
0
def gauss(alpha, beta):
    """ 
        Compute the Gauss nodes and weights from the recursion 
        coefficients associated with a set of orthogonal polynomials 

        Inputs: 
        alpha - recursion coefficients
        beta - recursion coefficients

        Outputs: 
        x - quadrature nodes		
        w - quadrature weights

        Adapted from the MATLAB code by Walter Gautschi
        http://www.cs.purdue.edu/archives/2002/wxg/codes/gauss.m
    """

    from scipy.linalg import eig_banded

    A = np.vstack((np.sqrt(beta), alpha))
    x, V = eig_banded(A, lower=False)
    w = beta[0] * sp.real(sp.power(V[0, :], 2))
    return x, w
Beispiel #31
0
def gauss(alpha,beta):
    """ 
        Compute the Gauss nodes and weights from the recursion 
        coefficients associated with a set of orthogonal polynomials 

        Inputs: 
        alpha - recursion coefficients
        beta - recursion coefficients

        Outputs: 
        x - quadrature nodes		
        w - quadrature weights

        Adapted from the MATLAB code by Walter Gautschi
        http://www.cs.purdue.edu/archives/2002/wxg/codes/gauss.m
    """
    
    from scipy.linalg import eig_banded

    A = np.vstack((np.sqrt(beta),alpha))
    x,V = eig_banded(A,lower=False) 
    w = beta[0]*sp.real(sp.power(V[0,:],2)) 
    return x,w
Beispiel #32
0
 def __init__(self, Nr, dr, mmax, queue, kernel):
     r_list = cell_centers(0.0, Nr * dr, Nr)
     A1 = 2 * np.pi * (r_list - 0.5 * dr)
     A2 = 2 * np.pi * (r_list + 0.5 * dr)
     V = np.pi * ((r_list + 0.5 * dr)**2 - (r_list - 0.5 * dr)**2)
     self.Lambda = np.sqrt(V)
     # Highest negative mode is never needed due to symmetry, so we have 2*mmax modes instead of 2*mmax+1.
     if mmax == 0:
         self.vals = np.zeros((Nr, 1))
     else:
         self.vals = np.zeros((Nr, 2 * mmax))
     # Save storage by only keeping eigenvectors for positive modes (negative modes are the same)
     self.Hi = np.zeros((Nr, Nr, mmax + 1))
     for m in range(0, mmax + 1):
         T1 = A1 / (dr * V)
         T2 = -(A1 + A2) / (dr * V) - (m / r_list)**2
         T3 = A2 / (dr * V)
         # Boundary conditions
         T2[0] += T1[0]
         T2[Nr - 1] -= T3[Nr - 1]
         # Symmetrize the matrix
         # S = Lambda * T * Lambda^-1
         # This is the root-volume weighting
         T1[1:] *= self.Lambda[1:] / self.Lambda[:-1]
         T3[:-1] *= self.Lambda[:-1] / self.Lambda[1:]
         a_band_upper = np.zeros((2, Nr))
         a_band_upper[
             0, :] = T1  # T3->T1 thanks to scipy packing and symmetry
         a_band_upper[1, :] = T2
         self.vals[:, m], self.Hi[:, :, m] = eig_banded(a_band_upper)
     # Set eigenvalues of negative modes (they are the same as corresponding positive modes)
     # Modes are packed in usual FFT fashion, so negative indices work as expected.
     for m in range(1, mmax):
         self.vals[:, -m] = self.vals[:, m]
     self.queue = queue
     self.kernel = kernel
# Create a new figure 
fig = plt.figure()
ax = fig.add_subplot(1,1,1)

frame = 0
while frame < frames:
    k2 = k2start + speed*frame 

    # Create effective Hamiltonian and solve
    A = np.zeros([2,levels], dtype=np.complex128)
    for n in range(levels):
        A[1,n] = V2*np.cos(q*b*k2/p + 2*np.pi*np.float(n)*q/p)
        if n < (levels-1):
            A[0,n+1] = V1*np.exp(np.complex(0.0,q*a*k1/p))
    [d, v] = eig_banded(A) 

    for i in range(levels):
        E[i] = d[i]
        State = v[:,i]
        StateAbs = abs(State)
        ns[i] = StateAbs.argmax()
        if frame == 0:
            prev_ns[i] = ns[i]
            positions[i] = ns[i]
        if frame > 0:
            ss[i] = ns[i] - prev_ns[i]
            if ss[i] > p/2.0:
                ss[i] = -(p - ss[i])
            elif ss[i] < -p/2.0:
                ss[i] = p + ss[i]
Beispiel #34
0
def slepian(M, width, sym=True):
    """Return a digital Slepian (DPSS) window.

    Used to maximize the energy concentration in the main lobe.  Also called
    the digital prolate spheroidal sequence (DPSS).

    Parameters
    ----------
    M : int
        Number of points in the output window. If zero or less, an empty
        array is returned.
    width : float
        Bandwidth
    sym : bool, optional
        When True (default), generates a symmetric window, for use in filter
        design.
        When False, generates a periodic window, for use in spectral analysis.

    Returns
    -------
    w : ndarray
        The window, with the maximum value always normalized to 1

    Examples
    --------
    Plot the window and its frequency response:

    >>> from scipy import signal
    >>> from scipy.fftpack import fft, fftshift
    >>> import matplotlib.pyplot as plt

    >>> window = signal.slepian(51, width=0.3)
    >>> plt.plot(window)
    >>> plt.title("Slepian (DPSS) window (BW=0.3)")
    >>> plt.ylabel("Amplitude")
    >>> plt.xlabel("Sample")

    >>> plt.figure()
    >>> A = fft(window, 2048) / (len(window)/2.0)
    >>> freq = np.linspace(-0.5, 0.5, len(A))
    >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max())))
    >>> plt.plot(freq, response)
    >>> plt.axis([-0.5, 0.5, -120, 0])
    >>> plt.title("Frequency response of the Slepian window (BW=0.3)")
    >>> plt.ylabel("Normalized magnitude [dB]")
    >>> plt.xlabel("Normalized frequency [cycles per sample]")

    """
    if M < 1:
        return np.array([])
    if M == 1:
        return np.ones(1, 'd')
    odd = M % 2
    if not sym and not odd:
        M = M + 1

    # our width is the full bandwidth
    width = width / 2
    # to match the old version 
    width = width / 2
    m = np.arange(M, dtype='d')
    H = np.zeros((2, M))
    H[0, 1:] = m[1:] * (M - m[1:]) / 2
    H[1, :] = ((M - 1 - 2 * m) / 2)**2 * np.cos(2 * np.pi * width)

    _, win = linalg.eig_banded(H, select='i', select_range=(M-1, M-1))
    win = win.ravel() / win.max()

    if not sym and not odd:
        win = win[:-1]
    return win
Beispiel #35
0
# Create a new figure
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)

frame = 0
while frame < frames:
    k2 = k2start + speed * frame

    # Create effective Hamiltonian and solve
    A = np.zeros([2, levels], dtype=np.complex128)
    for n in range(levels):
        A[1, n] = V2 * np.cos(q * b * k2 / p + 2 * np.pi * np.float(n) * q / p)
        if n < (levels - 1):
            A[0, n + 1] = V1 * np.exp(np.complex(0.0, q * a * k1 / p))
    [d, v] = eig_banded(A)

    for i in range(levels):
        E[i] = d[i]
        State = v[:, i]
        StateAbs = abs(State)
        ns[i] = StateAbs.argmax()
        if frame == 0:
            prev_ns[i] = ns[i]
            positions[i] = ns[i]
        if frame > 0:
            ss[i] = ns[i] - prev_ns[i]
            if ss[i] > p / 2.0:
                ss[i] = -(p - ss[i])
            elif ss[i] < -p / 2.0:
                ss[i] = p + ss[i]
Beispiel #36
0
def slepian(M, width, sym=True):
    """Return a digital Slepian (DPSS) window.

    Used to maximize the energy concentration in the main lobe.  Also called
    the digital prolate spheroidal sequence (DPSS).

    Parameters
    ----------
    M : int
        Number of points in the output window. If zero or less, an empty
        array is returned.
    width : float
        Bandwidth
    sym : bool, optional
        When True (default), generates a symmetric window, for use in filter
        design.
        When False, generates a periodic window, for use in spectral analysis.

    Returns
    -------
    w : ndarray
        The window, with the maximum value always normalized to 1

    Examples
    --------
    Plot the window and its frequency response:

    >>> from scipy import signal
    >>> from scipy.fftpack import fft, fftshift
    >>> import matplotlib.pyplot as plt

    >>> window = signal.slepian(51, width=0.3)
    >>> plt.plot(window)
    >>> plt.title("Slepian (DPSS) window (BW=0.3)")
    >>> plt.ylabel("Amplitude")
    >>> plt.xlabel("Sample")

    >>> plt.figure()
    >>> A = fft(window, 2048) / (len(window)/2.0)
    >>> freq = np.linspace(-0.5, 0.5, len(A))
    >>> response = 20 * np.log10(np.abs(fftshift(A / abs(A).max())))
    >>> plt.plot(freq, response)
    >>> plt.axis([-0.5, 0.5, -120, 0])
    >>> plt.title("Frequency response of the Slepian window (BW=0.3)")
    >>> plt.ylabel("Normalized magnitude [dB]")
    >>> plt.xlabel("Normalized frequency [cycles per sample]")

    """
    if M < 1:
        return np.array([])
    if M == 1:
        return np.ones(1, 'd')
    odd = M % 2
    if not sym and not odd:
        M = M + 1

    # our width is the full bandwidth
    width = width / 2
    # to match the old version
    width = width / 2
    m = np.arange(M, dtype='d')
    H = np.zeros((2, M))
    H[0, 1:] = m[1:] * (M - m[1:]) / 2
    H[1, :] = ((M - 1 - 2 * m) / 2)**2 * np.cos(2 * np.pi * width)

    _, win = linalg.eig_banded(H, select='i', select_range=(M - 1, M - 1))
    win = win.ravel() / win.max()

    if not sym and not odd:
        win = win[:-1]
    return win
Beispiel #37
0
def golub_welsch(order, dist, acc=100, **kws):
    """
Golub-Welsch algorithm for creating quadrature nodes and weights

Parameters
----------
order : int
    Quadrature order
dist : Dist
    Distribution nodes and weights are found for with
    `dim=len(dist)`
acc : int
    Accuracy used in discretized Stieltjes procedure.
    Will be increased by one for each itteration.

Returns
-------
x : numpy.array
    Optimal collocation nodes with `x.shape=(dim, order+1)`
w : numpy.array
    Optimal collocation weights with `w.shape=(order+1,)`

Examples
--------
>>> Z = cp.Normal()
>>> x, w = cp.golub_welsch(3, Z)
>>> print(x)
[[-2.33441422 -0.74196378  0.74196378  2.33441422]]
>>> print(w)
[ 0.04587585  0.45412415  0.45412415  0.04587585]

Multivariate
>>> Z = cp.J(cp.Uniform(), cp.Uniform())
>>> x, w = cp. golub_welsch(1, Z)
>>> print(x)
[[ 0.21132487  0.21132487  0.78867513  0.78867513]
 [ 0.21132487  0.78867513  0.21132487  0.78867513]]
>>> print(w)
[ 0.25  0.25  0.25  0.25]
    """

    o = np.array(order)*np.ones(len(dist), dtype=int)+1
    P, g, a, b = stieltjes(dist, np.max(o), acc=acc, retall=True, **kws)

    X, W = [], []
    dim = len(dist)

    for d in range(dim):
        if o[d]:
            A = np.empty((2, o[d]))
            A[0] = a[d, :o[d]]
            A[1, :-1] = np.sqrt(b[d, 1:o[d]])
            vals, vecs = eig_banded(A, lower=True)

            x, w = vals.real, vecs[0, :]**2
            indices = np.argsort(x)
            x, w = x[indices], w[indices]

        else:
            x, w = np.array([a[d, 0]]), np.array([1.])

        X.append(x)
        W.append(w)

    if dim==1:
        x = np.array(X).reshape(1,o[0])
        w = np.array(W).reshape(o[0])
    else:
        x = cp.utils.combine(X).T
        w = np.prod(cp.utils.combine(W), -1)

    assert len(x)==dim
    assert len(w)==len(x.T)
    return x, w
Beispiel #38
0
def golub_welsch(order, dist, acc=100, **kws):
    """
Golub-Welsch algorithm for creating quadrature nodes and weights

Parameters
----------
order : int
    Quadrature order
dist : Dist
    Distribution nodes and weights are found for with
    `dim=len(dist)`
acc : int
    Accuracy used in discretized Stieltjes procedure.
    Will be increased by one for each itteration.

Returns
-------
x : numpy.array
    Optimal collocation nodes with `x.shape=(dim, order+1)`
w : numpy.array
    Optimal collocation weights with `w.shape=(order+1,)`

Examples
--------
>>> Z = cp.Normal()
>>> x, w = cp.golub_welsch(3, Z)
>>> print x
[[-2.33441422 -0.74196378  0.74196378  2.33441422]]
>>> print w
[ 0.04587585  0.45412415  0.45412415  0.04587585]

Multivariate
>>> Z = cp.J(cp.Uniform(), cp.Uniform())
>>> x, w = cp. golub_welsch(1, Z)
>>> print x
[[ 0.21132487  0.21132487  0.78867513  0.78867513]
 [ 0.21132487  0.78867513  0.21132487  0.78867513]]
>>> print w
[ 0.25  0.25  0.25  0.25]
    """

    o = np.array(order) * np.ones(len(dist), dtype=int) + 1
    P, g, a, b = stieltjes(dist, np.max(o), acc=acc, retall=True, **kws)

    X, W = [], []
    dim = len(dist)

    for d in xrange(dim):
        if o[d]:
            A = np.empty((2, o[d]))
            A[0] = a[d, :o[d]]
            A[1, :-1] = np.sqrt(b[d, 1:o[d]])
            vals, vecs = eig_banded(A, lower=True)

            x, w = vals.real, vecs[0, :]**2
            indices = np.argsort(x)
            x, w = x[indices], w[indices]

            # p = P[-1][d]
            # dp = po.differential(p, po.basis(1,1,dim)[d])
            #
            # x = x - p(x)/dp(x)
            # x = x - p(x)/dp(x)
            # x = x - p(x)/dp(x)
            #
            # z = np.arange(dim)
            # arg = np.array([k*(z == d) for k in range(2*o[d]-3)])
            # b_ = dist.mom(arg.T)
            #
            # X_, r = np.meshgrid(x, np.arange(2*o[d]-3))
            # X_ = X_**r
            # w = np.linalg.lstsq(X_, b_)[0].flatten()
            # print "w", w.shape
            # print np.linalg.lstsq(X_, b_)[0]

        else:
            x, w = np.array([a[d, 0]]), np.array([1.])

        X.append(x)
        W.append(w)

    if dim == 1:
        x = np.array(X).reshape(1, o[0])
        w = np.array(W).reshape(o[0])
    else:
        x = combine(X).T
        w = np.prod(combine(W), -1)

    assert len(x) == dim
    assert len(w) == len(x.T)
    return x, w
Beispiel #39
0
def main(parameters):
    r"""Calculates the ground-state of the system. If the system is perturbed, the time evolution of 
    the perturbed system is then calculated.

    parameters
    ----------
    parameters : object
        Parameters object

    returns object
        Results object
    """
    # Array initialisations
    pm = parameters
    string = 'EXT: constructing arrays'
    pm.sprint(string, 1)
    pm.setup_space()

    # Construct the kinetic energy matrix
    K = construct_K(pm)

    # Construct the Hamiltonian matrix
    H = np.copy(K)
    H[0, :] += pm.space.v_ext[:]

    # Solve the Schroedinger equation
    string = 'EXT: calculating the ground-state density'
    pm.sprint(string, 1)
    energies, wavefunctions = spla.eig_banded(H, lower=True)

    # Normalise the wavefunctions
    wavefunctions /= np.sqrt(pm.space.delta)

    # Calculate the ground-state density
    density = np.absolute(wavefunctions[:, 0])**2

    # Calculate the ground-state energy
    energy = energies[0]
    string = 'EXT: ground-state energy = {:.5f}'.format(energy)
    pm.sprint(string, 1)

    # Save the quantities to file
    results = rs.Results()
    results.add(pm.space.v_ext, 'gs_ext_vxt')
    results.add(density, 'gs_ext_den')
    results.add(energy, 'gs_ext_E')
    results.add(wavefunctions.T, 'gs_ext_eigf')
    results.add(energies, 'gs_ext_eigv')
    if (pm.run.save):
        results.save(pm)

    # Propagate through real time
    if (pm.run.time_dependence):

        # Print to screen
        string = 'EXT: constructing arrays'
        pm.sprint(string, 1, newline=True)

        # Construct the Hamiltonian matrix
        H = np.copy(K)
        H[0, :] += pm.space.v_ext[:]
        if (pm.sys.im == 1):
            H = H.astype(np.cfloat)
        H[0, :] += pm.space.v_pert[:]

        # Construct the sparse matrices used in the Crank-Nicholson method
        A = construct_A(pm, H)
        C = 2.0 * sps.identity(pm.space.npt, dtype=np.cfloat) - A

        # Construct the time-dependent density array
        density = np.zeros((pm.sys.imax, pm.space.npt), dtype=np.float)

        # Save the ground-state
        wavefunction = wavefunctions[:, 0].astype(np.cfloat)
        density[0, :] = np.absolute(wavefunction[:])**2

        # Print to screen
        string = 'EXT: real time propagation'
        pm.sprint(string, 1)

        # Perform real time iterations
        for i in range(1, pm.sys.imax):

            # Construct the vector b
            b = C * wavefunction

            # Solve Ax=b
            wavefunction, info = spsla.cg(A,
                                          b,
                                          x0=wavefunction,
                                          tol=pm.ext.rtol_solver)

            # Normalise the wavefunction
            norm = npla.norm(wavefunction) * np.sqrt(pm.space.delta)
            wavefunction /= norm
            string = 'EXT: t = {:.5f}, normalisation = {}'.format(
                i * pm.sys.deltat, norm**2)
            pm.sprint(string, 1, newline=False)

            # Calculate the density
            density[i, :] = np.absolute(wavefunction[:])**2

        # Calculate the current density
        current_density = calculate_current_density(pm, density)

        # Save the quantities to file
        results.add(density, 'td_ext_den')
        results.add(current_density, 'td_ext_cur')
        results.add(pm.space.v_ext + pm.space.v_pert, 'td_ext_vxt')
        if (pm.run.save):
            results.save(pm)

    return results
Beispiel #40
0
def iwave_modes_banded(N2, dz, k=None):
    """
    !!! DOES NOT WORK!!!
    Calculates the eigenvalues and eigenfunctions to the internal wave eigenvalue problem:
    
    $$
    \left[ \frac{d^2}{dz^2} - \frac{1}{c_0} \bar{\rho}_z \right] \phi = 0
    $$
    
    with boundary conditions 
    """

    nz = N2.shape[0]  # Remove the surface values
    if k is None:
        k = nz - 2

    dz2 = 1 / dz**2

    # Construct the LHS matrix, A
    A = np.vstack([-1*dz2*np.ones((nz,)),\
        2*dz2*np.ones((nz,)),\
        -1*dz2*np.ones((nz,)),\
    ])

    # BC's
    #A[0,0] = -1.
    #A[0,1] = 0.
    #A[-1,-1] = -1.
    #A[-1,-2] = 0.
    A[1, 0] = -1.
    A[2, 0] = 0.
    A[1, -1] = -1.
    A[0, -1] = 0.

    # Now convert from a generalized eigenvalue problem to
    #       A.v = lambda.B.v
    # a standard problem
    #       A.v = lambda.v
    # By multiply the LHS by inverse of B
    #       (B^-1.A).v = lambda.v
    # B^-1 = 1/N2 since B is diagonal
    A[0, :] /= N2
    A[1, :] /= N2
    A[2, :] /= N2

    w, phi = linalg.eig_banded(A)

    pdb.set_trace()

    ## Main diagonal
    #dd = 2*dz2*np.ones((nz,))

    #dd /= N2

    #dd[0] = -1
    #dd[-1] = -1

    ## Off diagonal
    #ee = -1*dz2*np.ones((nz-1,))
    #ee /= N2[0:-1]

    #ee[0] = 0
    #ee[-1] = 0

    ## Solve... (use scipy not numpy)
    #w, phi = linalg.eigh_tridiagonal(dd, ee )

    #####

    c = 1. / np.power(w, 0.5)  # since term is ... + N^2/c^2 \phi

    # Sort by the eigenvalues
    idx = np.argsort(c)[::-1]  # descending order

    ## Calculate the actual phase speed
    cn = np.real(c[idx])

    idxgood = ~np.isnan(cn)
    phisort = phi[:, idx]

    return np.real(phisort[:, idxgood]), np.real(cn[idxgood])