def METHOD_NAME(input_grid, output_grid=None, q=1, fov=1, shift=0, planner='estimate'):
	'''Construct a FourierTransform object.
	The most time-efficient Fourier transform method will be chosen according to actual or estimated performance.
	Parameters
	----------
	input_grid : Grid
		The grid that will be used for the Field passed to the Fourier transform.
	output_grid : None or Grid
		The grid of the resulting field. If it is None, a optimal grid will be chosen, according to `q` and `fov`.
	q : scalar or ndarray
		Describes how many samples to take in the Fourier domain. A value of 1 means critcally sampled in the Fourier domain.
	fov : scalar or ndarray
		Describes how far out the Fourier domain extends. A value of 1 means the same amount of samples as the spatial domain.
	shift : scalar or ndarray
		Describes by how much the Fourier domain should be shifted compared to the native sampling of FFT.
	planner : string
		If it is 'estimate', performance of the different methods will be estimated from theoretical complexity estimates.
		If it is 'measure', actual Fourier transforms will be performed to get the actual performance. The latter takes longer,
		but is more accurate.
	Returns
	-------
	FourierTransform
		The Fourier transform that was requested.
	'''
	from .fast_fourier_transform import FastFourierTransform, make_fft_grid, get_fft_parameters
	from .matrix_fourier_transform import MatrixFourierTransform
	from .naive_fourier_transform import NaiveFourierTransform
	if output_grid is not None:
		# Try to detect if the grid is compatible with an FFT grid.
		try:
			q, fov, shift = get_fft_parameters(output_grid, input_grid)
			# If we got this far, the output grid is a native FFT grid.
			# Remove output grid as its now completely defined by q, fov and shift parameters.
			output_grid = None
		except ValueError:
			# The grid is not a native FFT grid.
			pass
	if output_grid is None:
		# Choose between FFT and MFT
		if not (input_grid.is_regular and input_grid.is_('cartesian')):
			raise ValueError('For non-regular non-cartesian Grids, a Fourier transform is required to have an output_grid.')
		if input_grid.ndim not in [1, 2]:
			method = 'fft'
		else:
			output_grid = make_fft_grid(input_grid, q, fov, shift)
			if planner == 'estimate':
				# Estimate analytically from complexities.
				# Convert shapes to float to avoid potential overflows.
				N_in = input_grid.shape.astype('float') * q
				N_out = output_grid.shape.astype('float')
				if input_grid.ndim == 1:
					fft = 4 * N_in[0] * np.log2(N_in)
					mft = 4 * input_grid.size * N_out[0]
				else:
					fft = 4 * np.prod(N_in) * np.log2(np.prod(N_in))
					mft = 4 * (np.prod(input_grid.shape) * N_out[1] + np.prod(N_out) * input_grid.shape[0])
				if fft > mft:
					method = 'mft'
				else:
					method = 'fft'
			elif planner == 'measure':
				# Measure directly.
				fft = FastFourierTransform(input_grid, q, fov)
				mft = MatrixFourierTransform(input_grid, output_grid)
				a = input_grid.zeros(dtype='complex')
				fft_time = _time_it(lambda: fft.forward(a))
				mft_time = _time_it(lambda: mft.forward(a))
				if fft_time > mft_time:
					method = 'mft'
				else:
					method = 'fft'
	else:
		# Choose between MFT and Naive
		if input_grid.is_separated and input_grid.is_('cartesian') and output_grid.is_separated and output_grid.is_('cartesian') and input_grid.ndim in [1, 2]:
			method = 'mft'
		else:
			method = 'naive'
	# Make the Fourier transform
	if method == 'fft':
		return FastFourierTransform(input_grid, q, fov, shift)
	elif method == 'mft':
		return MatrixFourierTransform(input_grid, output_grid)
	elif method == 'naive':
		return NaiveFourierTransform(input_grid, output_grid)