예제 #1
0
def get_glm_earth_geometry(glm, nadir, ltgellipsever):
    x_1d = glm.x
    y_1d = glm.y
    x, y = np.meshgrid(x_1d, y_1d)  # Two 2D arrays of fixed grid coordinates
    z = np.zeros_like(x)

    # Figure out the approximate GLM earth coverage based on GOES data book.
    # Convert below to radians and plot in fixed grid coordinates.
    #     rect_span = np.radians(14.81)*satheight #minimum degrees
    #     circ_diam = np.radians(15.59)*satheight #minimum degrees
    rect_span = np.radians(
        15)  #minimum degrees - matches figure in GOES data book
    circ_diam = np.radians(16)  #minimum degrees
    glm_angle = np.sqrt(x * x + y * y)
    outside_glm_full_disk = ((np.abs(x) > rect_span / 2.0) |
                             (np.abs(y) > rect_span / 2.0) |
                             (glm_angle > circ_diam / 2.0))

    geofixCS, grs80lla = get_GOESR_coordsys(nadir)
    geofix_ltg, lla_ltg = get_GOESR_coordsys_alt_ellps(nadir, ltgellipsever)
    X, Y, Z = geofix_ltg.toECEF(x, y, z)

    # X, Y, Z = geofix_ltg.toECEF(x,y,z) gives the 3D, earth-centered,
    # earth-fixed position of the intersection of the satellite-relative fixed
    # grid angle with the lightning ellipse.

    # The 3D position (X,Y,Z) defines an implicit lon, lat, alt with respect to
    # the target earth surface. Here, we intersect with the grs80 earth surface.

    lon_ltg, lat_ltg, alt_ltg = grs80lla.fromECEF(X, Y, Z)
    lon_ltg.shape = x.shape
    lat_ltg.shape = y.shape

    return (x, y), (X, Y, Z), (lon_ltg, lat_ltg,
                               alt_ltg), outside_glm_full_disk
예제 #2
0
def get_glm_parallax_offsets(lon, lat, goes_ds):
    # Get parallax of glm files to goes projection
    x, y = get_abi_x_y(lat, lon, goes_ds)
    z = np.zeros_like(x)

    nadir = goes_ds.goes_imager_projection.longitude_of_projection_origin

    _, grs80lla = get_GOESR_coordsys(nadir)
    geofix_ltg, lla_ltg = get_GOESR_coordsys_alt_ellps(nadir)

    lon_ltg, lat_ltg, alt_ltg = grs80lla.fromECEF(*geofix_ltg.toECEF(x, y, z))

    return lon_ltg - lon, lat_ltg - lat
예제 #3
0
def subdivided_fixed_grid(kwargs,
                          process_flash_kwargs,
                          out_kwargs,
                          s=1,
                          x_pad=100 * 28.0e-6,
                          y_pad=100 * 28.0e-6):
    """

    Generator function to turn a single set of keyword arguments to
    grid_GLM_flashes into an s by s block of keyword arguments.

    x_pad and y_pad are padding in fixed grid coordinates used to increase the
    bounding box over which flashes are subset from the data file. A flash with
    a centroid near the edge of the target grid may have events within the
    grid, so we want to capture that flash too. Default is the equivalent of
    100 km at nadir.

    Yields (i,j) kwargs_ij, process_flash_kwargs_ij for each i,j subgrid.
    """
    # Convert padding into an integer multiple of dx
    n_x_pad = int(x_pad / kwargs['dx'])
    n_y_pad = int(y_pad / kwargs['dy'])
    x_pad = float(n_x_pad * kwargs['dx'])
    y_pad = float(n_y_pad * kwargs['dy'])

    pads = (n_x_pad, n_y_pad, x_pad, y_pad)

    x_sub_bnd = subdivide_bnd(kwargs['x_bnd'], kwargs['dx'], s=s)
    y_sub_bnd = subdivide_bnd(kwargs['y_bnd'], kwargs['dy'], s=s)
    log.debug((x_sub_bnd, y_sub_bnd))
    nadir_lon = process_flash_kwargs['nadir_lon']
    geofixcs, grs80lla = get_GOESR_coordsys(sat_lon_nadir=nadir_lon)

    for i, j in itertools.product(range(s), range(s)):
        kwargsij = kwargs.copy()
        prockwargsij = process_flash_kwargs.copy()
        x_bnd_i = x_sub_bnd[i:i + 2].copy()
        y_bnd_j = y_sub_bnd[j:j + 2].copy()
        # Make a copy of this and use it as target grid specs before
        # we modify to use as the flash selection bounding box.
        # These abut one other exactly.
        kwargsij['x_bnd'], kwargsij['y_bnd'] = x_bnd_i.copy(), y_bnd_j.copy()
        x_bnd_i[0] -= x_pad
        x_bnd_i[1] += x_pad
        y_bnd_j[0] -= y_pad
        y_bnd_j[1] += y_pad
        # This x_bnd and y_bnd are different from the one above in kwargsij.
        # They are used to subset the flashes, and therefore have additional
        # padding.
        prockwargsij['x_bnd'], prockwargsij['y_bnd'] = x_bnd_i, y_bnd_j

        # The line below guarantees overlap across the grids.
        # The flash selection bouning box and the target grid are the same
        kwargsij['x_bnd'], kwargsij['y_bnd'] = x_bnd_i, y_bnd_j

        # No need to do lon_bnd and lat_bnd because we subset in fixed grid
        # coordinates instead.
        prockwargsij['lon_bnd'], prockwargsij['lat_bnd'] = None, None

        outfile_prefix_base = out_kwargs['output_filename_prefix']
        outfile_prefix_base_ij = outfile_prefix_base + '-'
        outfile_prefix_base_ij += '{0:02d}-{1:02d}'.format(i, j)
        out_kwargs_ij = out_kwargs.copy()
        out_kwargs_ij['output_filename_prefix'] = outfile_prefix_base_ij

        # out_kwargs_ij['output_writer_cache'] = out_kwargs_ij['output_writer']
        preprocess_out = GridOutputPreprocess(
            pads=pads, writer=out_kwargs_ij['output_writer'])
        out_kwargs_ij['preprocess_out'] = preprocess_out
        out_kwargs_ij['output_writer'] = preprocess_out.capture_write_call

        log.debug(("SUBGRID", i, j, x_bnd_i, y_bnd_j, pads))

        yield (i, j), kwargsij, prockwargsij, out_kwargs_ij, pads
예제 #4
0
        dx = dy = view['resolution']
        nx, ny = view['pixelsEW'], view['pixelsNS']
        if 'centerEW' in view:
            x_ctr, y_ctr = view['centerEW'], view['centerNS']
        else:
            # won't be known for mesoscale sectors.
            # Assume that it's in ctr_lon, ctr_lat
            x_ctr, y_ctr = ctr_lon, ctr_lat
        x_bnd = (np.arange(nx, dtype='float') -
                 nx / 2.0) * dx + x_ctr + 0.5 * dx
        y_bnd = (np.arange(ny, dtype='float') -
                 ny / 2.0) * dy + y_ctr + 0.5 * dy
        x_bnd = np.asarray([x_bnd.min(), x_bnd.max()])
        y_bnd = np.asarray([y_bnd.min(), y_bnd.max()])

        geofixcs, grs80lla = get_GOESR_coordsys(sat_lon_nadir=nadir_lon)
        ctr_lon, ctr_lat, ctr_alt = grs80lla.fromECEF(
            *geofixcs.toECEF(x_ctr, y_ctr, 0.0))
        fixed_grid = geofixcs
        log.debug((x_bnd, y_bnd, dx, dy, nx, ny))
    else:
        dx, dy = args.dx, args.dy
        nadir_lon = -75.0
        nx, ny = 1000, 1000
        x_ctr, y_ctr = args.ctr_lon, args.ctr_lat
        x_bnd = (np.arange(nx, dtype='float') -
                 nx / 2.0) * dx + x_ctr + 0.5 * dx
        y_bnd = (np.arange(ny, dtype='float') -
                 ny / 2.0) * dy + y_ctr + 0.5 * dy
        x_bnd = np.asarray([x_bnd.min(), x_bnd.max()])
        y_bnd = np.asarray([y_bnd.min(), y_bnd.max()])
예제 #5
0
def grid_setup(args):
    from lmatools.grid.make_grids import write_cf_netcdf_latlon, write_cf_netcdf_noproj, write_cf_netcdf_fixedgrid
    from lmatools.grid.make_grids import dlonlat_at_grid_center, grid_h5flashfiles
    from glmtools.grid.make_grids import grid_GLM_flashes
    from glmtools.io.glm import parse_glm_filename
    from lmatools.io.LMA_h5_file import parse_lma_h5_filename
    from lmatools.grid.fixed import get_GOESR_grid, get_GOESR_coordsys

    # When passed None for the minimum event or group counts, the gridder will skip
    # the check, saving a bit of time.
    min_events = int(args.min_events)
    if min_events <= 1:
        min_events = None
    min_groups = int(args.min_groups)
    if min_groups <= 1:
        min_groups = None

    if args.is_lma:
        filename_parser = parse_lma_h5_filename
        start_idx = 0
        end_idx = 1
    else:
        filename_parser = parse_glm_filename
        start_idx = 3
        end_idx = 4

    glm_filenames = args.filenames
    base_filenames = [os.path.basename(p) for p in glm_filenames]
    try:
        filename_infos = [filename_parser(f) for f in base_filenames]
        # opsenv, algorithm, platform, start, end, created = parse_glm_filename(f)
        filename_starts = [info[start_idx] for info in filename_infos]
        filename_ends = [info[end_idx] for info in filename_infos]
    except ValueError:
        log.error("One or more GLM files has a non-standard filename.")
        log.error("Assuming that --start and --end have been passed directly.")

    from glmtools.io.glm import parse_glm_filename
    if args.start is not None:
        start_time = datetime.strptime(args.start[:19], '%Y-%m-%dT%H:%M:%S')
    else:
        start_time = min(filename_starts)
    if args.end is not None:
        end_time = datetime.strptime(args.end[:19], '%Y-%m-%dT%H:%M:%S')
    else:
        end_time = max(filename_ends)

    date = datetime(start_time.year, start_time.month, start_time.day)
    # grid_dir = os.path.join('/data/LCFA-production/', 'grid_test')
    # outpath = grid_dir+'/20%s' %(date.strftime('%y/%b/%d'))
    outpath = os.path.join(args.outdir, '20%s' % (date.strftime('%y/%b/%d')))
    if os.path.exists(outpath) == False:
        os.makedirs(outpath)
        # subprocess.call(['chmod', 'a+w', outpath, grid_dir+'/20%s' %(date.strftime('%y/%b')), grid_dir+'/20%s' %(date.strftime('%y'))])

    if args.fixed_grid:
        proj_name = 'geos'

        if (args.goes_position != 'none') & (args.goes_sector != 'none'):
            resln = nearest_resolution(args)
            view = get_GOESR_grid(position=args.goes_position,
                                  view=args.goes_sector,
                                  resolution=resln)
            nadir_lon = view['nadir_lon']
            dx = dy = view['resolution']
            nx, ny = view['pixelsEW'], view['pixelsNS']
            geofixcs, grs80lla = get_GOESR_coordsys(sat_lon_nadir=nadir_lon)

            if 'centerEW' in view:
                x_ctr, y_ctr = view['centerEW'], view['centerNS']
            elif args.goes_sector == 'meso':
                # use ctr_lon, ctr_lat to get the center of the mesoscale FOV
                x_ctr, y_ctr, z_ctr = geofixcs.fromECEF(
                    *grs80lla.toECEF(args.ctr_lon, args.ctr_lat, 0.0))
        elif (args.goes_position != 'none') & (args.goes_sector == 'none'):
            # Requires goes_position, a center, and a width. Fully flexible
            # in resolution, i.e., doesn't slave it to one of the GOES-R specs
            view = get_GOESR_grid(position=args.goes_position,
                                  view='full',
                                  resolution='1.0km')
            nadir_lon = view['nadir_lon']
            dx1km = dy1km = view['resolution']
            geofixcs, grs80lla = get_GOESR_coordsys(sat_lon_nadir=nadir_lon)
            x_ctr, y_ctr, z_ctr = geofixcs.fromECEF(
                *grs80lla.toECEF(args.ctr_lon, args.ctr_lat, 0.0))

            # Convert the specified resolution in km given by args.dx to
            # a delta in fixed grid coordinates using the 1 km delta from the
            # GOES-R PUG.
            dx, dy = args.dx * dx1km, args.dy * dy1km
            nx, ny = int(args.width / args.dx), int(args.height / args.dy)
        else:
            raise ValueError(
                "Gridding on the fixed grid requires "
                "goes_position and dx. For goes_sector='meso', also specify "
                "ctr_lon and ctr_lat. Without goes_sector, also include width "
                "and height.")
        x_bnd = (np.arange(nx, dtype='float') -
                 nx / 2.0) * dx + x_ctr + 0.5 * dx
        y_bnd = (np.arange(ny, dtype='float') -
                 ny / 2.0) * dy + y_ctr + 0.5 * dy
        x_bnd = np.asarray([x_bnd.min(), x_bnd.max()])
        y_bnd = np.asarray([y_bnd.min(), y_bnd.max()])

        geofixcs, grs80lla = get_GOESR_coordsys(sat_lon_nadir=nadir_lon)
        ctr_lon, ctr_lat, ctr_alt = grs80lla.fromECEF(
            *geofixcs.toECEF(x_ctr, y_ctr, 0.0))
        fixed_grid = geofixcs
        log.debug((x_bnd, y_bnd, dx, dy, nx, ny))

        output_writer = partial(write_cf_netcdf_fixedgrid, nadir_lon=nadir_lon)
    else:
        # Default
        proj_name = 'latlong'
        output_writer = write_cf_netcdf_latlon
        ctr_lat = float(args.ctr_lat)
        ctr_lon = float(args.ctr_lon)
        dx_km = float(args.dx) * 1.0e3
        dy_km = float(args.dy) * 1.0e3
        width, height = 1000.0 * float(args.width), 1000.0 * float(args.height)
        x_bnd_km = (-width / 2.0, width / 2.0)
        y_bnd_km = (-height / 2.0, height / 2.0)
        dx, dy, x_bnd, y_bnd = dlonlat_at_grid_center(ctr_lat,
                                                      ctr_lon,
                                                      dx=dx_km,
                                                      dy=dy_km,
                                                      x_bnd=x_bnd_km,
                                                      y_bnd=y_bnd_km)

    # tuples of the corners
    corners = np.vstack([(x_bnd[0], y_bnd[0]), (x_bnd[0], y_bnd[1]),
                         (x_bnd[1], y_bnd[1]), (x_bnd[1], y_bnd[0])])
    # print(x_bnd, y_bnd)

    if args.is_lma:
        gridder = grid_h5flashfiles
        output_filename_prefix = 'LMA'
    else:
        gridder = grid_GLM_flashes
        output_filename_prefix = 'GLM'

    grid_kwargs = dict(proj_name=proj_name,
                       base_date=date,
                       do_3d=False,
                       dx=dx,
                       dy=dy,
                       frame_interval=float(args.dt),
                       x_bnd=x_bnd,
                       y_bnd=y_bnd,
                       ctr_lat=ctr_lat,
                       ctr_lon=ctr_lon,
                       outpath=outpath,
                       min_points_per_flash=min_events,
                       output_writer=output_writer,
                       subdivide=args.subdivide_grid,
                       output_filename_prefix=output_filename_prefix,
                       spatial_scale_factor=1.0)

    if args.fixed_grid:
        grid_kwargs['fixed_grid'] = True
        grid_kwargs['nadir_lon'] = nadir_lon
    if args.split_events:
        grid_kwargs['clip_events'] = True
    if min_groups is not None:
        grid_kwargs['min_groups_per_flash'] = min_groups
    if args.is_lma:
        grid_kwargs['energy_grids'] = True
    else:
        grid_kwargs['energy_grids'] = ('total_energy', )
    if (proj_name == 'pixel_grid') or (proj_name == 'geos'):
        grid_kwargs['pixel_coords'] = fixed_grid
    grid_kwargs['ellipse_rev'] = args.ellipse_rev
    # if args.corner_points:
    # grid_kwargs['corner_pickle'] = args.corner_points
    return gridder, glm_filenames, start_time, end_time, grid_kwargs
예제 #6
0
def grid_setup(args):
    from lmatools.grid.make_grids import write_cf_netcdf_latlon, write_cf_netcdf_noproj, write_cf_netcdf_fixedgrid
    from lmatools.grid.make_grids import dlonlat_at_grid_center, grid_h5flashfiles
    from glmtools.grid.make_grids import grid_GLM_flashes
    from glmtools.io.glm import parse_glm_filename
    from lmatools.io.LMA_h5_file import parse_lma_h5_filename
    from lmatools.grid.fixed import get_GOESR_grid, get_GOESR_coordsys

    # When passed None for the minimum event or group counts, the gridder will skip
    # the check, saving a bit of time.
    min_events = int(args.min_events)
    if min_events <= 1:
        min_events = None
    min_groups = int(args.min_groups)
    if min_groups <= 1:
        min_groups = None

    if args.is_lma:
        filename_parser = parse_lma_h5_filename
        start_idx = 0
        end_idx = 1
    else:
        filename_parser = parse_glm_filename
        start_idx = 3
        end_idx = 4

    glm_filenames = args.filenames
    base_filenames = [os.path.basename(p) for p in glm_filenames]
    try:
        filename_infos = [filename_parser(f) for f in base_filenames]
        # opsenv, algorithm, platform, start, end, created = parse_glm_filename(f)
        filename_starts = [info[start_idx] for info in filename_infos]
        filename_ends = [info[end_idx] for info in filename_infos]
    except ValueError:
        log.error("One or more GLM files has a non-standard filename.")
        log.error("Assuming that --start and --end have been passed directly.")

    from glmtools.io.glm import parse_glm_filename
    if args.start is not None:
        start_time = datetime.strptime(args.start[:19], '%Y-%m-%dT%H:%M:%S')
    else:
        start_time = min(filename_starts)
    if args.end is not None:
        end_time = datetime.strptime(args.end[:19], '%Y-%m-%dT%H:%M:%S')
    else:
        # Used to use max(filename_ends), but on 27 Oct 2020, the filename
        # ends started to report the time of the last event in the file,
        # causing a slight leakage (usually less than a second) into the
        # next minute. This caused two minutes of grids to be produced for every
        # three twenty second files passed to this script.
        # Instead, we now assume every LCFA file is 20 s long, beginning with
        # the start time. No doubt in the future we will see filenames that no
        # longer start on an even minute boundary.
        end_time = max(filename_starts) + timedelta(0, 20)

    date = datetime(start_time.year, start_time.month, start_time.day)

    outpath = args.outdir

    if args.fixed_grid:
        proj_name = 'geos'

        if (args.goes_position != 'none') & (args.goes_sector != 'none'):
            resln = nearest_resolution(args)
            view = get_GOESR_grid(position=args.goes_position,
                                  view=args.goes_sector,
                                  resolution=resln)
            nadir_lon = view['nadir_lon']
            dx = dy = view['resolution']
            nx, ny = view['pixelsEW'], view['pixelsNS']
            geofixcs, grs80lla = get_GOESR_coordsys(sat_lon_nadir=nadir_lon)

            if 'centerEW' in view:
                x_ctr, y_ctr = view['centerEW'], view['centerNS']
            elif args.goes_sector == 'meso':
                # use ctr_lon, ctr_lat to get the center of the mesoscale FOV
                x_ctr, y_ctr, z_ctr = geofixcs.fromECEF(
                    *grs80lla.toECEF(args.ctr_lon, args.ctr_lat, 0.0))
        elif (args.goes_position != 'none') & (args.goes_sector == 'none'):
            # Requires goes_position, a center, and a width. Fully flexible
            # in resolution, i.e., doesn't slave it to one of the GOES-R specs
            view = get_GOESR_grid(position=args.goes_position,
                                  view='full',
                                  resolution='1.0km')
            nadir_lon = view['nadir_lon']
            dx1km = dy1km = view['resolution']
            geofixcs, grs80lla = get_GOESR_coordsys(sat_lon_nadir=nadir_lon)
            x_ctr, y_ctr, z_ctr = geofixcs.fromECEF(
                *grs80lla.toECEF(args.ctr_lon, args.ctr_lat, 0.0))

            # Convert the specified resolution in km given by args.dx to
            # a delta in fixed grid coordinates using the 1 km delta from the
            # GOES-R PUG.
            dx, dy = args.dx * dx1km, args.dy * dy1km
            nx, ny = int(args.width / args.dx), int(args.height / args.dy)
        else:
            raise ValueError(
                "Gridding on the fixed grid requires "
                "goes_position and dx. For goes_sector='meso', also specify "
                "ctr_lon and ctr_lat. Without goes_sector, also include width "
                "and height.")
        # Need to use +1 here to convert to xedge, yedge expected by gridder
        # instead of the pixel centroids that will result in the final image
        nx += 1
        ny += 1
        x_bnd = (np.arange(nx, dtype='float') -
                 (nx) / 2.0) * dx + x_ctr + 0.5 * dx
        y_bnd = (np.arange(ny, dtype='float') -
                 (ny) / 2.0) * dy + y_ctr + 0.5 * dy
        log.debug(("initial x,y_ctr", x_ctr, y_ctr))
        log.debug(("initial x,y_bnd", x_bnd.shape, y_bnd.shape))
        x_bnd = np.asarray([x_bnd.min(), x_bnd.max()])
        y_bnd = np.asarray([y_bnd.min(), y_bnd.max()])

        geofixcs, grs80lla = get_GOESR_coordsys(sat_lon_nadir=nadir_lon)
        ctr_lon, ctr_lat, ctr_alt = grs80lla.fromECEF(
            *geofixcs.toECEF(x_ctr, y_ctr, 0.0))
        fixed_grid = geofixcs
        log.debug((x_bnd, y_bnd, dx, dy, nx, ny))

        output_writer = partial(write_cf_netcdf_fixedgrid, nadir_lon=nadir_lon)
    else:
        # Default
        proj_name = 'latlong'
        output_writer = write_cf_netcdf_latlon
        ctr_lat = float(args.ctr_lat)
        ctr_lon = float(args.ctr_lon)
        dx_km = float(args.dx) * 1.0e3
        dy_km = float(args.dy) * 1.0e3
        width, height = 1000.0 * float(args.width), 1000.0 * float(args.height)
        x_bnd_km = (-width / 2.0, width / 2.0)
        y_bnd_km = (-height / 2.0, height / 2.0)
        dx, dy, x_bnd, y_bnd = dlonlat_at_grid_center(ctr_lat,
                                                      ctr_lon,
                                                      dx=dx_km,
                                                      dy=dy_km,
                                                      x_bnd=x_bnd_km,
                                                      y_bnd=y_bnd_km)

    # tuples of the corners
    corners = np.vstack([(x_bnd[0], y_bnd[0]), (x_bnd[0], y_bnd[1]),
                         (x_bnd[1], y_bnd[1]), (x_bnd[1], y_bnd[0])])
    # print(x_bnd, y_bnd)

    if args.is_lma:
        gridder = grid_h5flashfiles
        output_filename_prefix = 'LMA'
    else:
        gridder = grid_GLM_flashes
        output_filename_prefix = 'GLM'

    grid_kwargs = dict(
        proj_name=proj_name,
        base_date=date,
        do_3d=False,
        dx=dx,
        dy=dy,
        frame_interval=float(args.dt),
        x_bnd=x_bnd,
        y_bnd=y_bnd,
        ctr_lat=ctr_lat,
        ctr_lon=ctr_lon,
        outpath=outpath,
        min_points_per_flash=min_events,
        output_writer=output_writer,
        subdivide=args.subdivide_grid,
        output_filename_prefix=output_filename_prefix,
        output_kwargs={'scale_and_offset': args.output_scale_and_offset},
        spatial_scale_factor=1.0)

    if args.fixed_grid:
        grid_kwargs['fixed_grid'] = True
        grid_kwargs['nadir_lon'] = nadir_lon
    if args.split_events:
        grid_kwargs['clip_events'] = True
    if min_groups is not None:
        grid_kwargs['min_groups_per_flash'] = min_groups
    if args.is_lma:
        grid_kwargs['energy_grids'] = True
    else:
        grid_kwargs['energy_grids'] = ('total_energy', )
    if (proj_name == 'pixel_grid') or (proj_name == 'geos'):
        grid_kwargs['pixel_coords'] = fixed_grid
    grid_kwargs['ellipse_rev'] = args.ellipse_rev
    # if args.corner_points:
    # grid_kwargs['corner_pickle'] = args.corner_points
    return gridder, glm_filenames, start_time, end_time, grid_kwargs