def runPass():
	env = envs.cuda(device_num=1)
	constants = Constants(double=env.supportsDouble(),
		a11=100.4, a12=97.7, a22=95.0, fx=f_ax, fy=f_ax, fz=f_rad, e_cut=e_cut)

	# axial size of the N / 2 cloud ~ 8e-6 >> potentials_separation
	# therefore we can safely use normal grid, provided that it has big enough border
	box = constants.boxSizeForN(N, 3, border=1.2)
	grid = UniformGrid(env, constants, shape,
		(box[0] + potentials_separation * 2, box[1], box[2]))
	#print constants.planeWaveModesForCutoff(constants.boxSizeForN(N, 3, border=2))

	gs = SplitStepGroundState(env, constants, grid, dt=1e-6)
	pulse = Pulse(env, constants, grid, f_rabi=f_rabi, f_detuning=f_detuning)
	evolution = SplitStepEvolution(env, constants, grid,
		potentials=split_potentials(constants, grid),
		dt=1e-6)

	n = ParticleNumberCollector(env, constants, grid, verbose=False)
	v = VisibilityCollector(env, constants, grid)
#	a = AxialProjectionCollector(env, constants, grid, pulse=pulse)
	u = UncertaintyCollector(env, constants, grid)
	s = SpinCloudCollector(env, constants, grid)

	psi = gs.create((N, 0))

	psi.toMSpace()
	mode_data = numpy.abs(env.fromDevice(psi.data))[0, 0] # remember mode data
	mask = buildProjectorMask(constants, grid)
	psi.toXSpace()

	psi.toWigner(128)
	pulse.apply(psi, numpy.pi / 2)
	evolution.run(psi, splitting_time, callbacks=[v, n, u, s],
		callback_dt=splitting_time / 100)
	env.synchronize()
	env.release()

	"""
	times, heightmap = a.getData()
	HeightmapPlot(
		HeightmapData("test", heightmap,
			xmin=0, xmax=splitting_time * 1e3,
			ymin=grid.z[0] * 1e6,
			ymax=grid.z[-1] * 1e6,
			zmin=-1, zmax=1,
			xname="T (ms)", yname="z ($\\mu$m)", zname="Spin projection")
	).save('split_potentials_axial.pdf')
	"""

	times, n_stddev, xi_squared = u.getData()
	XYData("Squeezing", times * 1000, numpy.log10(xi_squared),
		xname="T (ms)", yname="log$_{10}$($\\xi^2$)",
		description=parameters).save('split_potentials_xi.json')


	times, vis = v.getData()
	XYData('test', times * 1e3, vis,
		xname="T (ms)", yname="$\\mathcal{V}$",
		ymin=0, ymax=1,
		description=parameters).save('split_potentials_vis.json')


	times, phi, yps, Sx, Sy, Sz = s.getData()
	return times, Sx, Sy, Sz
예제 #2
0
def runTest(env, dim, grid_type, prop_type, use_cutoff, use_big_grid):

	# additional parameters
	constants_kwds = {
		'1d': dict(use_effective_area=True, fx=42e3, fy=42e3, fz=90),
		'3d': {}
	}[dim]

	# total number of atoms in ground state
	total_N = {
		'1d': 60,
		'3d': 50000
	}[dim]

	# number of lattice points (for no cutoff mode)
	shape = {
		('1d', 'uniform'): (64,),
		('3d', 'uniform'): (128, 8, 8),
		('1d', 'harmonic'): (50,),
		('3d', 'harmonic'): (50, 10, 10)
	}[(dim, grid_type)]

	# time step for split-step propagation
	ss_dt = {
		'1d': 1e-6,
		'3d': 1e-5
	}[dim]

	e_cut = {
		'1d': 12000,
		'3d': 3000
	}[dim]

	total_time = {
		'1d': 0.1,
		'3d': 1.0
	}[dim]

	# Prepare constants and grid
	constants = Constants(double=env.supportsDouble(),
		e_cut=(e_cut if use_cutoff else None),
		**constants_kwds)

	if grid_type == 'uniform':
		if use_cutoff:
			box_size = constants.boxSizeForN(total_N, len(shape))
			min_shape = constants.planeWaveModesForCutoff(box_size)

			# FFT supports 2**n dimensions only
			shape = tuple([2 ** (log2(x - 1) + 1) for x in min_shape])

			if use_big_grid:
				shape = tuple([2 * x for x in shape])

		grid = UniformGrid.forN(env, constants, total_N, shape)
	elif grid_type == 'harmonic':
		if use_cutoff:
			shape = constants.harmonicModesForCutoff(len(shape))
			if use_big_grid:
				shape = tuple([x + 3 for x in shape])

		grid = HarmonicGrid(env, constants, shape)

	if grid_type == 'uniform':
		gs = SplitStepGroundState(env, constants, grid, dt=ss_dt)
	elif grid_type == 'harmonic':
		gs = RK5HarmonicGroundState(env, constants, grid, eps=1e-7)

	if grid_type == 'harmonic':
		evolution = RK5HarmonicEvolution(env, constants, grid,
			atol_coeff=1e-3, eps=1e-6, Nscale=total_N)
	elif prop_type == 'split-step':
		evolution = SplitStepEvolution(env, constants, grid, dt=ss_dt)
	elif prop_type == 'rk5':
		evolution = RK5IPEvolution(env, constants, grid, Nscale=total_N,
			atol_coeff=1e-3, eps=1e-6)

	pulse = Pulse(env, constants, grid, f_detuning=41, f_rabi=350)

	a = AxialProjectionCollector(env, constants, grid, pulse=pulse)
	p = ParticleNumberCollector(env, constants, grid, pulse=pulse)
	v = VisibilityCollector(env, constants, grid)

	# experiment
	psi = gs.create((total_N, 0))

	pulse.apply(psi, theta=0.5 * numpy.pi)

	t1 = time.time()
	evolution.run(psi, total_time, callbacks=[a, p, v], callback_dt=0.005)
	env.synchronize()
	t2 = time.time()

	times, heightmap = a.getData()

	# check that the final state is still projected
	psi.toMSpace()
	mode_data = env.fromDevice(psi.data)
	mask = numpy.tile(buildProjectorMask(constants, grid),
		(psi.components, 1) + (1,) * grid.dim)
	masked_mode_data = mode_data * (1.0 - mask)
	assert masked_mode_data.max() < 1e-6 * mode_data.max()

	res = HeightmapPlot(
		HeightmapData("test", heightmap,
			xmin=0, xmax=total_time * 1e3,
			ymin=grid.z[0] * 1e6,
			ymax=grid.z[-1] * 1e6,
			zmin=-1, zmax=1,
			xname="T (ms)", yname="z ($\\mu$m)", zname="Spin projection")
	)

	times, Ns, Ntotals = p.getData()
	times, vis = v.getData()

	print ("  Shape: {shape}, final N: {N} ({Ntotal}), V: {vis}\n" +
		"  Time spent: {t} s").format(
		shape=shape, N=Ns[:,-1], Ntotal=Ntotals[-1], vis=vis[-1], t=t2-t1)

	return res
예제 #3
0
def runTest(env, comp, grid_type, dim, gs_type, use_cutoff):
	"""
	Creates Thomas-Fermi ground state using different types of representations
	"""

	# additional parameters
	constants_kwds = {
		'1d': dict(use_effective_area=True, fx=42e3, fy=42e3, fz=90),
		'3d': {}
	}[dim]

	# total number of atoms in ground state
	total_N = {
		'1d': 60,
		'3d': 50000
	}[dim]

	# number of lattice points
	shape = {
		('1d', 'uniform'): (64,),
		('3d', 'uniform'): (128, 8, 8),
		('1d', 'harmonic'): (50,),
		('3d', 'harmonic'): (50, 10, 10)
	}[(dim, grid_type)]

	# time step for split-step propagation
	ss_dt = {
		'1d': 1e-6,
		'3d': 1e-5
	}[dim]

	# absolute precision for split-step algorithm
	ss_precision = {
		'1comp': 1e-6,
		'2comp': 1e-8
	}[comp]

	# precision divided by time step for RK5 propagation
	rk5_rprecision = {
		('1d', '1comp'): 1,
		('3d', '1comp'): 1,
		('1d', '2comp'): 1e-2,
		('3d', '2comp'): 1e-3
	}[(dim, comp)]

	# relative error tolerance for RK5 propagation
	rk5_rtol = {
		('1d', 'uniform'): 1e-9,
		('1d', 'harmonic'): 1e-7,
		('3d', 'uniform'): 1e-6,
		('3d', 'harmonic'): 1e-6
	}[(dim, grid_type)]

	# absolute error tolerance divided by atom number for RK5 propagation
	rk5_atol_coeff = 2e-3

	target_N = {
		'1comp': (total_N, 0),
		'2comp': (int(total_N / 2 + 0.05 * total_N), int(total_N / 2 - 0.05 * total_N))
	}[comp]

	e_cut = {
		'1d': 8000,
		'3d': 7000
	}[dim]

	# Prepare constants and grid
	constants = Constants(double=env.supportsDouble(),
		e_cut=(e_cut if use_cutoff else None),
		**constants_kwds)
	if grid_type == 'uniform':
		grid = UniformGrid.forN(env, constants, total_N, shape)
	elif grid_type == 'harmonic':
		grid = HarmonicGrid(env, constants, shape)

	# Prepare 'apparatus'

	args = (env, constants, grid)

	if gs_type == "TF":
		gs = TFGroundState(*args)
		gs_kwds = {}
	elif gs_type == "split-step":
		gs = SplitStepGroundState(*args, dt=ss_dt)
		gs_kwds = dict(precision=ss_precision)
	elif gs_type == "rk5":
		params = dict(eps=rk5_rtol, atol_coeff=rk5_atol_coeff)
		gs_kwds = dict(relative_precision=rk5_rprecision)
		if grid_type == 'uniform':
			gs = RK5IPGroundState(*args, **params)
		elif grid_type == 'harmonic':
			gs = RK5HarmonicGroundState(*args, **params)

	# Create ground state
	t1 = time.time()
	psi = gs.create(target_N, **gs_kwds)
	t2 = time.time()
	t_gs = t2 - t1

	prj = ProjectionMeter.forPsi(psi)
	obs = IntegralMeter.forPsi(psi)

	# check that 2-component stats object works properly
	N_xspace1 = psi.density_meter.getNTotal()
	psi.toMSpace()
	N_mspace = psi.density_meter.getNTotal()
	mode_data = numpy.abs(env.fromDevice(psi.data)) # remember mode data
	psi.toXSpace()

	# population in x-space after double transformation (should not change)
	N_xspace2 = psi.density_meter.getNTotal()

	# calculate energy and chemical potential (per particle)
	E = obs.getEPerParticle(psi) / constants.hbar / constants.wz
	mu = obs.getMuPerParticle(psi) / constants.hbar / constants.wz
	mu_tf = numpy.array(
		[constants.muTF(N, dim=grid.dim) for N in target_N]
	).sum() / constants.hbar / constants.wz

	# Checks
	norm = numpy.linalg.norm
	target_norm = norm(numpy.array(target_N))

	# check that number of particles right after GS creation is correct
	assert N_xspace1.shape == (2,)
	assert norm(N_xspace1 - numpy.array(target_N)) / target_norm < 1e-6

	# check that double transform did not change N
	assert norm(N_xspace1 - N_xspace2) / target_norm < 1e-6

	# TODO: find out what causes difference even for uniform grid
	assert norm(N_mspace - N_xspace2) / target_norm < 0.02

	assert E.shape == (2,)
	assert mu.shape == (2,)

	if comp == '1comp':
		assert E[1] == 0
	else:
		assert E[1] != 0

	if comp == '1comp':
		assert mu[1] == 0
	else:
		assert mu[1] != 0

	# There should be some difference between analytical mu and numerical one,
	# so it is more of a sanity check
	assert abs(mu.sum() - mu_tf) / mu_tf < 0.35

	# Check that GS is really restricted by mask
	mask = numpy.tile(buildProjectorMask(constants, grid),
		(psi.components, 1) + (1,) * grid.dim)
	masked_mode_data = mode_data * (1.0 - mask)
	assert masked_mode_data.max() < 1e-6 * mode_data.max()

	E = E.sum()
	mu = mu.sum()
	Nx = N_xspace2.sum()
	Nm = N_mspace.sum()

	# Results
	print ("  Modes: {modes_num} out of {total_modes}\n" +
		"  N(x-space) = {Nx:.4f}, N(m-space) = {Nm:.4f}, " +
		"E = {E:.4f} hbar wz, mu = {mu:.4f} hbar wz\n" +
		"  Time spent: {t_gs} s").format(
		Nx=Nx, Nm=Nm, E=E, mu=mu, t_gs=t_gs, modes_num=int(mask.sum()), total_modes=mask.size)

	z = grid.z * 1e6 # cast to micrometers
	profile = prj.getZ(psi) / 1e6 # cast to micrometers^-1

	plots = [
		XYData(str(env) + ", " + grid_type + ", " + gs_type + " |" + str(i + 1) + ">",
			z, profile[i],
			xname="Z ($\\mu$m)", yname="Axial density ($\\mu$m$^{-1}$)", ymin=0,
			linestyle=('-' if i == 0 else '--'))
		for i in xrange(len(profile))
	]

	return plots[:(1 if comp == '1comp' else 2)]