def d(self, p):
        """
		Lazily estimate d_p(A) ~= || A^p ||^(1/p) where ||.|| is the 1-norm.
		"""
        if p not in self._d:
            est = onenormest((self._a * aslinearoperator(self._A))**p)
            self._d[p] = est**(1.0 / p)
        return self._d[p]
    def d(self, p):
        """
        Lazily estimate d_p(A) ~= || A^p ||^(1/p) where ||.|| is the 1-norm.
        """
        if p not in self._d:
            matvec = lambda v: self._a * (self._A.dot(v) - self._mu * v)
            rmatvec = lambda v: _np.conj(self._a) * (self._A.H.dot(v) - _np.
                                                     conj(self._mu) * v)
            LO = LinearOperator(self._A.shape,
                                dtype=self._dtype,
                                matvec=matvec,
                                rmatvec=rmatvec)

            est = onenormest(LO**p)

            # est = onenormest((self._a * aslinearoperator(self._A))**p)
            self._d[p] = est**(1.0 / p)

        return self._d[p]
def _onenormest_m1_power(A, p, t=2, itmax=5, compute_v=False, compute_w=False):
    """
    Efficiently estimate the 1-norm of (A - I)^p.

    Parameters
    ----------
    A : ndarray
        Matrix whose 1-norm of a power is to be computed.
    p : int
        Non-negative integer power.
    t : int, optional
        A positive parameter controlling the tradeoff between
        accuracy versus time and memory usage.
        Larger values take longer and use more memory
        but give more accurate output.
    itmax : int, optional
        Use at most this many iterations.
    compute_v : bool, optional
        Request a norm-maximizing linear operator input vector if True.
    compute_w : bool, optional
        Request a norm-maximizing linear operator output vector if True.

    Returns
    -------
    est : float
        An underestimate of the 1-norm of the sparse matrix.
    v : ndarray, optional
        The vector such that ||Av||_1 == est*||v||_1.
        It can be thought of as an input to the linear operator
        that gives an output with particularly large norm.
    w : ndarray, optional
        The vector Av which has relatively large 1-norm.
        It can be thought of as an output of the linear operator
        that is relatively large in norm compared to the input.

    """
    return onenormest(
        _MatrixM1PowerOperator(A, p),
        t=t,
        itmax=itmax,
        compute_v=compute_v,
        compute_w=compute_w)
Exemple #4
0
def _onenormest_m1_power(A, p, t=2, itmax=5, compute_v=False, compute_w=False):
    """
    Efficiently estimate the 1-norm of (A - I)^p.

    Parameters
    ----------
    A : ndarray
        Matrix whose 1-norm of a power is to be computed.
    p : int
        Non-negative integer power.
    t : int, optional
        A positive parameter controlling the tradeoff between
        accuracy versus time and memory usage.
        Larger values take longer and use more memory
        but give more accurate output.
    itmax : int, optional
        Use at most this many iterations.
    compute_v : bool, optional
        Request a norm-maximizing linear operator input vector if True.
    compute_w : bool, optional
        Request a norm-maximizing linear operator output vector if True.

    Returns
    -------
    est : float
        An underestimate of the 1-norm of the sparse matrix.
    v : ndarray, optional
        The vector such that ||Av||_1 == est*||v||_1.
        It can be thought of as an input to the linear operator
        that gives an output with particularly large norm.
    w : ndarray, optional
        The vector Av which has relatively large 1-norm.
        It can be thought of as an output of the linear operator
        that is relatively large in norm compared to the input.

    """
    return onenormest(_MatrixM1PowerOperator(A, p),
                      t=t,
                      itmax=itmax,
                      compute_v=compute_v,
                      compute_w=compute_w)
Exemple #5
0
def py_zhexpv(v,
              A,
              anorm=None,
              wsp=None,
              iwsp=None,
              m=20,
              t=1.0,
              tol=0.0,
              return_work=False):
    A = aslinearoperator(A)

    v = v.astype(np.complex128, casting="safe", copy=False).ravel()

    n = v.shape[0]

    if A.shape[1] != A.shape[0]:
        raise ValueError("Expecting square LinearOperator.")
    if A.shape[1] != v.shape[0]:
        raise ValueError(
            "Dimension mismatch between LinearOperator and input vector.")
    if anorm is None:
        anorm = onenormest(A)
    if wsp is None:
        wsp = np.zeros(7 + n * (m + 2) + 5 * (m + 2) * (m + 2),
                       dtype=np.complex128)
    if iwsp is None:
        iwsp = np.zeros(m + 2, dtype=np.int32)

    if return_work:
        return dict(anorm=anorm, wsp=wsp, iwsp=iwsp, m=m, return_work=False)

    u, tol0, iflag0 = zhexpv(m, t, v, tol, anorm, wsp, iwsp, A.matvec, 0)

    if iflag0 > 0:
        raise ExpokitError(messages[iflag0])
    elif iflag0 < 0:
        raise ExpokitError("bad input arguments")

    return u
Exemple #6
0
def residual_gevp(A,B,la,evec):
        r"""
        :param A: left matrix
        :param B: right matrix 
        :param la: eigenvalues
        :param evec: eigenvectors
        :return: res - residual
        """
        
        n = la.shape[0]
        res = numpy.zeros(n,numpy.complex_)   
        for i in range(0, n):
            vec = evec[:,i:i+1]
            AB = A - la[i]*B 
            res[i] = linalg.norm(AB.dot(vec))
            #calculate relative residual
            if(sparse.issparse(AB)):
                 AB_norm=norm.onenormest(AB, t=3, itmax=5, compute_v=False, compute_w=False)
            else:
                 AB_norm=linalg.norm(AB)
                 
            res[i] = res[i]/(AB_norm*linalg.norm(vec)) 
        return res;
Exemple #7
0
def residual_qevp(M,C,K,la,evec):
        r"""
        :param M: Mass Matrix
        :param C: Damping Matrix
        :param K: Stiffness Matrix
        :param la: eigenvalues
        :param evec: eigenvectors
        :return: res - residual
        """
        
        n = la.shape[0]
        res = numpy.zeros(n,numpy.complex_)   
        for i in range(0, n):
            vec = evec[:,i:i+1]
            A = la[i]*la[i]*M + la[i]*C + K
            res[i] = linalg.norm(A.dot(vec))
            #calculate relative residual
            if(sparse.issparse(A)):
                 A_norm=norm.onenormest(A, t=3, itmax=5, compute_v=False, compute_w=False)
            else:
                 A_norm=linalg.norm(A)
            
            res[i] = res[i]/(A_norm*linalg.norm(vec))
        return res;             
Exemple #8
0
def shift_matrices(obj, m, c, k, tau):
    r"""
         
        :param obj: object of the class ``BrakeClass``
        :param m: Mass Matrix
        :param c: Damping Matrix
        :param k: Stiffness Matrix
        :param tau: Shift
        :return: M, C, K - Shifted Mass, Damping and Stiffness Matrix respectively
        
        Procedure::
        
         The M , C , K are obtained as follows:
        
          M = m
          C = 2 * tau * m + c
          K = tau_squared * m + tau * c + k

        """

    #object attributes used in the function
    LOG_LEVEL = obj.log_level
    logger_t = obj.logger_t
    logger_i = obj.logger_i

    if (LOG_LEVEL == 10):  #Debug Mode
        logger_i.debug("\n" + "\n" + "\n" +
                       'In shift matrices (shift_matrices.py)')
        logger_i.debug(
            '----------------------------------------------------------------')
        logger_i.debug('Shifting about the point ' + str(tau))

    M = m
    C = 2 * tau * m + c
    tau_squared = tau * tau
    K = tau_squared * m + tau * c + k

    if (LOG_LEVEL == 10):  #Debug Mode
        m_norm = norm.onenormest(M,
                                 t=3,
                                 itmax=5,
                                 compute_v=False,
                                 compute_w=False)
        c_norm = norm.onenormest(C,
                                 t=3,
                                 itmax=5,
                                 compute_v=False,
                                 compute_w=False)
        k_norm = norm.onenormest(K,
                                 t=3,
                                 itmax=5,
                                 compute_v=False,
                                 compute_w=False)

        logger_i.debug('Properties of shifted matrices')
        logger_i.debug("\n" + 'M ' + ' ' + 'No of nonzeros = ' + str(M.nnz) +
                       ' 1-Norm = ' + str(m_norm))
        logger_i.debug('C ' + ' ' + 'No of nonzeros = ' + str(C.nnz) +
                       ' 1-Norm = ' + str(c_norm))
        logger_i.debug('K ' + ' ' + 'No of nonzeros = ' + str(K.nnz) +
                       ' 1-Norm = ' + str(k_norm))

    return M, C, K
Exemple #9
0
 def GetConditionNumber(self,A):
     self.matrix_condition_number = onenormest(K_b)
     return self.matrix_condition_number
Exemple #10
0
def create_MCK(obj, sparse_list, omega):
        r"""
         
        :param obj: object of the class ``BrakeClass``
        :param sparse_list: a python list of matrices in Compressed Sparse Column format 
          of type '<type 'numpy.float64'>',
        :param omega: angular frequency
        :return: M - Mass Matrix, C - Damping Matrix, K - Stiffness Matrix
        :raises: Assemble_BadInputError, When a matrix in the list is not sparse
        :raises: Assemble_BadInputError, When a matrix in the list is not square
        :raises: Assemble_BadInputError, When the matrix  are not of the same size
        
        Procedure::
         
         The M , C , K are assembled as follows:
        
         - M = M1
         - C = D1+DR*(omegaRef/omega)+DG*(omega/omegaRef)
         - K = K1+KR+KGeo*math.pow((omega/omegaRef),2)

        """
        
        #object attributes used in the function
        LOG_LEVEL = obj.log_level
        logger_t = obj.logger_t
        logger_i = obj.logger_i
        omegaRef = obj.omegaRef
        fRef = obj.fRef
        
        #unittesting
        if len(sparse_list) != 8:
         raise Assemble_BadInputError('The sparse list is not of length 8')
        else:
         for i in range(0,len(sparse_list)):
                if(not scipy.sparse.issparse(sparse_list[i])):
                  raise Assemble_BadInputError('The list is not sparse')
                if (sparse_list[i].shape[0]!=sparse_list[i].shape[1]):
                  raise Assemble_BadInputError('The matrix is not square')
                if (sparse_list[i].shape[0]!=sparse_list[0].shape[0]):
                  raise Assemble_BadInputError('The matrix are not of the same size')

        if(LOG_LEVEL==10): #Debug Mode
                logger_i.debug("\n"+"\n"+"\n"+'In assemble matrices (assemble.py)')
                logger_i.debug('----------------------------------------------------------------') 

        #converting csc to csr format
        M1 = sparse_list[0].tocsr()
        D1 = sparse_list[1].tocsr()
        DG = sparse_list[2].tocsr()
        DR = sparse_list[3].tocsr()
        D4 = sparse_list[4].tocsr()
        K1 = sparse_list[5].tocsr()
        KR = sparse_list[6].tocsr()
        KGeo = sparse_list[7].tocsr()

        if(LOG_LEVEL==10): #Debug Mode
	  
          logger_i.debug('Matrices in CSC format converted to CSR')
	  
	  for i in range(0,len(sparse_list)):
		componentMatrix = sparse_list[i]
		normMatrix = norm.onenormest(componentMatrix.tocsr(), t=3, itmax=5, compute_v=False, compute_w=False)
		logger_i.debug(obj.data_file_list[i]+' '+obj.data_file_name[i]+' Nonzeros = '+str(componentMatrix.nnz)+' 1-Norm = '+str(normMatrix))


        #Old implementation from sarosh's code
        '''
        M = m
        C = c1+c2*(omega/omegaRef)+c3*((omegaRef/omega)-1)+c4/(2*math.pi*fRef)
        K = k1+k2+k3*(math.pow((omega/omegaRef),2)-1);
        '''

        M = M1
        C = D1+DR*(omegaRef/omega)+DG*(omega/omegaRef)
        K = K1+KR+KGeo*math.pow((omega/omegaRef),2)

        if(LOG_LEVEL==10): #Debug Mode
          m_norm = norm.onenormest(M, t=3, itmax=5, compute_v=False, compute_w=False)
          c_norm = norm.onenormest(C, t=3, itmax=5, compute_v=False, compute_w=False)
          k_norm = norm.onenormest(K, t=3, itmax=5, compute_v=False, compute_w=False)

          logger_i.debug("\n"+"\n"+'Properties of assembled matrices')
          logger_i.debug('M '+' '+'Nonzeros = '+str(M.nnz)+' 1-Norm = '+str(m_norm))
          logger_i.debug('C '+' '+'Nonzeros = '+str(C.nnz)+' 1-Norm = '+str(c_norm))
          logger_i.debug('K '+' '+'Nonzeros = '+str(K.nnz)+' 1-Norm = '+str(k_norm))

        return M, C, K;
Exemple #11
0
print "\n" + "\n" + 'Beginning Data Analysis'

sparse_list = load.load_matrices(obj)

obj.logger_i.info("\n" + 'Matrices in CSC format converted to CSR')

obj.logger_i.info("\n\n" + 'Properties of various component matrices' + "\n")

for i in range(0, len(sparse_list)):
    componentMatrix = sparse_list[i]

    csrForm = componentMatrix.tocsr()
    normMatrix = onenormest(csrForm,
                            t=3,
                            itmax=5,
                            compute_v=False,
                            compute_w=False)

    #diffFlag = numpy.allclose(csrForm.data, csrForm.transpose().data)
    #symmFlag = 'symmetric' if diffFlag else 'not symmetric'

    eps = pow(10, -9)
    rank = estimate_rank(aslinearoperator(componentMatrix), eps)
    #print 'Approximate rank with relative error of(', eps, ')for numerical rank definition = ',rank

    print obj.data_file_list[i], obj.data_file_name[
        i], componentMatrix.shape, ' NonZeros = ', componentMatrix.nnz, ' 1-Norm = ', normMatrix, ' rank ', rank
    obj.logger_i.info(obj.data_file_list[i] + ' ' + obj.data_file_name[i] +
                      str(componentMatrix.shape) + ' NonZeros = ' +
                      str(componentMatrix.nnz) + ' 1-Norm = ' +
Exemple #12
0
def test_onenormest(B):
    C = spla.onenormest(B)
    npt.assert_allclose(C, np.linalg.norm(B.todense(), 1))
Exemple #13
0
def scale_matrices(obj, m, c, k):
    r"""
         
        :param obj: object of the class ``BrakeClass``
        :param m: Mass Matrix
        :param c: Damping Matrix
        :param k: Stiffness Matrix
        :return: M, C, K - Scaled Mass, Damping and Stiffness Matrix respectively
        :return: scaling parameters, - gamma and delta.

        Procedure::
        
         The M , C , K, gamma, delta  are obtained as follows:
        
         M = gamma*gamma*delta*m;
         C = gamma*delta*c;
         K = delta*k;
         gamma = math.sqrt(k_norm/m_norm);
         delta = 2/(k_norm+c_norm*gamma);   
         
        Note::
        
         scipy.sparse.linalg.onenormest - Computes a lower bound of the 1-norm of a sparse matrix.
         In the disk brake modelling theory spectral norm has been used but since I could not
         find a better(less computational cost) way to obtain this in python, I have used 1-norm
         approximation
         
        """

    #object attributes used in the function
    LOG_LEVEL = obj.log_level
    logger_t = obj.logger_t
    logger_i = obj.logger_i

    if (LOG_LEVEL == 10):  #Debug Mode
        logger_i.debug("\n" + "\n" + "\n" +
                       'In scale matrices (scale_matrices.py)')
        logger_i.debug(
            '----------------------------------------------------------------')

    m_norm = norm.onenormest(m, t=3, itmax=5, compute_v=False, compute_w=False)
    c_norm = norm.onenormest(c, t=3, itmax=5, compute_v=False, compute_w=False)
    k_norm = norm.onenormest(k, t=3, itmax=5, compute_v=False, compute_w=False)

    gamma = math.sqrt(k_norm / m_norm)
    delta = 2 / (k_norm + c_norm * gamma)
    M = gamma * gamma * delta * m
    C = gamma * delta * c
    K = delta * k

    if (LOG_LEVEL == 10):  #Debug Mode
        m_scaled_norm = gamma * gamma * delta * m_norm
        c_scaled_norm = gamma * delta * c_norm
        k_scaled_norm = delta * k_norm
        rho = max(m_scaled_norm, c_scaled_norm, k_scaled_norm) / min(
            m_scaled_norm, k_scaled_norm)
        logger_i.debug('Scaling factors gamma = ' + str(gamma) + ' delta = ' +
                       str(delta))
        logger_i.debug('The scaled problem has rho = ' + str(rho))

    return M, C, K, gamma
Exemple #14
0
def test_onenormest(matrices):
    A_dense, A_sparse, b = matrices
    est0 = splin.onenormest(A_dense)
    est = splin.onenormest(A_sparse)
    assert_allclose(est, est0)
Exemple #15
0
def OBE_integrator(
        r0=np.array((0., 0., 0.)),
        r1=np.array((0, 0, 3e-2)),
        v=np.array(
            (0, 0, 200)
        ),  #Parameters for defining position of molecule as function of time
        X_states=None,
        B_states=None,  #States that are needed for simulation
        microwave_fields=None,
        laser_fields=None,  #Lists of MicrowaveFields and LaserFields 
        Gamma=2 * np.pi * 1.6e6,  #Natural linewidth of the excited state
        states_pop=None,
        pops=None,  #States that are populated and their populations
        Nsteps=int(5e3),
        dt=None,
        dt_max=1e-5,  #Number of timesteps, or alternatively size of timesteps
        method='exp',  #Method to use for time-integration
        verbose=True,  #Whether or not to print outputs for debugging
):
    """
    Function that integrates optical Bloch equations for TlF in Centrex.

    The structure of the code is as follows:
    0. Define position of molecule as function of time. Makes it easier to
       convert spatial dependence of e.g. laser/microwave intensity to a
       time dependence.

    1. Define the internal Hamiltonian of the molecule. The Hamiltonian
       for the X- and B-states of TlF is fetched from file and diagonalized.
       The eigenstates of the Hamiltonians are used as the basis in the rest
       of the calculation. The size of the basis is reduced by keeping only 
       states that couple to one of the time-dependent fields, or which can
       be reached via spontaneous decay from the excited state.

        1.1 Define X-state Hamiltonian and find the diagonal basis
        1.2 Define B-state Hamiltonian and find the diagonal basis

    2. Microwave couplings. Construct Hamiltonian for microwave couplings between different 
       rotational states within X based on the list of microwave fields that is provided.

    3. Optical couplings. Construct the Hamiltonian for laser couplings between X and B. Can
       have multiple laser fields provided in a list of LaserField objects.
    
    4. Generate the total Hamiltonian that contains the couplings due to the fields, and the
       internal molecular Hamiltonian

    5. Generate collapse operators that describe spontaneous decay

    6. Generate initial density matrix

    7. Transform to Liouville space if using exponentiation method

    8. Time-evolution

    inputs:
    r0 = initial position of molecule [m]
    r1 = final positon of molecule [m]
    v = velocity of molecule [m/s]
    X_states = list of states in X-state of TlF used in the simulation (list of State objects)
    B_states = list of states in B-state of TlF used in the simulation (list of State objects)
    laser_fields = list of OpticalField objects (see OBE_classes.py)
    microwave_fields = list of MicrowaveField objects (see OBE_classes.py)
    states_pops = states that are initially populated
    pops = initial populations of states_pops. If none, Boltzmann distribution assumed

    outputs:
    t_array = array of times at which we have datapoints [s]
    pop_results = populations in each state at the times stored in t_array

    """

    ### 0. Define molecular position as function of time ###
    def molecule_position(t, r0, v):
        """
        Function that returns position of molecule at a given time for given initial position and 
        velocity.
        
        inputs:
        t = time in seconds
        r0 = position of molecule at t = 0 in meters
        v = velocity of molecule in meters per second
        
        returns:
        r = position of molecule in metres
        """
        r = r0 + v * t

        return r

    #Define a lambda function that gives position as function of time
    r_t = lambda t: molecule_position(t, r0, v)

    #Calculate total time for simulation [s]
    z0 = r0[2]
    z1 = r1[2]
    vz = v[2]
    T = np.abs((z1 - z0) / vz)

    # If want printed output, print it
    if verbose:
        print("Total simulation time is {:.3E} s".format(T))

    ### 1. Internal Hamiltonian
    ## 1.1 X-state of TlF

    #Load Hamiltonian from file
    H_X_uc = make_hamiltonian(
        "./utilities/TlF_X_state_hamiltonian_J0to4.pickle")

    #Hamiltonian on file is in uncoupled angular momentum basis. Transform it to coupled.
    #Load transform matrix
    with open("./utilities/UC_to_C_j0to4.pickle", "rb") as f:
        S_trans = pickle.load(f)

    #Transform matrix
    E = np.array((0, 0, 0))
    B = np.array(
        (0, 0, 0.001)
    )  #Very small magnetic field is used to ensure mF is a good quantum number
    H_X = S_trans.conj().T @ H_X_uc(E, B) @ S_trans

    #Define basis to which the Hamiltonian was transformed
    Jmin = 0
    Jmax = 4
    I_F = 1 / 2
    I_Tl = 1 / 2
    QN_X = [
        CoupledBasisState(F,
                          mF,
                          F1,
                          J,
                          I_F,
                          I_Tl,
                          electronic_state='X',
                          P=(-1)**J,
                          Omega=0) for J in ni_range(Jmin, Jmax + 1)
        for F1 in ni_range(np.abs(J - I_F), J + I_F + 1)
        for F in ni_range(np.abs(F1 - I_Tl), F1 + I_Tl + 1)
        for mF in ni_range(-F, F + 1)
    ]

    #Diagonalize the Hamiltonian (also making sure V is as close as identity matrix as possible
    # in terms of ordering of states)
    D, V = np.linalg.eigh(H_X)
    V_ref_X = np.eye(V.shape[0])
    D, V = reorder_evecs(V, D, V_ref_X)
    H_X_diag = V.conj().T @ H_X @ V

    #Define new basis based on eigenstates of H_X:
    QN_X_diag = matrix_to_states(V, QN_X)

    #Sometimes only a subset of states is needed for the simulation. Determine the X-states
    #that are needed here.
    if X_states is None:
        ground_states = QN_X_diag
    else:
        ground_states = find_exact_states(X_states,
                                          H_X_diag,
                                          QN_X_diag,
                                          V_ref=V_ref_X)

    #Find the Hamiltonian in the reduced basis
    H_X_red = reduced_basis_hamiltonian(QN_X_diag, H_X_diag, ground_states)

    #Set small off diagonal terms to zero
    H_X_red[np.abs(H_X_red) < 0.1] = 0

    ## 1.2 B-state of TlF

    #Load Hamiltonian from file
    H_B = make_hamiltonian_B(
        "./utilities/B_hamiltonians_symbolic_coupled_P_1to3.pickle")

    #Define the basis that the Hamiltonian is in
    Jmin = 1
    Jmax = 3
    I_F = 1 / 2
    I_Tl = 1 / 2
    Ps = [-1, 1]
    QN_B = [
        CoupledBasisState(F,
                          mF,
                          F1,
                          J,
                          I_F,
                          I_Tl,
                          P=P,
                          Omega=1,
                          electronic_state='B')
        for J in ni_range(Jmin, Jmax + 1)
        for F1 in ni_range(np.abs(J - I_F), J + I_F + 1)
        for F in ni_range(np.abs(F1 - I_Tl), F1 + I_Tl + 1)
        for mF in ni_range(-F, F + 1) for P in Ps
    ]

    #Diagonalize the Hamiltonian
    D, V = np.linalg.eigh(H_B)
    V_ref_B = np.eye(H_B.shape[0])
    D, V = reorder_evecs(V, D, V_ref_B)
    H_B_diag = V.conj().T @ H_B @ V

    #Define new basis based on eigenstates of H_B
    QN_B_diag = matrix_to_states(V, QN_B)

    #Sometimes only a subset of states is needed for the simulation. Determine the X-states
    #that are needed here.
    if B_states is None:
        excited_states = QN_B_diag
    else:
        excited_states = find_exact_states(B_states,
                                           H_B_diag,
                                           QN_B_diag,
                                           V_ref=V_ref_B)

    #Find the Hamiltonian in the reduced basis
    H_B_red = reduced_basis_hamiltonian(QN_B_diag, H_B_diag, excited_states)

    #Set small off diagonal terms to zero
    H_B_red[np.abs(H_B_red) < 0.1] = 0

    ## 1.3 Define total internal Hamiltonian
    H_int = scipy.linalg.block_diag(H_X_red, H_B_red)
    V_ref_int = np.eye(H_int.shape[0])

    #Define Hamiltonian in the rotating frame (transformation not applied yet)
    H_rot = H_int

    #Define QN for the total Hamiltonian that includes both X and B
    QN = ground_states + excited_states

    if verbose:
        print("Diagonal of H_int:")
        print(np.diag(H_int) / (2 * np.pi))

    ### 2. Couplings due to microwaves
    #If there are microwave fields, loop over them. Otherwise skip this section.
    if microwave_fields is not None:
        microwave_couplings = []
        omegas = []
        for microwave_field in microwave_fields:
            #Find the exact ground and excited states for the field
            microwave_field.find_closest_eigenstates(H_rot, QN, V_ref_int)

            #Calculate angular part of matrix element for main transition
            ME_main = microwave_field.calculate_ME_main(
            )  #Angular part of ME for main transition

            #Find the coupling matrices due to the laser
            H_list = microwave_field.generate_couplings(QN)
            H_list = [H / ME_main for H in H_list]
            Hu_list = [np.triu(H) for H in H_list]
            Hl_list = [np.tril(H) for H in H_list]

            #Find some necessary parameters and then define the coupling matrix as a function of time
            Omega_t = microwave_field.find_Omega_t(
                r_t)  #Time dependence of Rabi rate
            p_t = microwave_field.p_t  #Time dependence of polarization of field
            omega = microwave_field.calculate_frequency(
                H_rot, QN)  #Calculate frequency of transition
            D_mu = microwave_field.generate_D(
                omega, H_rot, QN,
                V_ref_int)  #Matrix that shifts energies for rotating frame
            H_rot += D_mu

            #Define the coupling matrix as function of time
            def H_mu_t_func(Hu_list, Hl_list, p_t, Omega_t, t):
                return (
                    Omega_t(t) *
                    (Hu_list[0] * p_t(t)[0] + Hu_list[1] * p_t(t)[1] +
                     Hu_list[2] * p_t(t)[2] + Hl_list[0] * p_t(t)[0].conj() +
                     Hl_list[1] * p_t(t)[1].conj() +
                     Hl_list[2] * p_t(t)[2].conj()))

            H_mu_t = partial(H_mu_t_func, Hu_list, Hl_list, p_t, Omega_t)
            microwave_couplings.append(H_mu_t)

            #Print output for checks
            if verbose:
                print("ME_main = {:.3E}".format(ME_main))
                i_e = QN.index(microwave_field.excited_main)
                i_g = QN.index(microwave_field.ground_main)
                print(H_mu_t(T / 2)[i_e, i_g] / (2 * np.pi * 1e6))
                print(Omega_t(T / 2))

        #Generate function that gives couplings due to all microwaves
        def H_mu_tot_t(t):
            H_mu_tot = microwave_couplings[0](t)
            if len(microwave_couplings) > 1:
                for H_mu_t in microwave_couplings[1:]:
                    H_mu_tot = H_mu_tot + H_mu_t(t)
            return H_mu_tot

        if verbose:
            with open("H_mu_tot.pickle", 'wb+') as f:
                pickle.dump(H_mu_tot_t(T / 2), f)

        #Shift energies in H_int in accordance with the rotating frame
        #H_rot = H_rot + D_mu

    else:
        H_mu_tot_t = lambda t: np.zeros(H_rot.shape)

    if verbose:
        time = timeit.timeit("H_mu_tot_t(T/2)", number=10,
                             globals=locals()) / 10
        print("Time to generate H_mu_tot_t: {:.3e} s".format(time))
        H_test = H_mu_tot_t(T / 2)
        non_zero = H_test[np.abs(H_test) > 0].shape[0]
        print("Non-zero elements at T/2: {}".format(non_zero))

    ### 3. Optical couplings due to laser
    #If there are laser fields, loop over them. Otherwise skip this section
    if laser_fields is not None:
        optical_couplings = []
        optical_Ls = []
        D_laser = np.zeros(H_rot.shape)
        for laser_field in laser_fields:
            #Find the exact ground and excited states for the field
            laser_field.find_closest_eigenstates(H_rot, QN, V_ref_int)

            #Calculate angular part of matrix element for main transition
            ME_main = laser_field.calculate_ME_main(
            )  #Angular part of ME for main transition

            #Find the coupling matrices due to the laser
            H_list = laser_field.generate_couplings(QN)
            H_list = [H / ME_main for H in H_list]
            Hu_list = [np.triu(H) for H in H_list]
            Hl_list = [np.tril(H) for H in H_list]

            #Find some necessary parameters and then define the coupling matrix as a function of time
            p_t = laser_field.p_t  #Time dependence of polarization of field (includes phase modulation)
            Omega_t = laser_field.find_Omega_t(
                r_t)  #Time dependence of Rabi rate
            D_laser += laser_field.generate_D(
                H_rot, QN)  #Matrix that shifts energies for rotating frame
            H_rot = H_rot + laser_field.generate_D(H_rot, QN)

            #Define the optical coupling Hamiltonian as function of time
            def H_oc_t_func(Hu_list, Hl_list, p_t, Omega_t, t):
                return (
                    Omega_t(t) *
                    (Hu_list[0] * p_t(t)[0] + Hu_list[1] * p_t(t)[1] +
                     Hu_list[2] * p_t(t)[2] + Hl_list[0] * p_t(t)[0].conj() +
                     Hl_list[1] * p_t(t)[1].conj() +
                     Hl_list[2] * p_t(t)[2].conj()))

            H_oc_t = partial(H_oc_t_func, Hu_list, Hl_list, p_t, Omega_t)

            optical_couplings.append(H_oc_t)

            #Print output for checks
            if verbose:
                print("ME_main = {:.3E}".format(ME_main))
                i_e = QN.index(laser_field.excited_main)
                i_g = QN.index(laser_field.ground_main)
                print(H_oc_t(T / 2)[i_e, i_g] / (2 * np.pi * 1e6))
                print(Omega_t(T / 2) / (1e6 * 2 * np.pi))
                print("excited main:")
                laser_field.ground_main.print_state()

        #Functions for total Hamiltonian and Lindbladian due to optical couplings
        def H_oc_tot_t(t):
            H_oc_tot = optical_couplings[0](t)
            if len(optical_couplings) > 1:
                for H_oc_t in optical_couplings[1:]:
                    H_oc_tot = H_oc_tot + H_oc_t(t)
            return H_oc_tot

        #Shift energies in H_rot in accordance with the rotating frame
        #Also shift the energies so that ground_main is at zero energy
        i_g = QN.index(laser_field.ground_main)
        H_rot = H_rot - np.eye(H_rot.shape[0]) * H_rot[i_g, i_g]

    #If no laser fields are defined, set coupling matrix to zeros
    else:
        H_oc_tot_t = lambda t: np.zeros(H_rot.shape)

    if verbose:
        time = timeit.timeit("H_oc_tot_t(T/2)", number=10,
                             globals=locals()) / 10
        print("Time to generate H_oc_tot_t: {:.3e} s".format(time))
        print("Diagonal of H_rot in rotating frame of laser:")
        print(np.diag(H_rot) / (2 * np.pi))
        print("D_laser:")
        print(np.diag(D_laser))
        # with open("H_oc_tot.pickle",'wb+') as f:
        #     pickle.dump(H_oc_tot_t(T/2.3156165),f)

    ### 4. Total Hamiltonian
    #Define the total Hamiltonian (including the oscillating fields) in the rotating frame
    # as a function of time
    H_tot_t = lambda t: H_rot + H_oc_tot_t(t) + H_mu_tot_t(t)

    if verbose:
        time = timeit.timeit("H_tot_t(T/2)", number=10, globals=locals()) / 10
        print("Time to generate H_tot_t: {:.3e} s".format(time))
        print("Diagonal of H_tot_t(T/2) in rotating frame of laser:")
        print(np.diag(H_tot_t(T / 2)) / (2 * np.pi))
        # print("D_laser:")
        # print(np.diag(D_laser))

    ### 5. Collapse operators
    #Here we generate the matrices that describe spontaneous decay from the excited
    #states to the ground states
    C_list = collapse_matrices(QN, ground_states, excited_states, gamma=Gamma)

    #Generate the superoperator that contains spontaneous decay
    #This is constant in time so only generated once
    L_collapse = np.zeros((len(QN)**2, len(QN)**2), dtype=complex)
    for C in tqdm(C_list):
        L_collapse += (generate_superoperator(C,
                                              C.conj().T) - 1 / 2 *
                       (generate_flat_superoperator(C.conj().T @ C) +
                        generate_sharp_superoperator(C.conj().T @ C)))
    #Make the collapse operator into a sparse matrix
    L_collapse = csr_matrix(L_collapse)

    ### 6. Initial populations
    #Find the exact forms of the states that are initially populated
    states_pop = find_exact_states(states_pop, H_rot, QN, V_ref=V_ref_int)

    #If populations in states are not specified, assume Boltzmann distribution
    if pops is None:
        pops = find_boltzmann_pops(states_pop)
        pops = pops / np.sum(pops)

    #Generate initial density matrix
    rho_ini = generate_density_matrix(QN, states_pop, pops)

    if verbose:
        print("Initial population in")
        states_pop[0].print_state()
        print("is {:.5f}".format(pops[0]))

    if method == 'exp':
        ### 7. Transfer to Liouville space
        #We transfer to Liouville space where the density matrix is a vector
        #and time-evolution is found by matrix exponentiation

        #Generate the Lindbladian
        #Define a function that gives the time dependent part of the Liouvillian
        #at time t
        L_t = lambda t: (generate_commutator_superoperator(
            coo_matrix(-1j * H_tot_t(t))) + L_collapse)

        if verbose:
            time = timeit.timeit("L_t(T/2)", number=10, globals=locals()) / 10
            print("Time to generate L_t: {:.3e} s".format(time))
            L_test = L_t(T / 2)
            non_zero = L_test[np.abs(L_test) > 0]

        ### 8. Time-evolution
        #Here we perform the time-evolution of the system

        #Set rho vector to its initial value
        rho_vec = generate_rho_vector(rho_ini)

        #Calculate timestep
        if dt is None:
            dt = T / Nsteps
        else:
            Nsteps = int(T / dt) + 1

        #Generate array of times
        t_array = np.linspace(0, T, Nsteps)

        #Pre-calculate some parameters for the matrix exponentiation
        #Calculate onenorm estimate
        norm = onenormest(L_t(T / 2))

        #Calculate wsp and iwsp
        m = 20  #maximum size of Krylov subspace
        n = rho_vec.shape[0]
        wsp = np.zeros(7 + n * (m + 2) + 5 * (m + 2) * (m + 2),
                       dtype=np.complex128)
        iwsp = np.zeros(m + 2, dtype=np.int32)

        #Array for storing results
        pop_results = np.zeros((len(QN), len(t_array)), dtype=float)
        pop_results[:, 0] = np.real(np.diag(rho_ini))

        #Loop over timesteps
        for i, t_i in enumerate(tqdm(t_array[1:])):
            #Calculate the Lindbladian at this time
            L_sparse = L_t(t_i)

            #Time evolve the density vector
            rho_vec = py_zgexpv(rho_vec,
                                L_sparse,
                                t=dt,
                                anorm=norm,
                                wsp=wsp,
                                iwsp=iwsp,
                                m=m)

            #Convert back to density matrix
            rho = rho_vec.reshape(len(QN), len(QN))

            #Find populations in each state
            pop_results[:, i + 1] = np.real(np.diag(rho))

        # if verbose:
        #     time = timeit.timeit("py_zgexpv(rho_vec, L_sparse, t = dt, anorm = norm, wsp = wsp, iwsp = iwsp,m = m)",
        #                          number = 10, globals = locals())/10
        #     print("Time for exponentiating: {:.3E}".format(time))

    elif method == 'RK45':
        ### 7. Setting up ODE solver

        #Define a function that generates the RHS of the OBEs in vector format
        #Still useful to use Liouville space for the collapse operators since they can be
        #fully precalculated (see rhs_C below)
        def Lindblad_rhs(t, rho_vec):
            dim = int(np.sqrt(len(rho_vec)))
            rho = rho_vec.reshape((dim, dim))
            rhs_H = (-1j * (H_tot_t(t) @ rho - rho @ H_tot_t(t))).flatten()
            rhs_C = L_collapse @ rho_vec
            rhs = rhs_H + rhs_C
            return rhs

        if verbose:
            time = timeit.timeit(
                "rhs_test  = Lindblad_rhs(T/2,rho_ini.flatten())",
                number=10,
                globals=locals()) / 10
            print("Time to generate RHS: {:.3e} s".format(time))

        ### 8. Time-evolution

        #Perform time evolution using IVP solver from scipy
        t_span = (0, T)
        sol = solve_ivp(Lindblad_rhs,
                        t_span,
                        rho_ini.flatten(),
                        dense_output=True,
                        max_step=dt_max,
                        method='RK45')

        #Get t_array and populations from solution object
        t_array = sol.t
        pop_results = np.real(
            np.einsum(
                'jji->ji',
                sol.y.reshape(
                    (rho_ini.shape[0], rho_ini.shape[1], sol.y.shape[1]))))

    else:
        raise NotImplementedError("Time integation method not implemented")

    return t_array, pop_results
Exemple #16
0
#Putting the matrix in CSR form

csr = csr_matrix((value, index, pointer))

#Some tests on the matrix:

#Norm

norm = sp.norm(csr)

print('Frobenius norm =', norm)

#Lower bound of 1-norm

onenorm = sp.onenormest(csr)

print('Lower bound of 1-norm =', onenorm)

#Solving the system

#Note that sp.spsolve doesn't seem to work. It says that 'colind and rwoptr must be of type cint', so use lsmr instead

soln = sp.lsmr(csr, RHS)  #Least squares approx

print('Least squares solution =', soln[0])

#Condition number

print('Condition number =', soln[6])
Exemple #17
0
from _expokit import dgexpv, dsexpv, zgexpv, zhexpv
import numpy as np
from scipy.sparse import random
from scipy.sparse.linalg import onenormest, expm_multiply, aslinearoperator

n = 100
m = 20
time = 10.0
iflag = np.array([1])
tol = 0.0
v = np.zeros(n, dtype=complex)
v[0] = 1
v /= np.linalg.norm(v)
A = random(n, n, format="csr")
A = -1j * ((A.T + A) / 2)
anorm = onenormest(A)
wsp = np.zeros(7 + n * (m + 2) + 5 * (m + 2) * (m + 2), dtype=complex)
iwsp = np.zeros(m + 2, dtype=int)

A_op = aslinearoperator(A)

output_vec, tol0, iflag0 = zgexpv(m, time, v, tol, anorm, wsp, iwsp,
                                  A_op.matvec, 0)

exact_vec = expm_multiply(time * A, v)

print iflag0
print np.linalg.norm(output_vec - exact_vec)
import meshes
import FEM
import time
import scipy.sparse.linalg as spla

meshwidth = 0.05
processes = 8

p,t=meshes.grid_square(1,meshwidth)

timer=time.time()
seqM=FEM.mass(p,t)
seqTime=time.time()-timer

timer=time.time()
parM,processes=FEM.massParallel(p,t,processes)
parTime=time.time()-timer

print "difference of matrices:        ", spla.onenormest(seqM-parM)
print "time for sequential assembling:", seqTime
print "time for parallel assembling:  ", parTime
print "speed-up:  ", seqTime/parTime
print "efficiency:", (seqTime/parTime)/processes