def remote_convolution(image, kernel, host_id):

    """
    This function ...
    :param image:
    :param kernel:
    :param host_id:
    """

    # Check whether we are already connected to the specified remote host
    if host_id in connected_remotes and connected_remotes[host_id] is not None:
        remote = connected_remotes[host_id]
    else:

        # Debugging
        log.debug("Logging in to remote host ...")

        # Create a remote instance for the specified host ID
        remote = Remote()
        remote.setup(host_id)

    # Debugging
    log.debug("Creating temporary directory remotely ...")

    # Create a temporary directory to do the convolution
    remote_home_directory = remote.home_directory
    remote_temp_path = fs.join(remote_home_directory, time.unique_name("convolution"))
    remote.create_directory(remote_temp_path)

    # Debugging
    #log.debug("Uploading the kernel to the remote directory ...")

    # Upload the kernel FITS file to the remote directory
    #remote_kernel_path = fs.join(remote_temp_path, "kernel.fits")
    #remote.upload(kernel_path, remote_temp_path, new_name="kernel.fits", compress=True, show_output=True)

    # Debugging
    log.debug("Creating a local temporary directory ...")

    # Create a temporary directory locally to contain the frames
    local_temp_path = fs.join(fs.home(), time.unique_name("convolution"))
    fs.create_directory(local_temp_path)

    # Debugging
    log.debug("Saving the image frames to the temporary directory ...")

    # Save the frames
    local_frame_paths = []
    constant_frames = []
    for frame_name in image.frames:
        frame_path = fs.join(local_temp_path, frame_name + ".fits")

        # Only upload and convolve non-constant frames
        if not image.frames[frame_name].is_constant():

            image.frames[frame_name].save(frame_path)
            local_frame_paths.append(frame_path)

        else:

            log.debug("The " + frame_name + " frame is constant, so this won't be uploaded and convolved")
            constant_frames.append(frame_name)

    # Debugging
    log.debug("Saving the kernel to the temporary directory ...")
    local_kernel_path = fs.join(local_temp_path, "kernel.fits")
    kernel.save(local_kernel_path)

    # Debugging
    log.debug("Uploading the image frames to the remote directory ...")

    # Upload the frames
    remote_frame_paths = []
    for local_frame_path in local_frame_paths:

        # Determine the name of the local frame file
        frame_file_name = fs.name(local_frame_path)

        # Debugging
        log.debug("Uploading the " + fs.strip_extension(frame_file_name) + " frame ...")

        # Upload the frame file
        remote_frame_path = fs.join(remote_temp_path, frame_file_name)
        remote.upload(local_frame_path, remote_temp_path, new_name=frame_file_name, compress=True, show_output=True)
        remote_frame_paths.append(remote_frame_path)

    # Debugging
    log.debug("Uploading the kernel to the remote directory ...")

    # Upload the kernel
    remote_kernel_path = fs.join(remote_temp_path, "kernel.fits")
    remote.upload(local_kernel_path, remote_temp_path, new_name="kernel.fits", compress=True, show_output=True)

    # Debugging
    log.debug("Creating a python script to perform the convolution remotely ...")

    # Create a python script that does the convolution
    #script_file = tempfile.NamedTemporaryFile()
    #local_script_path = script_file.name

    local_script_path = fs.join(local_temp_path, "convolve.py")
    script_file = open(local_script_path, 'w')

    script_file.write("#!/usr/bin/env python\n")
    script_file.write("# -*- coding: utf8 -*-\n")
    script_file.write("\n")
    script_file.write("# Import astronomical modules\n")
    script_file.write("from astropy.units import Unit\n")
    script_file.write("\n")
    script_file.write("# Import the relevant PTS classes and modules\n")
    script_file.write("from pts.magic.core.frame import Frame\n")
    script_file.write("from pts.magic.core.image import Image\n")
    script_file.write("from pts.magic.core.kernel import ConvolutionKernel\n")
    script_file.write("from pts.core.tools.logging import log\n")
    script_file.write("\n")
    script_file.write("# Inform the user\n")
    script_file.write("log.info('Opening the kernel frame ...')\n")
    script_file.write("\n")
    script_file.write("# Open the kernel\n")
    script_file.write("kernel = ConvolutionKernel.from_file('" + remote_kernel_path + "')\n")
    script_file.write("\n")
    for remote_frame_path in remote_frame_paths:

        frame_name = fs.strip_extension(fs.name(remote_frame_path))

        script_file.write("# Inform the user\n")
        script_file.write("log.info('Opening the " + frame_name + " frame ...')\n")
        script_file.write("\n")
        script_file.write("# Open the frame\n")
        script_file.write("frame = Frame.from_file('" + remote_frame_path + "')\n")
        script_file.write("\n")
        script_file.write("# Inform the user\n")
        script_file.write("log.info('Convolving the " + frame_name + " frame ...')\n")
        script_file.write("\n")
        script_file.write("# Do the convolution and save the result\n")
        script_file.write("frame.convolve(kernel, allow_huge=True)\n")
        script_file.write("frame.save('" + remote_frame_path + "')\n") # overwrite the frame
        script_file.write("\n")

        #script_file.write("# Save the image\n")
        #script_file.write("image.save(" + remote_image_path + ")\n")

    # Write to disk
    #script_file.flush()
    script_file.close()

    # Debugging
    log.debug("Uploading the python script ...")

    # Upload the script file
    remote_script_path = fs.join(remote_temp_path, "convolve.py")
    remote.upload(local_script_path, remote_temp_path, new_name="convolve.py", show_output=True)

    # Close the local script (it is automatically removed)
    #script_file.close()

    # Debugging
    log.debug("Executing the script remotely ...")

    # Execute the script file remotely
    remote.execute("python " + remote_script_path, output=False, show_output=True)

    # Debugging
    log.debug("Downloading the results ...")

    # Download the resulting FITS file (the convolved image)
    #local_result_path = self.full_output_path("convolved.fits")
    #remote.download(remote_image_path, fs.directory_of(local_result_path), new_name="convolved.fits", compress=True)

    for remote_frame_path in remote_frame_paths:

        # Determine the name of the local frame file
        frame_file_name = fs.name(remote_frame_path)

        # Debugging
        log.debug("Downloading the " + fs.strip_extension(frame_file_name) + " frame ...")

        # Download
        remote.download(remote_frame_path, local_temp_path, new_name=frame_file_name, compress=True, show_output=True)

    # Remove the temporary directory on the remote's filesystem
    remote.remove_directory(remote_temp_path)

    # Load the result
    #self.image = Image.from_file(local_result_path)

    for frame_name in image.frames.keys():
        if frame_name in constant_frames: continue # Skip constant frames, these are not convolved
        local_frame_path = fs.join(local_temp_path, frame_name + ".fits")
        image.frames[frame_name] = Frame.from_file(local_frame_path)

    # Remove the local temporary directory
    fs.remove_directory(local_temp_path)