def remote_filter_convolution(host_id, datacube_path, wavelengths, filters, keep_output=False):

    """
    This function ...
    :param host_id:
    :param datacube_path:
    :param wavelengths:
    :param filters:
    :param keep_output:
    :return:
    """

    # 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("filter-convolution"))
    remote.create_directory(remote_temp_path)

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

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

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

    # Upload the frame file
    datacube_name = fs.name(datacube_path)
    remote_datacube_path = fs.join(remote_temp_path, datacube_name)
    remote.upload(datacube_path, remote_temp_path, compress=True, show_output=True)

    # Debugging
    log.debug("Writing the wavelengths to the temporary local directory ...")
    local_wavelengths_path = fs.join(local_temp_path, "wavelengths.txt")
    np.savetxt(local_wavelengths_path, wavelengths)

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

    # Upload the kernel FITS file to the remote directory
    remote_wavelengths_path = fs.join(remote_temp_path, "wavelengths.txt")
    remote.upload(local_wavelengths_path, remote_temp_path, compress=True, show_output=True)

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

    # Create the script
    local_script_path = fs.join(local_temp_path, "make_images.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 standard modules\n")
    script_file.write("import numpy as np\n")
    script_file.write("\n")
    script_file.write("# Import the relevant PTS classes and modules\n")
    script_file.write("from pts.magic.core.image import Image\n")
    script_file.write("from pts.magic.core.frame import Frame\n")
    script_file.write("from pts.core.basics.filter import Filter\n")
    script_file.write("from pts.core.tools.logging import log\n")
    script_file.write("from pts.core.tools import filesystem as fs\n")
    script_file.write("\n")
    script_file.write("# Inform the user\n")
    script_file.write("log.info('Loading the datacube ...')\n")
    script_file.write("\n")
    script_file.write("# Open the datacube as an Image\n")
    script_file.write("datacube = Image.from_file('" + remote_datacube_path + "', always_call_first_primary=False)\n")
    script_file.write("\n")
    script_file.write("# Inform the user\n")
    script_file.write("log.info('Loading the wavelengths ...')\n")
    script_file.write("\n")
    script_file.write("# Load the wavelengths from the text file\n")
    script_file.write("wavelengths = np.loadtxt('" + remote_wavelengths_path + "')\n")
    script_file.write("\n")
    script_file.write("# Convert the frames from neutral surface brightness to wavelength surface brightness\n")
    script_file.write("for l in range(len(wavelengths)):\n")
    script_file.write("\n")
    script_file.write("    # Get the wavelength\n")
    script_file.write("    wavelength = wavelengths[l]\n")
    script_file.write("\n")
    script_file.write("    # Determine the name of the frame in the datacube\n")
    script_file.write("    frame_name = 'frame' + str(l)\n")
    script_file.write("\n")
    script_file.write("    # Divide this frame by the wavelength in micron\n")
    script_file.write("    datacube.frames[frame_name] /= wavelength\n")
    script_file.write("\n")
    script_file.write("    # Set the new unit\n")
    script_file.write("    datacube.frames[frame_name].unit = 'W / (m2 * arcsec2 * micron)'\n")
    script_file.write("\n")
    script_file.write("# Convert the datacube to a numpy array where wavelength is the third dimension\n")
    script_file.write("fluxdensities = datacube.asarray()\n")
    script_file.write("\n")
    script_file.write("# Inform the user\n")
    script_file.write("log.info('Creating the filters ...')\n")
    script_file.write("\n")
    script_file.write("filters = dict()\n")
    script_file.write("\n")
    for filter_name in filters:
        fltr = filters[filter_name]
        script_file.write("# Inform the user\n")
        script_file.write("log.info('Creating the " + str(fltr) + " filter')\n")
        script_file.write("\n")
        script_file.write("fltr = Filter.from_string('" + str(fltr) + "')\n")
        script_file.write("filters['" + filter_name + "'] = fltr\n")
        script_file.write("\n")
    script_file.write("# Inform the user\n")
    script_file.write("log.info('Performing the filter convolutions ...')\n")
    script_file.write("\n")
    script_file.write("# Loop over the filters, perform the convolution\n")
    script_file.write("for filter_name in filters:\n")
    script_file.write("\n")
    script_file.write("    log.info('Making the observed image for the ' + str(fltr) + ' filter ...')\n")
    script_file.write("    fltr = filters[filter_name]\n")
    script_file.write("    data = fltr.convolve(wavelengths, fluxdensities)\n")
    script_file.write("    frame = Frame(data)\n")
    script_file.write("    frame.unit = 'W/(m2 * arcsec2 * micron)'\n")
    script_file.write("    path = fs.join('" + remote_temp_path + "', filter_name + '.fits')\n")
    script_file.write("    frame.save(path)\n")

    # Write to disk
    script_file.close()

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

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

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

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

    # Remove the datacube in the remote directory
    remote.remove_file(remote_datacube_path)

    # Debugging
    log.debug("Downloading the convolved frames ...")

    # Download
    local_downloaded_temp_path = fs.join(fs.home(), fs.name(remote_temp_path))
    fs.create_directory(local_downloaded_temp_path)
    remote.download(remote_temp_path, local_downloaded_temp_path, compress=True, show_output=True)

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

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

    # Create a dictionary to contain the frames
    frames = dict()

    # Loop over the filters, load the frame
    for filter_name in filters:

        # Determine the path to the resulting FITS file
        path = fs.join(local_downloaded_temp_path, filter_name + ".fits")

        # Check whether the frame exists
        if not fs.is_file(path): raise RuntimeError("The image for filter " + str(filters[filter_name]) + " is missing")

        # Load the FITS file
        frame = Frame.from_file(path)

        # Add the frame to the dictionary
        frames[filter_name] = frame

    # Remove the downloaded temporary directory
    if not keep_output: fs.remove_directory(local_downloaded_temp_path)

    # Return the dictionary of frames
    return frames