import numpy as _np
from . import backends
import warnings
from .trivial import parse_state_string, write_state_string
from .core import subsystem, reverse_subsystem
###########################################################
# Automatic spin-Relaxation
###########################################################
[docs]
def relaxation_operators(spin_system,temperature='infinity'):
"""Returns the collapse operators for a spin system for which T1 and T2 times have been supplied in the system dictionary.
:param spin_system: The spin system for which the collapse operators are to be calculated.
:Keyword Arguments:
* *temperature* ('infinity') -- The temperature at which the system is to be simulated. The default is 'infinity'.
:returns list: A list of collapse operators.
"""
# doi: 10.1002/mrc.1242
# doi:10.1016/j.chemphys.2011.03.014 (old)
if temperature != 'infinity':
raise NotImplementedError("Temperature dependence not implemented yet. Only infinite temperature limit is supported.")
if temperature == 'infinity':
d = 0
all_cops = []
if spin_system.method == "sympy":
kind = "symbolic"
else:
kind = "numeric"
sqrt = backends.get_calcmethod("sqrt", kind)
for spin in spin_system.system:
spin_name = spin['name']
T1_defined = 'T1' in spin.keys()
T2_defined = 'T2' in spin.keys()
if T1_defined:
T1 = spin['T1']
if T2_defined:
T2 = spin['T2']
#projectors = getattr(spin_system, spin_name + 'p')
if T2_defined:
if T1_defined:
rate = 2/T2 - 1/T1
else:
rate = 2/T2
rate = sqrt(rate)
#for level in projectors.values():
# #print(level)
# all_cops.append(rate*level)
zop = getattr(spin_system, spin_name + 'z')
all_cops.append(rate*zop)
# Problematic for S>1 => Fix later
if T1_defined:
raiseing = getattr(spin_system, spin_name + 'plus')
lowering = getattr(spin_system, spin_name + 'minus')
rate_up = (1+d)/(4*T1/2)
rate_down = (1-d)/(4*T1/2)
all_cops.append(sqrt(rate_up)*raiseing)
all_cops.append(sqrt(rate_down)*lowering)
#if spin['val'] == 1/2:
# rate = sqrt(2/(spin['T1']))
#elif spin['val'] == 1:
# #print("HEY")
# rate = sqrt(2/(3*spin['T1']))
#else:
# raise(ValueError('Only Spins with S<1 supported.'))
#all_level_keys = projectors.keys()
#print(rate)
#Sx = getattr(spin_system, spin_name + 'x')
#for lev in all_level_keys:
# PP = projectors[lev]
# all_cops.append(rate*Sx*PP)
return all_cops
###########################################################
# Collapse Operators for Level Transitions (laser excitation,
#, decay processes, chemical reaction) and all related
# functions
###########################################################
[docs]
def tidyup_ratedict(spinsystem, rates):
"""Tidies up a rate dictionary, i.e. ensures that the keys have a correct format for usage with the transition_operators method.
:param System spinsystem: The spin system for which the collapse operators are to be calculated. (future use)
:param dict rates: A rate dictionary for level transitions. The keys of the dictionary describe the levels between which transitions occur, the values are the rates of the transitions. e.g. {'A->B': 1e6, 'B->A': 1e6} describes a transition from level A to level B with a rate of 1e6 s^-1 and vice versa.
:returns dict: A tidy rate dictionary.
"""
tidyrates = {}
# Method to add a rate to a dictionary.
def _add_rate(name1, name2, rate, key):
for ind_name, name in enumerate([name1, name2]):
# parse
try:
name_parsed = parse_state_string(name)
except ValueError:
raise ValueError("Rate '" + key + "' has an invalid format")
# check if names members of spin system
for sname in name_parsed.keys():
if sname+"id" not in dir(spinsystem):
raise ValueError("Rate '" + key + "' has an invalid format")
# add correct state description to total string
if ind_name == 0 :
s = write_state_string(name_parsed)+"->"
else:
s += write_state_string(name_parsed)
# add the key-value pair to the dictionary
if s in tidyrates.keys():
raise ValueError("Rate '" + s + "' cannot be specified more than once.")
else:
tidyrates[s] = rate
# Process all keys of the dictionary one by one.
for key, rate in rates.items():
# Split the process in source and sink.
parts_two = key.split("<->")
if len(parts_two) == 2:
_add_rate(parts_two[0], parts_two[1], rate, key)
_add_rate(parts_two[1], parts_two[0], rate, key)
else:
part_forward = key.split("->")
if len(part_forward) == 2:
_add_rate(part_forward[0], part_forward[1], rate, key)
else:
part_backward = key.split("<-")
if len(part_backward) == 2:
_add_rate(part_backward[1], part_backward[0], rate, key)
else:
raise ValueError("Rate '" + key + "' has an invalid format.")
return tidyrates
[docs]
def transition_operators(spinsystem, rates):
"""Returns the collapse operators for incoherent (optical) transitions described in a rate dictionary.
:param System spinsystem: The spin system for which the collapse operators are to be calculated.
:param dict rates: A rate dictionary for level transitions. The keys of the dictionary describe the levels between which transitions occur, the values are the rates of the transitions. e.g. {'A->B': 1e6, 'B->A': 1e6} describes a transition from level A to level B with a rate of 1e6 s^-1 and vice versa.
:returns list: A list of collapse operators.
"""
# Extract all backend specific methods.
if spinsystem.method == "sympy":
sqrt_fun = backends.get_calcmethod("sqrt", "symbolic")
else:
sqrt_fun = backends.get_calcmethod("sqrt", "numeric")
ket_fun = getattr(getattr(backends,spinsystem.method), 'ket')
bra_fun = getattr(getattr(backends,spinsystem.method), 'bra')
# Process all entries of a tidy rates dictionary:
rates = tidyup_ratedict(spinsystem, rates)
all_cops = []
transform = False
for key, rate in rates.items():
# Split the rate description in source and sink.
part_forward = key.split("->")
name1 = part_forward[0]
name2 = part_forward[1]
# Further process the descriptions of source and sink levels.
coll_states = []
# Probe whether transition occurs in alternate basis.
# Prohibit transition between states of different basis sets.
if "_" in name1:
basisname = name1.split("_")[0]
if "_" not in name2 or name2.split("_")[0] != basisname:
warnings.warn("Source and sink of a transition are not specified in the same basis. Basis transformation will be performed for both, which may be erroneous.")
#else:
transform = True
Tto = getattr(spinsystem, "to"+basisname)
Tfrom = getattr(spinsystem,"from"+basisname)
elif "_" in name2:
basisname = name2.split("_")[0]
warnings.warn("Source and sink of a transition are not specified in the same basis. Basis transformation will be performed for both, which may be erroneous.")
transform = True
Tto = getattr(spinsystem, "to"+basisname)
Tfrom = getattr(spinsystem,"from"+basisname)
names_parsed = [parse_state_string(i) for i in [name1, name2]]
constituents = list(names_parsed[0].keys()) + list(names_parsed[1].keys())
# check if constituent is from basis transformation
separable = True
for c in constituents:
if c not in spinsystem.ghosts.keys() and c not in [i["name"] for i in spinsystem.system]:
separable = False
break
for name_num in names_parsed :
operator = spinsystem.id
for name in name_num.keys():
if name_num[name] is None:
operator = operator * getattr(spinsystem, name+"id")
else:
operator = operator * getattr(spinsystem, name+"p")[name_num[name]]
if transform:
operator = operator.transform(Tto)
# Go to subsystem of involved spins/levels
if separable:
coll, rcoll, recipe = subsystem(spinsystem, operator, constituents)
else:
coll = operator
coll_states.append((_np.where(abs((coll).diag()) > 1e-9)[0]))
# Construct the collapse operators.
for source in coll_states[0]:
bra = bra_fun(_np.shape(coll)[0], int(source))
for sink in coll_states[1]:
ket = ket_fun(_np.shape(coll)[0], int(sink))
c_ops = sqrt_fun(rate)*(ket*bra)
# Go back to original spin system
if separable:
c_ops = reverse_subsystem(c_ops, rcoll, recipe)
if transform:
c_ops = c_ops.transform(Tfrom)
all_cops.append(c_ops)
return all_cops
def transition_operators_old(spinsystem, rates):
"""Returns the collapse operators for incoherent (optical) transitions described in a rate dictionary.
:param System spinsystem: The spin system for which the collapse operators are to be calculated.
:param dict rates: A rate dictionary for level transitions. The keys of the dictionary describe the levels between which transitions occur, the values are the rates of the transitions. e.g. {'A->B': 1e6, 'B->A': 1e6} describes a transition from level A to level B with a rate of 1e6 s^-1 and vice versa.
:returns list: A list of collapse operators.
"""
# Extract all backend specific methods.
if spinsystem.method == "sympy":
sqrt_fun = backends.get_calcmethod("sqrt", "symbolic")
else:
sqrt_fun = backends.get_calcmethod("sqrt", "numeric")
ket_fun = getattr(getattr(backends,spinsystem.method), 'ket')
bra_fun = getattr(getattr(backends,spinsystem.method), 'bra')
# Process all entries of a tidy rates dictionary:
rates = tidyup_ratedict(spinsystem, rates)
all_cops = []
transform = False
for key, rate in rates.items():
# Split the rate description in source and sink.
part_forward = key.split("->")
name1 = part_forward[0]
name2 = part_forward[1]
# Further process the descriptions of source and sink levels.
coll_states = []
# Probe whether transition occurs in alternate basis.
# Prohibit transition between states of different basis sets.
if "_" in name1:
basisname = name1.split("_")[0]
if "_" not in name2 or name2.split("_")[0] != basisname:
warnings.warn("Source and sink of a transition are not specified in the same basis. Basis transformation will be performed for both, which may be erroneous.")
#else:
transform = True
Tto = getattr(spinsystem, "to"+basisname)
Tfrom = getattr(spinsystem,"from"+basisname)
elif "_" in name2:
basisname = name2.split("_")[0]
warnings.warn("Source and sink of a transition are not specified in the same basis. Basis transformation will be performed for both, which may be erroneous.")
transform = True
Tto = getattr(spinsystem, "to"+basisname)
Tfrom = getattr(spinsystem,"from"+basisname)
for name_num in [name1, name2]:
operator = spinsystem.id
names_parsed = parse_state_string(name_num)
for name in names_parsed.keys():
if names_parsed[name] is None:
operator = operator * getattr(spinsystem, name+"id")
else:
operator = operator * getattr(spinsystem, name+"p")[names_parsed[name]]
if transform:
operator = operator.transform(Tto)
coll_states.append((_np.where(abs((operator).diag()) > 1e-9)[0]))
# Construct the collapse operators.
for source in coll_states[0]:
bra = bra_fun(spinsystem.dim, int(source))
for sink in coll_states[1]:
ket = ket_fun(spinsystem.dim, int(sink))
c_ops = sqrt_fun(rate)*(ket*bra)
if transform:
c_ops = c_ops.transform(Tfrom)
all_cops.append(c_ops)
return all_cops