Example #1
0
def prep_rows(prefixes, backplane, blocker, column_descs,
                 planet, moon=None, moon_length=0,
                 tiles=[], tiling_min=100, ignore_shadows=False,
                 start_index=1, allow_zero_rows=False):
    """Generates the metadata and returns a list of lists of strings. The inner
    list contains string representations for each column in one row of the
    output file. These will be concatenated with commas between them and written
    to the file. The outer list contains one list for each output row. The
    number of output rows can be zero or more.

    The tiles argument supports detailed listings where a geometric region is
    broken down into separate subregions. If the tiles argument is empty (which
    is the default), then this routine writes a summary file.

    If the tiles argument is not empty, then the routine writes a detailed file,
    which generally contains one record for each non-empty subregion. The tiles
    argument must be a list of boolean backplane keys, each equal to True for
    the pixels within the subregion. An additional column is added before the
    geometry columns, containing the index value of the associated tile.

    The first backplane in the list is treated differently. It should evaluate
    to an area roughly equal to the union of all the other backplanes. It is
    used as an overlay to all subsequent tiles.

    In a summmary listing, this routine writes one record per call, even if all
    values are null. In a detailed listing, only records associated with
    non-empty regions of the meshgrid are written.

    Input:
        prefixes        a list of the strings to appear at the beginning of the
                        line, up to and including the ring observation ID. Each
                        individual string should already be enclosed in quotes.
        backplane       backplane for the observation.
        blocker         the name of one moon that may be able to block or shadow
                        other bodies.
        column_descs    a list of column descriptions.
        planet          name of planet, uppercase, e.g., "SATURN".
        moon            optionally, the moon name to write into the record.
        moon_length     the character width of a column to contain moon names.
                        If zero (which is the default), then no moon name is
                        written into the record.
        tiles           an optional list of boolean backplane keys, used to
                        support the generation of detailed tabulations instead
                        of summary tabulations. See details above.
        tiling_min      the lower limit on the number of meshgrid points in a
                        region before that region is subdivided into tiles.
        ignore_shadows  True to ignore any mask constraints applicable to
                        shadowing or to the sunlit faces of surfaces.
        start_index     index to use for first subregion. Default 1.
        allow_zero_rows True to allow the function to return no rows. If False,
                        a row filled with null values will be returned if
                        necessary.
    """

    # Handle option for multiple tile sets
    if type(tiles) == tuple:
        rows = []
        local_index = start_index
        for tile in tiles:
            new_rows = prep_rows(prefixes, backplane, blocker, column_descs,
                                 planet, moon, moon_length,
                                 tile, tiling_min, ignore_shadows,
                                 local_index, allow_zero_rows=True)
            rows += new_rows
            local_index += len(tile) - 1

        if rows or allow_zero_rows:
            return rows

        return prep_rows(prefixes, backplane, blocker, column_descs,
                         planet, moon, moon_length,
                         [], tiling_min, ignore_shadows,
                         start_index, allow_zero_rows=False)

    # Handle a single set of tiles
    if tiles:
        global_area = backplane.evaluate(tiles[0]).vals
        subregion_masks = [np.logical_not(global_area)]

        if global_area.sum() < tiling_min:
            tiles = []
        else:
            for tile in tiles[1:]:
                mask = backplane.evaluate(tile).vals & global_area
                subregion_masks.append(np.logical_not(mask))
    else:
        subregion_masks = []

    # Initialize the list of rows
    rows = []

    # Create all the needed pixel masks
    excluded_mask_dict = {}
    for column_desc in column_descs:
        event_key = column_desc[0]
        mask_desc = column_desc[1]
        target = event_key[1]

        key = (target,) + mask_desc
        if key in excluded_mask_dict: continue

        excluded_mask_dict[key] = \
            construct_excluded_mask(backplane, target, planet, mask_desc,
                                    blocker, ignore_shadows)

    # Interpret the subregion list
    if tiles:
        indices = range(1,len(tiles))
    else:
        indices = [0]

    # For each subregion...
    for indx in indices:

        # Skip a subregion if it will be empty
        if indx != 0 and np.all(subregion_masks[indx]): continue

        # Initialize the list of columns
        prefix_columns = list(prefixes) # make a copy

        # Append the moon name if necessary
        if moon_length > 0:
            lmoon = len(moon)
            if lmoon > moon_length:
                entry = '"' + moon[:moon_length] + '"'
            else:
                entry = '"' + moon + (moon_length - lmoon) * ' ' + '"'

            prefix_columns.append(entry)

        # Insert the subregion index
        if subregion_masks:
            prefix_columns.append('%2d' % (indx + start_index - 1))

        # Append the backplane columns
        data_columns = []
        nothing_found = True

        # For each column...
        for column_desc in column_descs:
            event_key = column_desc[0]
            mask_desc = column_desc[1]

            # Fill in the backplane array
            if event_key[1] == NULL:
                values = oops.Scalar(0., True)
            else:
                values = backplane.evaluate(event_key)

            # Make a shallow copy and apply the new masks
            target = event_key[1]
            excluded = excluded_mask_dict[(target,) + mask_desc]
            values = values.mask_where(excluded)
            if len(subregion_masks) > 1:
                values = values.mask_where(subregion_masks[indx])
            elif len(subregion_masks) == 1:
                values = values.mask_where(subregion_masks[0])

            if not np.all(values.mask):
                nothing_found = False

            # Write the column using the specified format
            if len(column_desc) > 2:
                format = ALT_FORMAT_DICT[(event_key[0], column_desc[2])]
            else:
                format = FORMAT_DICT[event_key[0]]

            data_columns.append(formatted_column(values, format))

        # Save the row if it was completed
        if len(data_columns) < len(column_descs): continue # hopeless error
        if nothing_found and (indx > 0 or allow_zero_rows): continue
        rows.append(prefix_columns + data_columns)

    # Return something if we can
    if rows or allow_zero_rows:
        return rows

    return prep_rows(prefixes, backplane, blocker, column_descs,
                     planet, moon, moon_length,
                     [], 0, ignore_shadows, start_index,
                     allow_zero_rows=False)
Example #2
0
def prep_rows(prefixes,
              backplane,
              blocker,
              column_descs,
              planet,
              moon=None,
              moon_length=0,
              count_length=0,
              tiles=[],
              tiling_min=100,
              ignore_shadows=False):
    """Generates the metadata and returns a list of lists of strings. The inner
    list contains string representations for each column in one row of the
    output file. These will be concatenated with commas between them and written
    to the file. The outer list contains one list for each output row. The
    number of output rows can be zero or more.

    The tiles argument supports detailed listings where a geometric region is
    broken down into separate subregions. If the tiles argument is empty (which
    is the default), then this routine writes a summary file.

    If the tiles argument is not empty, then the routine writes a detailed file,
    which generally contains one record for each non-empty subregion. The tiles
    argument must be a list of boolean backplane keys, each equal to True for
    the pixels within the subregion. An additional column is added before the
    geometry columns, containing the index value of the associated tile.

    The first backplane in the list is treated differently. It should evaluate
    to an area roughly equal to the union of all the other backplanes. It is
    used as an overlay to all subsequent tiles.

    In a summmary listing, this routine writes one record per call, even if all
    values are null. In a detailed listing, only records associated with
    non-empty regions of the meshgrid are written.

    Input:
        prefixes        a list of the strings to appear at the beginning of the
                        line, up to and including the ring observation ID. Each
                        individual string should already be enclosed in quotes.
        backplane       backplane for the observation.
        blocker         the name of one moon that may be able to block or shadow
                        other bodies.
        column_descs    a list of column descriptions.
        planet          name of planet, uppercase, e.g., "SATURN".
        moon            optionally, the moon name to write into the record.
        moon_length     the character width of a column to contain moon names.
                        If zero (which is the default), then no moon name is
                        written into the record.
        count_length    the character width of a column to contain the number
                        if samples obtained on the body or within a tile; zero
                        (which is the default) to suppress this column.
        tiles           an optional list of boolean backplane keys, used to
                        support the generation of detailed tabulations instead
                        of summary tabulations. See details above.
        tiling_min      the lower limit on the number of meshgrid points in a
                        region before that region is subdivided into tiles.
        ignore_shadows  True to ignore any mask constraints applicable to
                        shadowing or to the sunlit faces of surfaces.
    """

    # Handle option for tiles
    if tiles:
        subregion_masks = [None]  # let zone indexing start at 1

        # Handle a 1-D set of regions
        if len(tiles) == 1:
            indices = range(1, len(tiles[0]) + 1)
            for tile in tiles[0]:
                mask = backplane.evaluate(tile).vals
                subregion_masks.append(np.logical_not(mask))

        # Handle a 2-D set of regions
        else:
            indices = range(1, len(tiles[0]) * len(tiles[1]) + 1)
            for tile1 in tiles[0]:
                mask1 = backplane.evaluate(tile1).vals
                for tile2 in tiles[1]:
                    mask2 = backplane.evaluate(tile2).vals & mask1
                    subregion_masks.append(np.logical_not(mask2))

        # Check size of tile
        pixels = 0
        for mask in subregion_masks[1:]:
            pixels += mask.size - np.count_nonzero(mask)

        if pixels < tiling_min:
            return []

    # Without tiling, the subregion index is zero
    else:
        indices = [0]
        subregion_masks = []

    # Create all the needed pixel masks
    excluded_mask_dict = {}
    for column_desc in column_descs:
        event_key = column_desc[0]
        mask_desc = column_desc[1]
        target = event_key[1]

        key = (target, ) + mask_desc
        if key in excluded_mask_dict: continue

        excluded_mask = construct_excluded_mask(backplane, target, planet,
                                                mask_desc, blocker,
                                                ignore_shadows)
        excluded_mask_dict[key] = excluded_mask

    # Initialize the list of rows
    rows = []

    # For each subregion...
    for indx in indices:

        # Skip a tile if it contains no pixels
        if indx != 0 and np.all(subregion_masks[indx]): continue

        # Initialize the list of columns
        prefix_columns = list(prefixes)  # make a copy

        # Append the moon name if necessary
        if moon_length > 0:
            lmoon = len(moon)
            if lmoon > moon_length:
                entry = '"' + moon[:moon_length] + '"'
            else:
                entry = '"' + moon + (moon_length - lmoon) * ' ' + '"'

            prefix_columns.append(entry)

        # Insert the subregion zone if necessary
        if tiles:
            prefix_columns.append('%2d' % indx)

        # Prepare the backplane columns
        data_columns = []

        # For each column...
        pixel_count = 0
        for column_desc in column_descs:
            event_key = column_desc[0]
            mask_desc = column_desc[1]

            # Fill in the backplane array
            if event_key[1] == NULL:
                values = oops.Scalar(0., True)
            else:
                values = backplane.evaluate(event_key)

            # Make a shallow copy and apply the new masks
            target = event_key[1]
            excluded = excluded_mask_dict[(target, ) + mask_desc]
            values = values.mask_where(excluded)
            if tiles:
                values = values.mask_where(subregion_masks[indx])

            if values.size > 1:
                pixel_count = max(pixel_count, values.unmasked())

            # Write the column using the specified format
            if len(column_desc) > 2:
                format = ALT_FORMAT_DICT[(event_key[0], column_desc[2])]
            else:
                format = FORMAT_DICT[event_key[0]]

            data_columns.append(formatted_column(values, format))

        # Save the row if it was completed
        if len(data_columns) < len(column_descs): continue  # hopeless error
        if indx > 0 and pixel_count == 0: continue

        # Generate the sample count column if necessary
        if count_length:
            count_str = str(pixel_count)
            lcount = len(count_str)
            if count_length > lcount:
                count_str = (count_length - lcount) * ' ' + count_str
            elif count_length < lcount:
                count_str = count_length * '9'  # truncate so it fits

            count_columns = [count_str]
        else:
            count_columns = []

        rows.append(prefix_columns + count_columns + data_columns)

    return rows
def process_file(root, name, index, files, selection="S"):

    # Don't abort if cspice throws a runtime error
    try:

        (volume_id, file_spec) = volume_and_filespec(root, name)

        roid = ring_observation_id(name)
        logstr = "%s  %4d/%4d  %s" % (volume_id, index, files, roid)
        print logstr,
        terminated_print = False

        i20 = name.index("20")
        year = int(name[i20:i20 + 4])
        if year < 2004:
            print "skipped"
            return

        prefixes = [
            '"' + volume_id + '"', '"' + file_spec + '"', '"' + roid + '"'
        ]

        # Create the observation object
        obs = uvis.from_file(os.path.join(root, name), enclose=True)

        # Get the target
        target = obs.dict["TARGET_NAME"].upper()
        if target in TRANSLATIONS.keys():
            target = TRANSLATIONS[target]

        print " " + target
        terminated_print = True

        # Create the backplane
        cad = obs.cadence

        if cad.steps <= MAX_TIMESTEPS:
            steps = cad.steps
            tstride = cad.tstride
        else:
            steps = MAX_TIMESTEPS
            tstride = (cad.time[1] - cad.time[0]) / steps

        time_vals = cad.tstart + tstride * np.arange(0.5, steps)

        if len(obs.shape) > 1:
            time = oops.Scalar(time_vals[:, np.newaxis])
        else:
            time = oops.Scalar(time_vals)

        backplane = oops.Backplane(obs, time=time)

        # Catch SPICE NOFRAMECONNECT exceptions before going any further
        ignore = backplane.right_ascension()

        # Define a list of moon names and the blocker moon
        if target in SYSTEM_NAMES and target != PLANET:
            blocker = target
            moon_names = [target]
        else:
            blocker = None
            moon_names = []

        # Write the summary files for the rings and for the planet
        if "S" in selection:
            meta.write_record(prefixes,
                              backplane,
                              blocker,
                              ring_summary,
                              RING_SUMMARY_COLUMNS,
                              PLANET,
                              ignore_shadows=True)

            meta.write_record(prefixes,
                              backplane,
                              blocker,
                              planet_summary,
                              PLANET_SUMMARY_COLUMNS,
                              PLANET,
                              moon=PLANET,
                              moon_length=NAME_LENGTH,
                              ignore_shadows=True)

        # Write the detailed files for the rings and for the planet
        if "D" in selection:
            meta.write_record(prefixes,
                              backplane,
                              blocker,
                              ring_detailed,
                              RING_DETAILED_COLUMNS,
                              PLANET,
                              tiles=RING_TILES,
                              ignore_shadows=True)

            meta.write_record(prefixes,
                              backplane,
                              blocker,
                              planet_detailed,
                              PLANET_DETAILED_COLUMNS,
                              PLANET,
                              moon=PLANET,
                              moon_length=NAME_LENGTH,
                              tiles=PLANET_TILES,
                              ignore_shadows=True)

        # Write the moon files
        for name in moon_names:
            if "S" in selection:
                meta.write_record(prefixes,
                                  backplane,
                                  blocker,
                                  moon_summary,
                                  MOON_SUMMARY_DICT[name],
                                  PLANET,
                                  moon=name,
                                  moon_length=NAME_LENGTH,
                                  ignore_shadows=True)

            if "D" in selection:
                meta.write_record(prefixes,
                                  backplane,
                                  blocker,
                                  moon_detailed,
                                  MOON_DETAILED_DICT[name],
                                  PLANET,
                                  moon=name,
                                  moon_length=NAME_LENGTH,
                                  tiles=MOON_TILE_DICT[name],
                                  ignore_shadows=True)

    # A RuntimeError is probably caused by missing spice data. There is
    # probably nothing we can do.
    except RuntimeError as e:

        if "NOFRAMECONNECT" in str(e):
            print "**** SPICE(NOFRAMECONNECT)"
            noframe_file.write(PREFIX + "\n")
        else:
            if not terminated_print: print
            print e

            error_file.write(40 * "*" + "\n" + logstr + "\n")
            error_file.write(str(e))
            error_file.write("\n\n")

    # Other kinds of errors are genuine bugs. For now, we just log the
    # problem, and jump over the image; we can deal with it later.
    except (AssertionError, AttributeError, IndexError, KeyError, LookupError,
            TypeError, ValueError, ZeroDivisionError,
            pyparsing.ParseException):

        if not terminated_print: print

        traceback.print_exc()
        error_file.write(40 * "*" + "\n" + logstr + "\n")
        error_file.write(traceback.format_exc())
        error_file.write("\n\n")
Example #4
0
def prep_rows(prefixes,
              backplane,
              blocker,
              column_descs,
              planet,
              moon=None,
              moon_length=0,
              tiles=[],
              tiling_min=100,
              ignore_shadows=False):
    """Generates the metadata and returns a list of lists of strings. The inner
    list contains string representations for each column in one row of the
    output file. These will be concatenated with commas between them and written
    to the file. The outer list contains one list for each output row. The
    number of output rows can be zero or more.

    The tiles argument supports detailed listings where a geometric region is
    broken down into separate subregions. If the tiles argument is empty (which
    is the default), then this routine writes a summary file.

    If the tiles argument is not empty, then the routine writes a detailed file,
    which generally contains one record for each non-empty subregion. The tiles
    argument must be a list of boolean backplane keys, each equal to True for
    the pixels within the subregion. An additional column is added before the
    geometry columns, containing the index value of the associated tile.

    The first backplane in the list is treated differently. It should evaluate
    to an area roughly equal to the union of all the other backplanes. It is
    used to ensure that tiling is suppressed when the region to be tiled is too
    small. If the number of meshgrid samples that are equal to True in this
    backplane is smaller than the limit specified by argument tiling_min, then
    no detailed record is written.

    In a summmary listing, this routine writes one record per call, even if all
    values are null. In a detailed listing, only records associated with
    non-empty regions of the meshgrid are written.

    Input:
        prefixes        a list of the strings to appear at the beginning of the
                        line, up to and including the ring observation ID. Each
                        individual string should already be enclosed in quotes.
        backplane       backplane for the observation.
        blocker         the name of one moon that may be able to block or shadow
                        other bodies.
        column_descs    a list of column descriptions.
        planet          name of planet, uppercase, e.g., "SATURN".
        moon            optionally, the moon name to write into the record.
        moon_length     the character width of a column to contain moon names.
                        If zero (which is the default), then no moon name is
                        written into the record.
        tiles           an optional list of boolean backplane keys, used to
                        support the generation of detailed tabulations instead
                        of summary tabulations. See details above.
        tiling_min      the lower limit on the number of meshgrid points in a
                        region before that region is subdivided into tiles.
        ignore_shadows  True to ignore any mask constraints applicable to
                        shadowing or to the sunlit faces of surfaces.
    """

    # Initialize the list of rows
    rows = []
    column_count = len(prefixes) + len(column_descs)

    # Decide whether to write a detailed record
    if tiles != []:
        test_area = backplane.evaluate(tiles[0])
        if test_area.sum() < tiling_min: return rows

    # Create all the needed pixel masks
    mask_dict = {}
    for column_desc in column_descs:
        event_key = column_desc[0]
        mask_desc = column_desc[1]

        target = event_key[1]
        construct_mask(mask_dict, backplane, target, planet, mask_desc,
                       blocker, ignore_shadows)

    # Interpret the subregion list
    if tiles == []:
        append_digits = 0
        indices = [0]
    else:
        indices = range(1, len(tiles))
        if indices[-1] < 10:
            append_digits = 1
        else:
            append_digits = 2

    # For each subregion...
    for index in indices:

        # Initialize the list of columns
        columns = []
        for item in prefixes:
            columns.append(item)

        if tiles == []:
            subregion_mask = False
        else:
            true_where_included = backplane.evaluate(tiles[index])
            subregion_mask = (~true_where_included).vals

        # Skip this output row if it will be empty
        if append_digits > 0:
            if np.all(subregion_mask): continue

            all_masks_are_empty = True
            for mask in mask_dict.values():
                if not np.all(mask & subregion_mask):
                    all_masks_are_empty = False
                    continue

            if all_masks_are_empty: continue

        # Append the moon name if necessary
        if moon_length > 0:
            column_count += 1
            lmoon = len(moon)
            if lmoon > moon_length:
                columns.append('"' + moon[:moon_length] + '"')
            else:
                columns.append('"' + moon + (moon_length - lmoon) * ' ' + '"')

        # Append the detailed record number if necessary
        if append_digits == 1:
            column_count += 1
            columns.append("%1d" % index)
        elif append_digits == 2:
            column_count += 1
            columns.append("%2d" % index)

        try:

            # For each column...
            for column_desc in column_descs:
                event_key = column_desc[0]
                mask_desc = column_desc[1]

                # Fill in the backplane array
                if event_key[1] == NULL:
                    values = oops.Scalar(0., True)
                else:
                    values = backplane.evaluate(event_key)

                # Make a shallow copy and apply the new masks
                target = event_key[1]
                mask = mask_dict[(target, ) + mask_desc]
                values = oops.Scalar(values.vals,
                                     mask | values.mask | subregion_mask)

                # Write the column using the specified format
                if len(column_desc) > 2:
                    format = ALT_FORMAT_DICT[(event_key[0], column_desc[2])]
                else:
                    format = FORMAT_DICT[event_key[0]]

                columns.append(formatted_column(values, format))

        # Save the row if it was completed
        finally:
            if len(columns) == column_count:
                rows.append(columns)

    return rows