Package: centrex-tlf
ExtensionsCeNTREX-TlFCode for generating the CeNTREX TlF States, Hamiltonians, Transitions, Couplings and Lindblad equations.Consists of six modules:stateshamiltoniantransitionscouplingslindbladutilsstateshas code to generate states and the classes that describe theCoupledBasisState,UncoupledBasisStateandState; whereStateholds multipleCoupledBasisStatesorUncoupledBasisStateswith different amplitudes, i.e. when superpositions arise.DependenciesnumpyscipysympypandasInstallationpython -m pip install .where.is the path to the directory. To install directly fromGithubuse:python -m pip install git+https://github.com/ograsdijk/CeNTREX-TlFstatesstatescontains the functions and classes to represent the TlF states:CoupledBasisStateis a class representing a TlF state with coupled quantum numbers, i.e. F, mF, F1, J, I1, I2, Ω, P.UncoupledBasisStateis a class representing a TlF state with uncoupled quantum numbers, i.e. J, mJ, I1, m1, I2, m2, Ω, P.FinallyStateis a class representing a collection of states, since in most cases the TlF molecules are in a superposition state.fromcentrex_tlfimportstatesstates.CoupledBasisState(F=1,mF=0,F1=1/2,J=0,I1=1/2,I2=1/2,Omega=0,P=1)or using some of the functions to generate all hyperfine substates in a given J level:fromcentrex_tlfimportstatesQN=states.generate_uncoupled_states_ground(Js=[0,1])which returns an array containing the UncoupledBasisStatesarray([|X,J=0,mJ=0,I₁=1/2,m₁=-1/2,I₂=1/2,m₂=-1/2,P=+,Ω=0>,|X,J=0,mJ=0,I₁=1/2,m₁=-1/2,I₂=1/2,m₂=1/2,P=+,Ω=0>,|X,J=0,mJ=0,I₁=1/2,m₁=1/2,I₂=1/2,m₂=-1/2,P=+,Ω=0>,|X,J=0,mJ=0,I₁=1/2,m₁=1/2,I₂=1/2,m₂=1/2,P=+,Ω=0>,|X,J=1,mJ=-1,I₁=1/2,m₁=-1/2,I₂=1/2,m₂=-1/2,P=-,Ω=0>,|X,J=1,mJ=-1,I₁=1/2,m₁=-1/2,I₂=1/2,m₂=1/2,P=-,Ω=0>,|X,J=1,mJ=-1,I₁=1/2,m₁=1/2,I₂=1/2,m₂=-1/2,P=-,Ω=0>,|X,J=1,mJ=-1,I₁=1/2,m₁=1/2,I₂=1/2,m₂=1/2,P=-,Ω=0>,|X,J=1,mJ=0,I₁=1/2,m₁=-1/2,I₂=1/2,m₂=-1/2,P=-,Ω=0>,|X,J=1,mJ=0,I₁=1/2,m₁=-1/2,I₂=1/2,m₂=1/2,P=-,Ω=0>,|X,J=1,mJ=0,I₁=1/2,m₁=1/2,I₂=1/2,m₂=-1/2,P=-,Ω=0>,|X,J=1,mJ=0,I₁=1/2,m₁=1/2,I₂=1/2,m₂=1/2,P=-,Ω=0>,|X,J=1,mJ=1,I₁=1/2,m₁=-1/2,I₂=1/2,m₂=-1/2,P=-,Ω=0>,|X,J=1,mJ=1,I₁=1/2,m₁=-1/2,I₂=1/2,m₂=1/2,P=-,Ω=0>,|X,J=1,mJ=1,I₁=1/2,m₁=1/2,I₂=1/2,m₂=-1/2,P=-,Ω=0>,|X,J=1,mJ=1,I₁=1/2,m₁=1/2,I₂=1/2,m₂=1/2,P=-,Ω=0>],dtype=object)State objects, which are superpositions of BasisStates are also generated easily:superposition=1*QN[0]+0.1j*QN[1]which returns1.00x|X,J=0,mJ=0,I₁=1/2,m₁=-1/2,I₂=1/2,m₂=-1/2,P=+,Ω=0>0.00+0.10jx|X,J=0,mJ=0,I₁=1/2,m₁=-1/2,I₂=1/2,m₂=1/2,P=+,Ω=0>A subset ofState,CoupledBasisStatescan be selected with theQuantumSelectoras follows:QN=states.generate_coupled_states_ground(Js=[0,1])qn_select=states.QuantumSelector(J=1,mF=0,electronic=states.ElectronicState.X)qn_select.get_indices(QN)which returns all the indices withJ=1andmJ=0:array([4,6,9,13],dtype=int64)hamiltonianhamiltoniancontains the functions to generate TlF hamiltonians in the X and B state in either coupled or uncoupled form.Generating a ground state X hamiltonian can be accomplished easily using some convenience functions:fromcentrex_tlfimportstates,hamiltonian# generate the hyperfine sublevels in J=0 and J=1QN=states.generate_uncoupled_states_ground(Js=[0,1])# generate a dictionary with X hamiltonian termsH=hamiltonian.generate_uncoupled_hamiltonian_X(QN)# create a function outputting the hamiltonian as a function of E and BHfunc=hamiltonian.generate_uncoupled_hamiltonian_X_function(H)All functions generating hamiltonians only require a list or array of TlF states. Generating the hamiltonian only for certain hyperfine sublevels is hence also straightforward. The functioncalculate_uncoupled_hamiltonian_Xcalculates the hamiltonians from scratch, whereasgenerate_uncoupled_hamiltonian_Xpulls the non-zero elements from an sqlite database.To convert a hamiltonian from one basis to another transformation matrices can be generated or calculated
(generate_transform_matrixpulls non-zero matrix elements from an sqlite database,calculate_transform_matrixdoes the full element wise calculation):fromcentrex_tlfimportstates,hamiltonian# generate the hyperfine sublevels in J=0 and J=1QN=states.generate_uncoupled_states_ground(Js=[0,1])# generate the coupled hyperfine sublevels in J=0 and J=1QNc=states.generate_coupled_states_ground(Js=[0,1])# generate a dictionary with X hamiltonian termsH=hamiltonian.generate_uncoupled_hamiltonian_X(QN)Hfunc=hamiltonian.generate_uncoupled_hamiltonian_X_function(H)H0=Hfunc(E=[0,0,0],B=[0,0,1e-3])# generate the transformation matrixtransform=hamiltonian.generate_transform_matrix(QN,QNc)# calculate the transformed matrixH0c=transform.conj().T@H0@transformThis is mostly used for optical bloch simulations where the coupled states representation is more convenient.Stark Shift ExampleTo calculate the energy levels as a function of the electric field the following code can be used, which calculates all energies up toJ=6but only plots the|J=2, mJ=0>hyperfine levels. These are the states focussed by the electrostatic quadrupole lens in the CeNTREX experiment.importnumpyasnpimportmatplotlib.pyplotaspltfromcentrex_tlfimportstates,hamiltonian# generate states up to J=6QN=states.generate_uncoupled_states_ground(Js=np.arange(7))# generate the X hamiltonian termsH=hamiltonian.generate_uncoupled_hamiltonian_X(QN)# create a function outputting the hamiltonian as a function of E and BHfunc=hamiltonian.generate_uncoupled_hamiltonian_X_function(H)# V/cmEz=np.linspace(0,50e3,101)# generate the Hamiltonian for (almost) zero field, add a small field to make states# non-degenerateHi=Hfunc(E=[0,0,1e-3],B=[0,0,1e-3])E,V=np.linalg.eigh(Hi)# get the true superposition-states of the systemQN_states=hamiltonian.matrix_to_states(V,QN)# original eigenvectors used in tracking states as energies change orderV_track=V.copy()# indices of the J=2, mJ=0 states focused by the lensindices_J2_mJ0=[idxforidx,sinenumerate(QN_states)ifs.largest.J==2ands.largest.mJ==0]indices_J012=[idxforidx,sinenumerate(QN_states)ifs.largest.Jin[0,1,2]]# empty array for storing energiesenergy=np.empty([Ez.size,len(QN)],dtype=np.complex128)# iterate over the electric field valuesforidx,Eiinenumerate(Ez):Hi=Hfunc(E=[0,0,Ei],B=[0,0,1e-3])E,V=np.linalg.eigh(Hi)# sort indices to keep the state order the sameindices=np.argmax(np.abs(V_track.conj().T@V),axis=1)energy[idx,:]=E[indices]V_track[:,:]=V[:,indices]# plot the J=2, mJ=0 Stark curvesfig,ax=plt.subplots(figsize=(12,8))ax.plot(Ez,(energy.real[:,indices_J2_mJ0]-energy.real[:,indices_J2_mJ0][0,0])/(2*np.pi*1e9),)ax.set_xlabel("E [V/cm]")ax.set_ylabel("Energy [GHz]")ax.set_title("|J=2, mJ=0> Stark Curve")ax.grid(True)plt.show()couplingsCode for generating the CeNTREX TlF couplings.
Includes code for generating branching ratios, electric dipole coupling elements and coupling fieldsGenerating branching ratiosThe code below generates branching ratios from|J'=1, F1'=1/2, mF=0>to all states in theJ=1manifold.fromcentrex_tlfimportstates,couplingsexcited_state=states.CoupledBasisState(J=1,F1=1/2,F=1,mF=0,I1=1/2,I2=1/2,Omega=1,P=1)qn_select=states.QuantumSelector(J=1)ground_states=[1*sforsinstates.generate_coupled_states_X(qn_select)]br=couplings.calculate_br(1*excited_state,ground_states)Generating couplingsThe code below generates the coupling fields for theJ=1manifold to theJ'=1, F1'=1/2, F'=1manifold. The returned value is a dataclassCouplingFieldscontaining the following fields:ground_mainexcited_mainmain_coupling: the electric dipole coupling betweenground_mainandexcited_mainground_states: list of all ground statesexcited_states: list of all excited statesfields: a list ofCouplingFielddataclasses with the following fields:polarization: polarization vectorfield: coupling field in theground_states+excited_statesbasisfromcentrex_tlfimportstates,couplingsqn_select=states.QuantumSelector(J=1)ground_states=states.generate_coupled_states_X(qn_select)qn_select=states.QuantumSelector(J=1,F1=1/2,F=1,P=1,Ω=1)excited_states=states.generate_coupled_states_B(qn_select)# the generate_coupling_field_* functions requires lists as inputs, not np.ndarraysQN=list(1*np.append(ground_states,excited_states))ground_states=[1*sforsinground_states]excited_states=[1*sforsinexcited_states]H_rot=np.eye(len(QN),dtype=complex)*np.arange(len(QN))V_ref=np.eye(len(QN))pol_vecs=[np.array([0.0,0.0,1.0]),np.array([1.0,0.0,0.0])]normalize_pol=Truecoupling=couplings.generate_coupling_field_automatic(ground_states_approx=ground_states,excited_states_approx=excited_states,QN_basis=QN,H_rot=H_rot,QN=QN,V_ref=V_ref,pol_vecs=pol_vecs,normalize_pol=normalize_pol)