示例#1
0
 def get_offset(self, overpass, wind, return_index=False):
     """
     Calculates the offset (the (x,y) distance) from the source
     to the maximum enhancement (the center of the plume)
     
     Args:
       *  overpass, a PST.Overpass instance
       *  wind, a PST.Wind instance
       *  return_index = False; optionally returns the index in
          the file with the closest point
     
     Output: 
       *  (x_offset, y_offset); the x and y distances to the 
          center plume from the source
     """
     # List [(x1, y1), (x2, y2), ...] for all points in the instance
     posns = [Geometry.CoordGeom(wind).coord_to_wind_basis(overpass.lat,overpass.lon,lat,lon) for (lat,lon) in zip(self.retrieval_latitude,self.retrieval_longitude)]
     
     # List of [V(x1, y1), V(x2, y2), ...] for all positions (xi, yi) in posns
     all_enhancements = [PlumeModel.V(x,y,wind.speed,1.,overpass.a) for (x,y) in posns]
     
     # Index of the maximum enhancement found in all_enhancements
     closest_index = all_enhancements.index(max(all_enhancements))
     
     # (x, y) distance of the max enhancement with respect to the source. This way distances are measured from the center of the plume
     x_offset,y_offset = posns[closest_index]
     
     if return_index:
         return (x_offset, y_offset, closest_index)
     else:
         return (x_offset, y_offset)
示例#2
0
 def distance(vertices, tlat, tlon, wind, shift=(0, 0)):
     """Takes in an array shape (4, 2) of
         [ [lon1 lat1],
           [lon2 lat2],...]
         and returns an equivalenty shaped array of
         [ [x1 y1],
           [x2 y2], ...]
         As measured by in the direction of the wind"""
     distance_array = []
     for i in range(4):
         lon, lat = vertices[i]
         x, y = Geometry.CoordGeom(wind).coord_to_wind_basis(
             tlat, tlon, lat, lon)
         distance_array.append((x - shift[0], -(y - shift[1])))
     return np.array(Geometry.convex_hull(distance_array))
示例#3
0
 def get_secondary_offset(self, overpass, wind, return_index=False, secondary_sources=None):
     
     offset_positions = []
     if secondary_sources==None:
         secondary_sources = overpass.source.secondary
     for secondary in secondary_sources:
         # List [(x1, y1), (x2, y2), ...] for all points in the instance
         posns = [Geometry.CoordGeom(wind).coord_to_wind_basis(secondary.lat,secondary.lon,lat,lon) for (lat,lon) in zip(self.retrieval_latitude,self.retrieval_longitude)]
         
         # List of [V(x1, y1), V(x2, y2), ...] for all positions (xi, yi) in posns
         all_enhancements = [PlumeModel.V(x,y,wind.speed,1.,overpass.a) for (x,y) in posns]
         
         # Index of the maximum enhancement found in all_enhancements
         closest_index = all_enhancements.index(max(all_enhancements))
         
         # (x, y) distance of the max enhancement with respect to the source. This way distances are measured from the center of the plume
         x_offset,y_offset = posns[closest_index]
         if return_index:
             offset_positions.append((x_offset, y_offset, closest_index))
         else:
             offset_positions.append((x_offset, y_offset))
     return offset_positions
示例#4
0
def main(overpass, fname, **kwargs):
    params = defaults
    params.update(**kwargs)

    bg_kwargs = {
        'background_factor': params.f_background,
        'ymax_positive': params.y_max_positive,
        'ymax_negative': params.y_max_negative,
        'ymin_negative': params.y_min_negative,
        'ymin_positive': params.y_min_positive,
        'offset': params.offset,
        'sign': params.direction
    }

    filt_args = {
        'chi_squared_max': params.chi_squared_max,
        'snr_strong_co2_min': params.snr_strong_co2_min,
        'albedo_min': params.albedo_min,
        'albedo_max': params.albedo_max,
        'outcome_flags': params.outcome_flags,
        'surface_pressure_min': params.surface_pressure_min,
        'surface_pressure_max': params.surface_pressure_max
    }

    plume_args = dict(plume_factor=params.f_plume, xmax=params.x_max)

    print "Creating subplots"
    # Initialize gridspecs for the different panels
    obs_gs = gridspec.GridSpec(*params._shape)
    obs_gs.update(**params._obs_grid)

    mod_gs = gridspec.GridSpec(*params._shape)
    mod_gs.update(**params._mod_grid)

    cbar_gs = gridspec.GridSpec(*params._shape)
    cbar_gs.update(**params._cbar_grid)

    fig = plt.figure(figsize=params._size)

    h, w = params._shape
    half_w = params._obs_width

    # add subplots using gridspecs
    obs_ax = fig.add_subplot(obs_gs[:params._obs_height, :half_w])

    mod_ax = fig.add_subplot(mod_gs[:int(h // 2), half_w:])
    modfull_ax = fig.add_subplot(mod_gs[int(h // 2):, half_w:])

    cbar_ax = fig.add_subplot(cbar_gs[params._cbar_height, :half_w])

    # set tick locations if the step sizes are specified
    if params.x_step:
        dx = params.x_step
        xticks = np.arange(int(dx * math.ceil(params.xlim[0] / dx)),
                           params.xlim[1] + 1., dx)
        obs_ax.set_xticks(xticks)
        mod_ax.set_xticks(xticks)
        modfull_ax.set_xticks(xticks)

    if params.y_step:
        dy = params.y_step
        yticks = np.arange(int(dy * math.ceil(params.ylim[0] / dy)),
                           params.ylim[1], dy)
        yticks_full = np.arange(int(dy * math.ceil(params.ylim[0] / dy)),
                                params.ylim[1] + 1., dy)
        obs_ax.set_yticks(yticks_full)
        mod_ax.set_yticks(yticks_full)
        modfull_ax.set_yticks(yticks)

    # add labels, titles, set fonts
    label_args = dict(fontsize=params._labelfont, fontname=params.font)
    obs_ax.set_xlabel(params._xlabel, **label_args)
    obs_ax.set_ylabel(params._ylabel, **label_args)
    modfull_ax.set_xlabel(params._xlabel, **label_args)

    mod_ax.tick_params('x', bottom='off', labelbottom='off')

    title_args = dict(fontsize=params._titlefont, fontname=params.font)
    obs_ax.set_title(params._obslabel, **title_args)
    mod_ax.set_title(params._modlabel, **title_args)

    # now start the real work, axes are set as much as we can right now

    a = params.stability if params.stability else overpass.a

    try:
        wind = getattr(overpass, params.wind_source)
    except AttributeError:
        raise AttributeError('Overpass has no wind source "%s"' %
                             params.wind_source)
    except Exception:
        raise
    wind = wind.rotate(params.wind_adjustment)

    windspeed = Formats.windspeedformat % wind.speed
    wind_direction = Formats.winddirectionformat % wind.bearing
    fig.suptitle(params._title % (overpass.info, windspeed, wind_direction),
                 **title_args)

    F = overpass.get_emissions(temporal_factors=params.temporal_factors)
    F.convert(Units._model_units)
    u = wind.speed

    free_secondary_emissions = [
        src.get_emissions(overpass, temporal_factors=params.temporal_factors)
        for src in params.secondary_sources
    ]

    fixed_secondary_emissions = [
        src.get_emissions(overpass, temporal_factors=params.temporal_factors)
        for src in params.fixed_secondary_sources
    ]
    all_emissions = [F] + free_secondary_emissions + fixed_secondary_emissions

    co2_var = "smoothed_{}_xco2" if params.smooth else "{}_xco2"
    co2_var = co2_var.format(params.bias_correction)

    print 'Running Model with parameters'
    model_results = ModelFit.Model(
        overpass,
        f_plume=params.f_plume,
        f_background=params.f_background,
        offset=params.offset,
        y_max_positive=params.y_max_positive,
        y_max_negative=params.y_max_negative,
        y_min_negative=params.y_min_negative,
        y_min_positive=params.y_min_positive,
        direction=params.direction,
        wind_adjustment=params.wind_adjustment,
        wind_sources=params.wind_source,
        smooth=params.smooth,
        surface_stability=a,
        stability=params.stability,
        temporal_factors=params.temporal_factors,
        bias_correction=params.bias_correction,
        LocalBackground=PlumeModel.InBackground,
        LocalInPlume=PlumeModel.InPlume,
        co2_source='xco2',
        custom_wind=None,
        snr_strong_co2_min=params.snr_strong_co2_min,
        chi_squared_max=params.chi_squared_max,
        albedo_min=params.albedo_min,
        albedo_max=params.albedo_max,
        outcome_flags=params.outcome_flags,
        surface_pressure_max=params.surface_pressure_max,
        surface_pressure_min=params.surface_pressure_min,
        background_average=params.background_average,
        secondary_sources=params.secondary_sources,
        fixed_secondary_sources=params.fixed_secondary_sources,
        x_max=params.x_max,
        scatter_plot=params.scatter_plot,
        force_winds=params.force_winds,
        units=params.units,
        sza_adjustments=params.sza_adjustments,
        weighted=params.weighted,
        uncertainty=params.uncertainty)
    _, _, n_plume, cor = model_results[0]

    if params.secondary_sources:
        coordinate = Geometry.CoordGeom(wind)
        posns_from_main = [(0, 0)] + [
            coordinate.coord_to_wind_basis(overpass.lat, overpass.lon,
                                           second.lat, second.lon)
            for second in params.secondary_sources
        ]
        x = [pair[0] for pair in posns_from_main]
        y = [pair[1] for pair in posns_from_main]

        if params.plot_offset:
            x_center, y_center = np.average(np.array([x, y]),
                                            axis=1,
                                            weights=([F] +
                                                     free_secondary_emissions))
            x_from_center = [x0 - x_center for x0 in x]
            y_from_center = [y0 - y_center for y0 in y]

            # indices of top and bottom sources
            neg_offset = y_from_center.index(max(y_from_center))
            pos_offset = y_from_center.index(min(y_from_center))

            ## -1*y because the y in wind-basis is left-handed but we want the
            ##  plots to be the regular right-handed system
            # offset of bottom source on plot
            pos_start = (x_from_center[pos_offset],
                         -1 * y_from_center[pos_offset])
            # offset of top source on plot
            neg_start = (x_from_center[neg_offset],
                         -1 * y_from_center[neg_offset])

        else:
            x_center, y_center = 0, 0

            pos_start = (0, 0)
            neg_start = (0, 0)

    else:
        x_center, y_center = (0, 0)

        pos_start = (0, 0)
        neg_start = (0, 0)

    c_offset = (x_center, y_center)

    x_min = params.xlim[0] * 1000.
    x_max = params.xlim[1] * 1000.
    y_min = params.ylim[0] * 1000.
    y_max = params.ylim[1] * 1000.

    print 'Opening full file for making plots'
    data = File.full(overpass)

    def distance(vertices, tlat, tlon, wind, shift=(0, 0)):
        """Takes in an array shape (4, 2) of
            [ [lon1 lat1],
              [lon2 lat2],...]
            and returns an equivalenty shaped array of
            [ [x1 y1],
              [x2 y2], ...]
            As measured by in the direction of the wind"""
        distance_array = []
        for i in range(4):
            lon, lat = vertices[i]
            x, y = Geometry.CoordGeom(wind).coord_to_wind_basis(
                tlat, tlon, lat, lon)
            distance_array.append((x - shift[0], -(y - shift[1])))
        return np.array(Geometry.convex_hull(distance_array))

    distances = np.array([
        distance(data.retrieval_vertex_coordinates[j],
                 overpass.lat,
                 overpass.lon,
                 wind,
                 shift=c_offset)
        for j in range(len(data.retrieval_vertex_coordinates))
    ])

    background = File.File()
    background_k = []

    plume = File.File()
    else_data = File.File()
    failed_quality_data = File.File()

    x_offset, y_offset = data.get_offset(overpass, wind)

    if params.secondary_sources:
        secondary_offsets = data.get_secondary_offset(
            overpass, wind, secondary_sources=params.secondary_sources)

    print 'Classifying points'

    verts = []
    observed_xco2 = []
    model_xco2 = []

    verts_qf = []
    observed_xco2_qf = []
    model_xco2_qf = []
    all_sources = params.secondary_sources + params.fixed_secondary_sources
    for i in range(len(data)):
        coordinate = Geometry.CoordGeom(wind)
        rlat = data.retrieval_latitude[i]
        rlon = data.retrieval_longitude[i]
        x, y = coordinate.coord_to_wind_basis(overpass.lat, overpass.lon, rlat,
                                              rlon)
        dist = Geometry.CoordGeom.cartesian_distance((x, y),
                                                     (x_offset, y_offset))

        in_background = PlumeModel.InBackground(x, y, dist, u, 1.0, a,
                                                **bg_kwargs)
        in_plume = PlumeModel.InPlume(x, y, u, F, a, **plume_args)
        for j, second in enumerate(params.secondary_sources):
            xs, ys = coordinate.coord_to_wind_basis(second.lat, second.lon,
                                                    rlat, rlon)
            dx, dy = secondary_offsets[j]
            secondary_dist = Geometry.CoordGeom.cartesian_distance((xs, ys),
                                                                   (dx, dy))
            in_secondary_background = PlumeModel.InBackground(
                xs, ys, secondary_dist, u, 1., a, **bg_kwargs)
            in_secondary_plume = PlumeModel.InPlume(xs, ys, u, 1., a,
                                                    **plume_args)

            in_background = in_background and in_secondary_background
            in_plume = in_plume or in_secondary_plume

        if in_plume:
            if data.quality(i, **filt_args):
                plume.append(data, i)
            else:
                failed_quality_data.append(data, i)

        elif in_background:
            if data.quality(i, **filt_args):
                background.append(data, i)
                background_k.append(data.k[i])
            else:
                failed_quality_data.append(data, i)

        else:
            if data.quality(i, **filt_args):
                else_data.append(data, i)
            else:
                failed_quality_data.append(data, i)

        x_shifted = x - c_offset[0]
        y_shifted = y + c_offset[1]

        if y_min <= y_shifted <= y_max and x_min <= x_shifted <= x_max:
            lat_row = int((y_max - y_shifted) // 1000)
            lon_col = int((x_shifted - x_min) // 1000)

            if params.sza_adjustments:
                sza = Geometry.SZA(data, wind)
                enhancement = sza.V(x, y, u, F, a, i)
            else:
                enhancement = PlumeModel.V(x, y, u, F, a)

            for ind, child in enumerate(all_sources):
                F_second = all_emissions[ind + 1]

                x_p, y_p = coordinate.coord_to_wind_basis(
                    overpass.lat, overpass.lon, child.lat, child.lon)
                xs, ys = (x - x_p, y - y_p)

                if params.sza_adjustments:
                    second_enhancement = sza.V(xs, ys, u, F_second, a, i)
                else:
                    second_enhancement = PlumeModel.V(xs, ys, u, F_second, a)

                enhancement += second_enhancement
            if data.quality(i, **filt_args):
                model_xco2.append(enhancement)
                verts.append(distances[i])
                observed_xco2.append(data[co2_var][i])
            else:
                model_xco2_qf.append(enhancement)
                verts_qf.append(distances[i])
                observed_xco2_qf.append(data[co2_var][i])

    if params.background_average:
        background_mean = background_average
    else:
        background_mean = np.mean(background[co2_var])
    background_mean_k = np.mean(background_k)
    background_n = len(background)

    model_xco2 = np.array(model_xco2)
    model_xco2 /= (background_mean * background_mean_k)
    model_xco2 += 1.

    model_xco2_qf = np.array(model_xco2_qf)
    model_xco2_qf /= (background_mean * background_mean_k)
    model_xco2_qf += 1.

    verts = np.array(verts)
    verts_qf = np.array(verts_qf)
    observed_xco2 = np.array(observed_xco2) / float(background_mean)
    observed_xco2_qf = np.array(observed_xco2_qf) / float(background_mean)

    print 'Making grid plot'
    observed_coll = PolyCollection(verts / 1000.,
                                   array=observed_xco2,
                                   edgecolors='none',
                                   cmap=params._cmap)

    observed_coll_qf = PolyCollection(verts_qf / 1000.,
                                      array=observed_xco2_qf,
                                      edgecolors='none',
                                      cmap=params._cmap,
                                      alpha=params.opacity)

    model_coll = PolyCollection(verts / 1000.,
                                array=model_xco2,
                                edgecolors='none',
                                cmap=params._cmap)

    model_coll_qf = PolyCollection(verts / 1000.,
                                   array=model_xco2_qf,
                                   edgecolors='none',
                                   cmap=params._cmap,
                                   alpha=params.opacity)

    collections = [observed_coll, observed_coll_qf, model_coll, model_coll_qf]

    for coll in collections:
        coll.set_clim(*params.clim)

    obs_ax.add_collection(observed_coll)
    obs_ax.add_collection(observed_coll_qf)

    mod_ax.add_collection(model_coll)
    mod_ax.add_collection(model_coll_qf)

    cbarticks = np.linspace(params.clim[0], params.clim[1], 5)
    cbar = fig.colorbar(observed_coll,
                        cax=cbar_ax,
                        orientation='horizontal',
                        use_gridspec=True,
                        ticks=cbarticks)

    cbar.set_label(params._cbarlabel, **label_args)
    cbar.ax.set_xticklabels([params._ctick_fmt.format(x) for x in cbarticks],
                            fontname=params.font)

    bg_mean = Formats.ppmformat % background_mean
    scor = Formats.ppmformat % cor

    # add model to plot
    print 'Calculating model values for grid plot'
    position_from_main = [(0, 0)]
    coordinate = Geometry.CoordGeom(wind)
    all_sources = params.secondary_sources + params.fixed_secondary_sources
    for second in all_sources:
        posn = coordinate.coord_to_wind_basis(overpass.lat, overpass.lon,
                                              second.lat, second.lon)
        position_from_main.append(posn)

    position_from_center = [(x - c_offset[0], y - c_offset[1])
                            for (x, y) in position_from_main]

    x_ax_absolute = np.arange(x_min, x_max + params._dx, params._dx)
    y_ax_absolute = np.arange(y_min, y_max + params._dy, params._dy)
    y_ax_absolute -= 0.5 * params._dy
    model_array = np.ones((len(y_ax_absolute), len(x_ax_absolute)))

    x_ax_plot = (x_ax_absolute - 0.5 * params._dx) / 1000.
    y_ax_plot = (y_ax_absolute - 0.5 * params._dx) / 1000.

    normalize = background_mean * background_mean_k
    for ind in range(len(position_from_main)):
        x_rel, y_rel = position_from_center[ind]
        x_ax = x_ax_absolute - x_rel
        y_ax = y_ax_absolute + y_rel
        F = all_emissions[ind]
        rows, cols = model_array.shape
        for row in range(rows):
            for col in range(cols):
                x, y = x_ax[col], y_ax[row]
                enhancements = PlumeModel.V(x, y, u, F, a) / normalize
                model_array[row, col] += enhancements

    mask_value = 1 + (params.clim[1] - 1) * (params._decay_threshold)
    model_array = np.ma.masked_less_equal(model_array, mask_value)

    modfull_ax.pcolormesh(x_ax_plot,
                          y_ax_plot,
                          model_array,
                          cmap=params._cmap,
                          vmin=params.clim[0],
                          vmax=params.clim[1])
    modfull_ax.grid(True)

    obs_ax.text(params._paneltext_x,
                params._paneltext_y,
                'a = {}\nBackground = {} ppm'.format(a, bg_mean),
                fontsize=params._textfont,
                fontname=params.font,
                transform=obs_ax.transAxes)

    obs_ax.text(params._paneltext_xspace,
                1 - params._paneltext_y,
                'Number of points in plume: %s\nR = %s' % (n_plume, scor),
                fontsize=params._textfont,
                verticalalignment='top',
                fontname=params.font,
                transform=obs_ax.transAxes)

    bounds = boundaries.Boundaries(obs_ax, mod_ax, modfull_ax)
    bounds.plot(a,
                pos_start,
                neg_start,
                params.plume_thresholds,
                params.background_thresholds,
                xmax=1000 * params.xlim[1],
                ymax=params.ylim[1],
                offset=params.offset)

    grid_axes = (obs_ax, mod_ax, modfull_ax)
    axes = (obs_ax, mod_ax, modfull_ax)
    for gax in grid_axes:
        gax.set_xlim(*params.xlim)
        gax.set_ylim(*params.ylim)
        gax.grid(True)

    for ax in grid_axes:
        Formats.set_tickfont(ax)

    fig.savefig(fname, dpi=params._DPI, bbox_inches='tight')
    print 'Saved figure as', fname
示例#5
0
def best_winds(overpass,
               adjust_min=-10,
               adjust_max=10,
               tolerance=2.5,
               f_plume=0.10,
               f_background=0.01,
               offset=3000.,
               y_max_positive=50.e3,
               y_max_negative=50.e3,
               y_min_negative=0.,
               y_min_positive=0.,
               direction='y',
               wind_adjustment=0.,
               smooth=False,
               surface_stability=True,
               stability="new",
               temporal_factors=False,
               bias_correction='corrected',
               LocalBackground=PlumeModel.InBackground,
               LocalInPlume=PlumeModel.InPlume,
               co2_source='xco2',
               snr_strong_co2_min=None,
               chi_squared_max=None,
               albedo_min=None,
               albedo_max=None,
               outcome_flags={1, 2},
               surface_pressure_min=None,
               surface_pressure_max=None,
               background_average=None,
               secondary_sources=False,
               fixed_secondary_sources=[],
               x_max=75.e3,
               scatter_plot=False,
               force_winds=None,
               units=Units.output_units,
               sza_adjustments=True,
               output_file=False,
               weighted=False,
               run_model=True):
    """Searches for the wind adjustment that gives the highest correlation.
    
    Searches between increasingly narrow wind adjustments for the wind
    direction that gives the highest correlation. It prints out
    the adjustment, and then runs the full model function with this
    best adjustment value (if run_model==True).
    
    Searches for 10 degrees by default outside the limits set
    by ECMWF and MERRA. This can be adjsuted with the adjust_min and
    adjust_max arguments. tolerance is the difference between the
    outside limits of adjusting the wind at which to consider
    the search accurate enough and return the value.
    """
    merra = overpass.MERRA
    ecmwf = overpass.ECMWF
    average_wind = overpass.Average

    direction_min = min(merra.bearing, ecmwf.bearing) + adjust_min
    direction_max = max(merra.bearing, ecmwf.bearing) + adjust_max

    starting_wind_speed = average_wind.speed

    adjust_min = direction_min - average_wind.bearing
    adjust_max = direction_max - average_wind.bearing

    first_adjustments = numpy.linspace(adjust_min, adjust_max, 9)

    ## First all the default arguments are dealt with, and then move on to actually classifying data and fitting model

    # Args to pass to full_file.quality(i,**kwargs) method
    quality_args = {
        'chi_squared_max': chi_squared_max,
        'snr_strong_co2_min': snr_strong_co2_min,
        'albedo_min': albedo_min,
        'albedo_max': albedo_max,
        'outcome_flags': outcome_flags,
        'surface_pressure_min': surface_pressure_min,
        'surface_pressure_max': surface_pressure_max
    }

    bg_kwargs = {
        'background_factor': f_background,
        'ymax_positive': y_max_positive,
        'ymax_negative': y_max_negative,
        'ymin_negative': y_min_negative,
        'ymin_positive': y_min_positive,
        'offset': offset,
        'sign': direction
    }

    plume_kwargs = {'xmax': x_max, 'plume_factor': f_plume}

    # if secondary_sources is passed a collection of sources, it uses those as the secondary sources
    if hasattr(secondary_sources, "__iter__"):
        secondary = secondary_sources

    elif secondary_sources == True:
        secondary = overpass.source.secondary

    else:
        secondary = []

    # get emissions for the overpass and make sure they're in g/s
    F = overpass.get_emissions(temporal_factors=temporal_factors)
    F.convert(Units._model_units)
    secondary_emissions = [
        src.get_emissions(overpass, temporal_factors=temporal_factors)(
            Units._model_units) for src in secondary
    ]
    all_emissions = [F] + secondary_emissions

    # atmospheric stability parameter
    if surface_stability == True:
        if stability == "new":
            a = overpass.a
        else:
            a = overpass.a_old
    elif surface_stability == False:
        a = overpass.a_elevated
    else:
        a = surface_stability
    print "Using reported emissions: {0}".format(F.convert_cp(units))
    print "Using atmospheric stability paramter a={0}".format(a)
    print("Opening and reading full file")
    full_file = File.full(overpass)

    # bias correction:
    if bias_correction not in File.allowed_bias_correction:
        raise ValueError(
            "bias correction must be one of {0}; given {1}".format(
                ', '.join(File.allowed_bias_correction), bias_correction))

    if not (co2_source == 'xco2' or co2_source == 'co2_column'):
        raise ValueError(
            "co2_source must be one of 'xco2' or 'co2_column' not '{0}'".
            format(co2_source))
    co2 = "{0}_{1}".format(bias_correction, co2_source)
    if smooth:
        co2 = 'smoothed_' + co2

    if sza_adjustments:
        print "Assigning a sign to the sensor zenith angle"
        full_file.sign_zenith_angle(overpass)

    # filtered_data has the same fields as ModelData but only the points that pass the quality filter
    filtered_data = full_file.filter(**quality_args)

    print "Adjusting the winds"
    delta = adjust_max - adjust_min
    while delta > tolerance:
        correlations = []
        adjustments = numpy.linspace(adjust_min, adjust_max, 9)
        WindSources = [average_wind.rotate(x) for x in adjustments]
        print "Adjustments"
        print adjustments

        in_plume_objects = []
        background_objects = []
        model_enhancement_lists = []
        model_alpha_lists = []
        fixed_enhancement_lists = []

        for wind in WindSources:
            height_list = [overpass.height
                           ] + [source.height for source in secondary]
            mean_height = numpy.average(height_list, weights=all_emissions)
            wind.height = mean_height

            plume_data = File.File()
            background_data = File.File()
            model_enhancements = []
            model_alpha = []
            fixed_enhancements = []

            # we already have a, F determined
            u = wind.speed

            # the offset (x,y) in wind basis components from the source to the center plume (highest enhancement)
            x_offset, y_offset = filtered_data.get_offset(overpass, wind)

            secondary_offsets = filtered_data.get_secondary_offset(
                overpass, wind, secondary_sources=secondary)
            fixed_emissions = [
                fixed.get_emissions(overpass,
                                    temporal_factors=temporal_factors)(
                                        Units._model_units)
                for fixed in fixed_secondary_sources
            ]

            for i in range(len(filtered_data)):
                coordinate = Geometry.CoordGeom(wind)
                x, y = coordinate.coord_to_wind_basis(
                    overpass.lat, overpass.lon,
                    filtered_data.retrieval_latitude[i],
                    filtered_data.retrieval_longitude[i])
                dist = Geometry.CoordGeom.cartesian_distance(
                    (x, y), (x_offset, y_offset))
                sza = Geometry.SZA(filtered_data, wind)

                in_background = PlumeModel.InBackground(
                    x, y, dist, u, F, a, **bg_kwargs)
                in_plume = PlumeModel.InPlume(x, y, u, F, a, **plume_kwargs)
                if secondary_sources:
                    for ind, secondary_src in enumerate(secondary):
                        SZA_secondary = Geometry.SZA(filtered_data, wind)
                        xs, ys = Geometry.CoordGeom(wind).coord_to_wind_basis(
                            secondary_src.lat, secondary_src.lon,
                            filtered_data.retrieval_latitude[i],
                            filtered_data.retrieval_longitude[i])
                        secondary_offset = secondary_offsets[ind]
                        secondary_dist = Geometry.CoordGeom.cartesian_distance(
                            (xs, ys), secondary_offset)
                        in_secondary_plume = PlumeModel.InPlume(
                            xs, ys, u, 1., a, **plume_kwargs)
                        in_plume = in_plume or in_secondary_plume

                        in_secondary_background = PlumeModel.InBackground(
                            xs, ys, secondary_dist, u, 1., a, **bg_kwargs)
                        in_background = in_background and in_secondary_background

                if in_background:
                    background_data.append(filtered_data, i)

                if in_plume:
                    total_enhancement = 0.  #enhancements from all sources
                    plume_data.append(filtered_data, i)
                    # get enhancement from main source, then add secondary sources
                    if sza_adjustments:
                        main_enhancement = sza.V(x, y, u, F, a, i)
                    else:
                        main_enhancement = PlumeModel.V(x, y, u, F, a)
                    alpha = [main_enhancement / F]
                    total_enhancement += main_enhancement

                    for ind, secondary_src in enumerate(secondary):
                        xs, ys = Geometry.CoordGeom(wind).coord_to_wind_basis(
                            secondary_src.lat, secondary_src.lon,
                            filtered_data.retrieval_latitude[i],
                            filtered_data.retrieval_longitude[i])
                        F_secondary = secondary_emissions[ind]

                        if sza_adjustments:
                            secondary_enhancement = sza.V(
                                xs, ys, u, F_secondary, a, i)
                        else:
                            secondary_enhancement = PlumeModel.V(
                                xs, ys, u, F_secondary, a)

                        total_enhancement += secondary_enhancement
                        alpha.append(secondary_enhancement / F_secondary)

                    model_enhancements.append([total_enhancement])
                    model_alpha.append(alpha)

                    fixed_enhancement = 0.
                    for ind, fixed in enumerate(fixed_secondary_sources):
                        xs, ys = Geometry.CoordGeom(wind).coord_to_wind_basis(
                            fixed.lat, fixed.lon,
                            filtered_data.retrieval_latitude[i],
                            filtered_data.retrieval_longitude[i])
                        F_fixed = fixed_emissions[ind]
                        if sza:
                            source_enhancement = sza.V(xs, ys, u, F_fixed, a,
                                                       i)
                        else:
                            source_enhancement = PlumeModel.V(
                                xs, ys, u, F_fixed, a)
                        fixed_enhancement += source_enhancement

                    fixed_enhancements.append(fixed_enhancement)

            in_plume_objects.append(plume_data)
            background_objects.append(background_data)
            model_enhancement_lists.append(numpy.array(model_enhancements))
            model_alpha_lists.append(numpy.array(model_alpha))
            fixed_enhancement_lists.append(numpy.array(fixed_enhancements))

        for (k, wind) in enumerate(WindSources):
            if len(in_plume_objects[k]) <= 2:
                correlations.append(0)
            else:
                try:
                    fixed_enhance = fixed_enhancement_lists[k] / numpy.mean(
                        background_objects[k].k)
                    cor = numpy.corrcoef(
                        in_plume_objects[k][co2] - fixed_enhance,
                        model_enhancement_lists[k].flatten())[0, 1]
                except:
                    raise
                correlations.append(cor)

        max_cor = max(correlations)
        max_index = correlations.index(max_cor)

        adjust_max = adjustments[min(8, max_index + 3)]
        adjust_min = adjustments[max(0, max_index - 3)]
        delta = abs(adjust_max - adjust_min)

    print "Maximum Correlation: {0}; with wind adjustment {1} relative to the average\n\n".format(
        max_cor, adjustments[max_index])

    if run_model:
        print "Running the model with the best wind..."

        return Model(overpass,
                     f_plume=f_plume,
                     f_background=f_background,
                     offset=offset,
                     y_max_positive=y_max_positive,
                     y_max_negative=y_max_negative,
                     y_min_negative=y_min_negative,
                     y_min_positive=y_min_positive,
                     direction=direction,
                     wind_adjustment=wind_adjustment,
                     wind_sources=None,
                     smooth=smooth,
                     surface_stability=surface_stability,
                     stability=stability,
                     temporal_factors=temporal_factors,
                     bias_correction=bias_correction,
                     LocalBackground=LocalBackground,
                     LocalInPlume=LocalInPlume,
                     co2_source=co2_source,
                     snr_strong_co2_min=snr_strong_co2_min,
                     chi_squared_max=chi_squared_max,
                     albedo_min=albedo_min,
                     albedo_max=albedo_max,
                     outcome_flags=outcome_flags,
                     background_average=background_average,
                     secondary_sources=secondary,
                     x_max=x_max,
                     scatter_plot=scatter_plot,
                     force_winds=[WindSources[max_index]],
                     units=units,
                     sza_adjustments=sza_adjustments,
                     weighted=weighted,
                     fixed_secondary_sources=fixed_secondary_sources)
示例#6
0
def Model(overpass,
          f_plume=0.10,
          f_background=0.01,
          offset=3000.,
          y_max_positive=50.e3,
          y_max_negative=50.e3,
          y_min_negative=0.,
          y_min_positive=0.,
          direction='y',
          wind_adjustment=0.,
          wind_sources=['Average'],
          smooth=False,
          surface_stability=True,
          stability="new",
          temporal_factors=False,
          bias_correction='corrected',
          LocalBackground=PlumeModel.InBackground,
          LocalInPlume=PlumeModel.InPlume,
          co2_source='xco2',
          custom_wind=None,
          snr_strong_co2_min=None,
          chi_squared_max=None,
          albedo_min=None,
          albedo_max=None,
          outcome_flags={1, 2},
          surface_pressure_max=None,
          surface_pressure_min=None,
          background_average=None,
          secondary_sources=False,
          fixed_secondary_sources=[],
          x_max=75.e3,
          scatter_plot=False,
          force_winds=None,
          units=Units.output_units,
          sza_adjustments=True,
          weighted=False,
          uncertainty=True):
    """Computes model enhancements for an overpass, and compares them to observed data.
    
    The behaviour is specified by the many default arguments. This function
    does everything needed including calculating model enhancements, but
    delegates the actual comparison to the ModelFunctions module. See
    the keyword list document for an explanation of the optional arguments
    """
    ## First all the default arguments are dealt with, and then move on to actually classifying data and fitting model

    # Args to pass to full_file.quality(i,**kwargs) method
    quality_args = {
        'chi_squared_max': chi_squared_max,
        'snr_strong_co2_min': snr_strong_co2_min,
        'albedo_min': albedo_min,
        'albedo_max': albedo_max,
        'outcome_flags': outcome_flags,
        'surface_pressure_min': surface_pressure_min,
        'surface_pressure_max': surface_pressure_max
    }

    bg_kwargs = {
        'background_factor': f_background,
        'ymax_positive': y_max_positive,
        'ymax_negative': y_max_negative,
        'ymin_negative': y_min_negative,
        'ymin_positive': y_min_positive,
        'offset': offset,
        'sign': direction
    }

    plume_kwargs = {'xmax': x_max, 'plume_factor': f_plume}
    if secondary_sources == False:
        secondary = []
        secondary_sources = False
    elif secondary_sources == True:
        secondary = overpass.source.secondary
        secondary_sources = True
    elif hasattr(secondary_sources, "__iter__"):
        secondary = secondary_sources
        secondary_sources = True
    else:
        raise TypeError("Invalid argument '{}' for secondary_sources.\
        Must be True, False, or iterable collection of PointSources".format(
            secondary_sources))

    # bias correction:
    if bias_correction not in File.allowed_bias_correction:
        raise ValueError(
            "bias correction must be one of {0}; given {1}".format(
                ', '.join(File.allowed_bias_correction), bias_correction))

    if not (co2_source == 'xco2' or co2_source == 'co2_column'):
        raise ValueError(
            "co2_source must be one of 'xco2' or 'co2_column' not '{0}'".
            format(co2_source))
    co2 = "{0}_{1}".format(bias_correction, co2_source)
    if smooth:
        co2 = 'smoothed_' + co2

    # get emissions for the overpass and make sure they're in g/s
    F = overpass.get_emissions(temporal_factors=temporal_factors)
    F.convert(Units._model_units)

    # atmospheric stability parameter
    if surface_stability == True:
        if stability == "new":
            a = overpass.a
        elif stability == "old":
            a = overpass.a_old
    elif surface_stability == False:
        a = overpass.a_elevated
    else:
        a = surface_stability

    secondary_emissions = [
        second.get_emissions(overpass)(Units._model_units)
        for second in secondary
    ]
    all_emissions = [F(units)] + [em(units) for em in secondary_emissions]
    total_emissions = F(units)
    for second in secondary_emissions:
        total_emissions += second(units)
    emissions_info = ', '.join([str(emi) for emi in all_emissions])
    sources_info = ', '.join(
        [src for src in [overpass.short] + [s.short for s in secondary]])

    print "Using reported emissions:", emissions_info
    print "For sources:", sources_info
    print "Total emissions:", total_emissions
    print "Using atmospheric stability parameter a={0}".format(a)

    print "Opening and reading full file"
    full_file = File.full(overpass)

    # force_winds is an override for forcing the model to run with a given list of Wind instances.
    # Useful for running the model with many wind adjustments
    if force_winds is None:
        all_winds = PST.AllWinds(overpass)
        try:
            WindSources, wind_labels = all_winds.parse(wind_sources)
            WindSources = [wnd.rotate(wind_adjustment) for wnd in WindSources]
        except Exception as exc:
            WindSources, wind_labels = [], []
            print "Exception raised and ignored:", exc

        try:
            custom_winds, custom_labels = all_winds.add_custom(custom_wind)
        except ValueError as ve:
            print "custom_wind value was not valid. See message:", ve
        except Exception as sxc:
            print "Unexpected error occured:", sxc
        else:
            WindSources.extend(custom_winds)
            wind_labels.extend(custom_labels)
    else:
        WindSources = force_winds
        wind_labels = [str(wind) for wind in force_winds]

    if sza_adjustments:
        print "Assigning a sign to the sensor zenith angle"
        full_file.sign_zenith_angle(overpass)

    # filtered_data has the same fields as full_file but only the points that pass the quality filter
    filtered_data = full_file.filter(**quality_args)

    print "Classifying points"
    in_plume_objects = []
    background_objects = []
    model_enhancement_lists = []
    model_alpha_lists = []
    fixed_enhancement_lists = []

    for wind in WindSources:
        # set wind.height to the weighted (by emissions) average height
        height_list = [overpass.height
                       ] + [source.height for source in secondary]
        mean_height = numpy.average(height_list, weights=all_emissions)
        wind.height = mean_height

        plume_data = File.File()
        background_data = File.File()
        model_enhancements = []  # will be column vector [ [V1], [V2], ... ]
        model_alpha = []  # will be matrix A from math docs
        fixed_enhancements = []  # list of enhancements from fixed sources

        # we already have a, F determined
        u = wind.speed

        # the offset (x,y) in wind basis components from the source to the center plume (highest enhancement)
        x_offset, y_offset = filtered_data.get_offset(overpass, wind)

        # same as above offset but for each secondary source
        secondary_offsets = filtered_data.get_secondary_offset(
            overpass, wind, secondary_sources=secondary)

        # emissons of all the fixed secondary sources
        fixed_emissions = [
            fixed.get_emissions(overpass, temporal_factors=temporal_factors)(
                Units._model_units) for fixed in fixed_secondary_sources
        ]

        for i in range(len(filtered_data)):
            coordinate = Geometry.CoordGeom(wind)
            x, y = coordinate.coord_to_wind_basis(
                overpass.lat, overpass.lon,
                filtered_data.retrieval_latitude[i],
                filtered_data.retrieval_longitude[i])
            dist = Geometry.CoordGeom.cartesian_distance((x, y),
                                                         (x_offset, y_offset))

            sza = Geometry.SZA(filtered_data, wind)

            # check if point is in background or in plume, including secondary sources
            in_background = PlumeModel.InBackground(x, y, dist, u, F, a,
                                                    **bg_kwargs)
            in_plume = PlumeModel.InPlume(x, y, u, F, a, **plume_kwargs)
            if secondary_sources:
                for ind, secondary_src in enumerate(secondary):
                    SZA_secondary = Geometry.SZA(filtered_data, wind)
                    xs, ys = Geometry.CoordGeom(wind).coord_to_wind_basis(
                        secondary_src.lat, secondary_src.lon,
                        filtered_data.retrieval_latitude[i],
                        filtered_data.retrieval_longitude[i])
                    secondary_dist = Geometry.CoordGeom.cartesian_distance(
                        (xs, ys), secondary_offsets[ind])

                    in_secondary_plume = PlumeModel.InPlume(
                        xs, ys, u, 1., a, **plume_kwargs)
                    in_secondary_background = PlumeModel.InBackground(
                        xs, ys, secondary_dist, u, 1., a, **bg_kwargs)

                    # logic for when to consider it in-plume/background with secondary sources
                    in_plume = in_plume or in_secondary_plume
                    in_background = in_background and in_secondary_background

            if in_background:
                background_data.append(filtered_data, i)

            if in_plume:
                total_enhancement = 0.  #enhancements from all sources
                plume_data.append(filtered_data, i)
                # get enhancement from main source, then add secondary sources
                if sza_adjustments:
                    main_enhancement = sza.V(x, y, u, F, a, i)
                else:
                    main_enhancement = PlumeModel.V(x, y, u, F, a)
                alpha = [main_enhancement / F]
                total_enhancement += main_enhancement

                for ind, secondary_src in enumerate(secondary):
                    xs, ys = Geometry.CoordGeom(wind).coord_to_wind_basis(
                        secondary_src.lat, secondary_src.lon,
                        filtered_data.retrieval_latitude[i],
                        filtered_data.retrieval_longitude[i])
                    F_secondary = secondary_emissions[ind]

                    if sza_adjustments:
                        secondary_enhancement = sza.V(xs, ys, u, F_secondary,
                                                      a, i)
                    else:
                        secondary_enhancement = PlumeModel.V(
                            xs, ys, u, F_secondary, a)

                    total_enhancement += secondary_enhancement
                    alpha.append(secondary_enhancement / F_secondary)

                model_enhancements.append([total_enhancement])
                model_alpha.append(alpha)

                fixed_enhancement = 0.
                for ind, fixed in enumerate(fixed_secondary_sources):
                    xs, ys = Geometry.CoordGeom(wind).coord_to_wind_basis(
                        fixed.lat, fixed.lon,
                        filtered_data.retrieval_latitude[i],
                        filtered_data.retrieval_longitude[i])
                    F_fixed = fixed_emissions[ind]

                    if sza:
                        source_enhancement = sza.V(xs, ys, u, F_fixed, a, i)
                    else:
                        source_enhancement = PlumeModel.V(
                            xs, ys, u, F_fixed, a)
                    fixed_enhancement += source_enhancement

                fixed_enhancements.append(fixed_enhancement)

        in_plume_objects.append(plume_data)
        background_objects.append(background_data)
        model_enhancement_lists.append(numpy.array(model_enhancements))
        model_alpha_lists.append(numpy.array(model_alpha))
        fixed_enhancement_lists.append(numpy.array(fixed_enhancements))

    all_results = []
    for (k, wind) in enumerate(WindSources):
        print ''
        print wind_labels[k]

        defaults = ModelFunctions.results_defaults()
        defaults.co2_attribute = co2
        defaults.co2_name = co2_source
        defaults.output_units = units
        in_plume_objects[k].xco2_uncert = numpy.array(
            in_plume_objects[k].xco2_uncert)

        try:
            results = ModelFunctions.interpret_results(
                in_plume_objects[k],
                background_objects[k],
                model_enhancement_lists[k],
                model_alpha_lists[k],
                fixed_enhancement_lists[k],
                overpass,
                wind,
                defaults,
                float(total_emissions),
                weights=weighted,
                background_average=background_average,
                uncertainty=uncertainty)
            # results is tuple (scale factor, estimated emissions, number of plume points, correlation)

        except:
            results = defaults.null_value
            # print "An exception was raised: see message following"
            # print exc
            raise

        all_results.append(results)

        if secondary_sources:
            print '\nEmissions are ordered as', ', '.join(
                [overpass.short] + map(lambda s: s.short, secondary))
        print ''

    # make scatter plot if it's asked for, using last wind source
    if scatter_plot:
        if type(scatter_plot) != str:
            raise TypeError(
                "Keyword scatter_plot must be a string corresponding to a valid path. Given '{0}'"
                .format(scatter_plot))

        try:
            sc_location = ModelFunctions.make_scatter_plot(
                numpy.array((model_enhancement_lists[k]) /
                            numpy.mean(background_objects[k].k)).flatten(),
                in_plume_objects[k][co2], scatter_plot)
        except:
            raise
        else:
            print "Scatter plot made and saved as {0}".format(scatter_plot)

    return all_results
示例#7
0
def Plot(overpass, filename, min_xco2=KML.default_cmin, max_xco2=KML.default_cmax, secondary_sources=[], arrow_scale=0.02, stability="new", wind_source="Average", wind_adjustment=0., f_plume=0.10, f_background=0.01, offset=3.e3, y_max_positive=50.e3, y_max_negative=50.e3, y_min_positive=0., y_min_negative=0., direction='y', x_max=75.e3, snr_strong_co2_min=None, chi_squared_max=None, albedo_min=None, albedo_max=None, outcome_flags={1,2}, surface_pressure_min=None, surface_pressure_max=None, lon_thresh=0.5, lat_thresh=0.5, bias_correction='corrected', npoints=500, width=0.5, height=None, labelsize=Colours.default_fontsize, x=0.05, wind_arrow_sources=['MERRA', 'ECMWF', 'GEM', 'Average']):
    """Creates a KML file for an overpass with parameters as specified.
    
    If xco2 limits are default values, no new colour bar is made.
    Otherwise, will make a new colour bar and save it alongside the
    kml on the server.
    
    Parameters for defining the plume and background are included because
    the extended data for each polygon contains a flag for whether each
    point is in the plume, in the background, or in neither.
    
    Polygons are plotted for 'npoints' points on either side
    of the box defined by the lat and lon thresholds.
    """
    print "Making KML for",overpass.info
    if overpass.FullFile=="":
        raise ValueError("Corrupt overpass file")

    # Bundle together arguments that need to be passed to plume model functions
    # For determining background:
    bg_kwargs = {'background_factor':f_background,
                'ymax_positive':y_max_positive,
                'ymax_negative':y_max_negative,
                'ymin_negative':y_min_negative,
                'ymin_positive':y_min_positive,
                'offset':offset,
                'sign':direction
            }
    # For determining in plume points:
    plume_kwargs = {'plume_factor':f_plume,
                    'xmax':x_max
                }
    
    # Args to pass to full_file.quality(i,**kwargs) method
    quality_args = {'chi_squared_max':chi_squared_max,
                    'snr_strong_co2_min':snr_strong_co2_min,
                    'albedo_min':albedo_min,
                    'albedo_max':albedo_max,
                    'outcome_flags':outcome_flags,
                    'surface_pressure_min':surface_pressure_min,
                    'surface_pressure_max':surface_pressure_max
                    }
    
    # parse bias_correction argument
    if bias_correction not in File.allowed_bias_correction:
        type_err = "'bias_correction' argument must be one of %s"
        raise TypeError(type_err % ', '.join(File.allowed_bias_correction))
        
    # The co2 variable to read; ex, 'corrected_xco2', 'S31_xco2'
    co2 = bias_correction + "_xco2"
    try:
        wind = getattr(overpass,wind_source)
    except AttributeError:
        raise AttributeError("'wind_source' must be one of %s" % ', '.join(valid_winds))
    
    # make arrow_lat, arrow_lon the average lat, lon weighted by emissions
    if secondary_sources:
        secondary_lats = [second.lat for second in secondary_sources]
        secondary_lons = [second.lon for second in secondary_sources]
        all_lats = [overpass.lat] + secondary_lats
        all_lons = [overpass.lon] + secondary_lons
        all_emissions = [overpass.get_emissions()(Units._model_units)] + \
            [second.get_emissions(overpass)(Units._model_units) for second in secondary_sources]
        arrow_lat = numpy.average(all_lats, weights=all_emissions)
        arrow_lon = numpy.average(all_lons, weights=all_emissions)
        print "Using coordinate ({0}, {1}) for wind arrows".format(arrow_lat, arrow_lon)
    else:
        arrow_lat, arrow_lon = overpass.lat, overpass.lon
 
    # Use KML module to make the KML
    kml_description = overpass.strftime(KML.modis_description_fmt)
    Map = KML.KML(description=kml_description)
    oco2_name = "OCO-2 Data"
    oco2_description = "Data from OCO-2 v7 Full Files with '%s' "\
    "bias correction" % bias_correction
    
    OCO2_folder = KML.Folder(oco2_name, oco2_description)
    Map.add_folder(OCO2_folder)
    warn_level_folders = {} # dictionary to be able to update the folders
    for wl in range(21):
        folder_name = "Warn Level %d" % wl
        folder_description = "Lite File Warn Level %d" % wl
        folder = KML.Folder(folder_name, folder_description)
        OCO2_folder.add_object(folder)
        warn_level_folders[wl]=folder
        
    wind_arrows = KML.Overlay.wind_arrow(overpass,lat=arrow_lat,
                                         lon=arrow_lon,size=arrow_scale,
                                         sources=wind_arrow_sources)
    height = height if height else (1.1/5.)*width
    cbar = Colours.colour_bar('', cmin=min_xco2, cmax=max_xco2, fontsize=labelsize)
    colour_scale = KML.Overlay.colour_scale(cbar, width=width, height=height, x=x)
    Map.add_object(wind_arrows)
    Map.add_object(colour_scale)
    
    print('Opening Full File; Performing Bias Correction')
    full_file = File.full(overpass)
    lite_file = File.lite(overpass)
    
    # warn_dict maps a sounding id to a warn level
    warn_dict = {lite_file.sounding_id[n]:lite_file.warn_level[n]
                                    for n in range(len(lite_file))}
    
    lon = overpass.lon
    lat = overpass.lat
    
    close_indices = []
    for i in range(len(full_file)):
        lon_i = full_file.retrieval_longitude[i]
        lat_i = full_file.retrieval_latitude[i]
        dlon = abs(lon_i - overpass.lon)%360
        dlat = abs(lat_i - overpass.lat)%360
        if dlon<=lon_thresh and dlat<=lat_thresh:
          close_indices.append(i)
        i+=1
    
    # (k_min, k_max) are limits on what points to plot
    k_min = max(0,close_indices[0]-npoints)
    k_max = min(len(full_file),close_indices[-1]+npoints)
    
    # plume-model parameters
    u = wind.speed
    F = 1.0 # actual emissions are not important for background
    a = overpass.a if stability=="new" else overpass.a_old
    
    x_offset, y_offset = full_file.get_offset(overpass, wind)
    secondary_offsets = full_file.get_secondary_offset(overpass, wind,
                                    secondary_sources=secondary_sources)
    
    print('Adding polygons to KML File')
    count_plume_points = 0
    count_bg_points = 0
    for k in range(k_min,k_max):
        lats = full_file.retrieval_vertex_latitude[k,0,:]
        lons = full_file.retrieval_vertex_longitude[k,0,:]
        sounding_xco2 = full_file.corrected_xco2[k]
        sounding_id = full_file.id[k]
        sounding_lat = full_file.retrieval_latitude[k]
        sounding_lon = full_file.retrieval_longitude[k]
        
        sounding_colour = Colours.Colour(sounding_xco2, vmin=min_xco2,
                                                        vmax=max_xco2)
        
        if sounding_id in warn_dict:
            warn_level = warn_dict[sounding_id]
        else:
            warn_level=20
        
        point = Geometry.CoordGeom(wind)
        sounding_x, sounding_y = point.coord_to_wind_basis(lat, lon, 
                                                    sounding_lat, sounding_lon)
        
        data = KML.Data()
        data.get_data(k, full_file)
        wl_data = data.add_new_data('Warn Level',warn_level)
        posn_data = data.add_new_data('Wind Basis Coord',(sounding_x,sounding_y))
        
        data.add_new_data('Full File', os.path.split(overpass.FullFile)[1])
        data.add_new_data('Lite File', os.path.split(overpass.LiteFile)[1])
        data.add_new_data('Observation Mode', overpass.observation_mode)
        data.add_new_data('Latitude', sounding_lat)
        data.add_new_data('Longitude', sounding_lon)
        
        dist = ((sounding_x-x_offset)*(sounding_x-x_offset) + 
                (sounding_y-y_offset)*(sounding_y-y_offset))**0.5
        
        in_plume = PlumeModel.InPlume(sounding_x, sounding_y, u, F, a,
                                      **plume_kwargs)
        in_background = PlumeModel.InBackground(sounding_x, sounding_y, dist,
                                                u, F, a, **bg_kwargs)
        for (ind, second) in enumerate(secondary_sources):
            x0,y0 = secondary_offsets[ind]
            xs,ys = point.coord_to_wind_basis(second.lat, second.lon, sounding_lat, sounding_lon)
            second_dist = point.cartesian_distance((xs,ys),(x0,y0))
            in_secondary_plume = PlumeModel.InPlume(xs, ys, u, 1.0, a, **plume_kwargs)
            in_secondary_bg = PlumeModel.InBackground(xs, ys, second_dist, u, 1.0, a, **bg_kwargs)
            in_plume = in_plume or in_secondary_plume
            in_background = in_background and in_secondary_bg
        
        if in_plume:
            model_status = KML.DataPoint('Notes','In Plume Point')
            if full_file.quality(k, **quality_args):
                count_plume_points+=1
        elif in_background:
            model_status = KML.DataPoint('Notes','Background Point')
            if full_file.quality(k, **quality_args):
                count_bg_points+=1
        else:
            model_status = KML.DataPoint('Notes','None')
        data.add_data_field(model_status)
        
        quality = full_file.quality(k, **quality_args)
        data.add_new_data("Quality Check", str(quality))
        poly_col = sounding_colour.cformat(Colours.Colour.GE)
        sounding_polygon = KML.Polygon(lats, lons, sounding_id, poly_col)
        sounding_polygon.add_data(data)
        warn_level_folders[warn_level].add_object(sounding_polygon)

    Map.write(filename)
    print "KML saved as", filename
    print "Done Overpass"
示例#8
0
def vertical_plot(overpass,
                  file_name,
                  bias_correction="corrected",
                  x_max=75.e3,
                  y_max_negative=50.e3,
                  y_max_positive=50.e3,
                  f_plume=0.10,
                  f_background=0.01,
                  wind_adjustment=0.,
                  wind_source="Average",
                  y_min_positive=0.,
                  y_min_negative=0.,
                  offset=3.e3,
                  direction='y',
                  xco2_min=395,
                  xco2_max=405,
                  plot_max=125,
                  plot_min=125,
                  snr_strong_co2_min=None,
                  chi_squared_max=None,
                  albedo_min=None,
                  albedo_max=None,
                  surface_pressure_min=None,
                  surface_pressure_max=None,
                  smooth=False,
                  units='g/s',
                  outcome_flags={1, 2},
                  secondary_sources=False,
                  stability="new",
                  force_wind=None,
                  surface_stability=None,
                  failed_quality_color='grey',
                  show_latitude=False):
    """vertical_plot makes so-called vertical plots.
    
    Args:
      * overpass: a PST.Overpass instance
      * file_name: str, valid file path to save the image as
      
    Keyword Args:
      * see keyword arguments document
    """
    quality_args = {
        'chi_squared_max': chi_squared_max,
        'snr_strong_co2_min': snr_strong_co2_min,
        'albedo_min': albedo_min,
        'albedo_max': albedo_max,
        'outcome_flags': outcome_flags,
        'surface_pressure_min': surface_pressure_min,
        'surface_pressure_max': surface_pressure_max
    }

    bg_kwargs = {
        'ymax_negative': y_max_negative,
        'ymax_positive': y_max_positive,
        'background_factor': f_background,
        'ymin_negative': y_min_negative,
        'ymin_positive': y_min_positive,
        'offset': offset,
        'sign': direction
    }

    if bias_correction not in File.allowed_bias_correction:
        raise ValueError(
            "bias_correction must be one of {0}; given {1}".format(
                ', '.join(File.allowed_bias_correction), bias_correction))

    co2 = "{0}_xco2".format(bias_correction)
    if smooth:
        co2 = 'smoothed_' + co2

    try:
        wind = getattr(overpass, wind_source).rotate(wind_adjustment)
    except AttributeError:
        raise TypeError('wind_sources must be one of {0}; given {1}'.format(
            ", ".join(PST.AllWinds.valid_keys), wind_source))

    if force_wind:
        wind = force_wind

    u = wind.speed
    if surface_stability:
        a = surface_stability
    else:
        a = overpass.a if stability == "new" else overpass.a_old
    F = overpass.get_emissions(units)

    print "Using stability parameter a={0}".format(a)
    print("Opening and reading Full File")
    full_file = File.full(overpass)

    (x0, y0, index_min) = full_file.get_offset(overpass,
                                               wind,
                                               return_index=True)

    if secondary_sources:
        if hasattr(secondary_sources, "__iter__"):
            overpass.source.secondary = secondary_sources
            secondary_sources = True
        secondary_offsets = full_file.get_secondary_offset(overpass, wind)
        print "Using secondary sources {0}".format(overpass.source.secondary)

    if secondary_sources:
        all_source_latitudes = [overpass.lat] + [
            second.lat for second in overpass.source.secondary
        ]
    else:
        all_source_latitudes = [overpass.lat]

    weighted_avg_lat = numpy.average(all_source_latitudes,
                                     weights=all_source_latitudes)
    lat_offset = overpass.lat - weighted_avg_lat

    lat0 = full_file.retrieval_latitude[index_min]
    lon0 = full_file.retrieval_longitude[index_min]

    lat_length = 0.001 * Geometry.CoordGeom(wind).distance(
        overpass.lat, overpass.lon, overpass.lat + 1, overpass.lon)

    plume_data = File.File()
    else_data = File.File()
    background_data = File.File()
    failed_quality_data = File.File()

    delta_lat = 3.
    lat_max = weighted_avg_lat + plot_max / lat_length
    lat_min = weighted_avg_lat - plot_min / lat_length

    i = 0
    print("Classifying data")
    for i in range(len(full_file)):
        if full_file.quality(i, **quality_args):
            coordinate = Geometry.CoordGeom(wind)
            x, y = coordinate.coord_to_wind_basis(
                overpass.lat, overpass.lon, full_file.retrieval_latitude[i],
                full_file.retrieval_longitude[i])
            dist = Geometry.CoordGeom.cartesian_distance((x, y), (x0, y0))

            # Don't have a separate if secondary_sources... loop for background since it's far enough away that it shouldn't make a difference
            # As long as it isn't in the secondary plume, add the point to the background
            in_background = PlumeModel.InBackground(x, y, dist, u, F, a,
                                                    **bg_kwargs)

            in_plume = PlumeModel.InPlume(x,
                                          y,
                                          u,
                                          F,
                                          a,
                                          plume_factor=f_plume,
                                          xmax=x_max)
            if secondary_sources:
                for ind, secondary in enumerate(overpass.source.secondary):
                    xs, ys = Geometry.CoordGeom(wind).coord_to_wind_basis(
                        secondary.lat, secondary.lon,
                        full_file.retrieval_latitude[i],
                        full_file.retrieval_longitude[i])
                    secondary_offset = secondary_offsets[ind]
                    secondary_dist = Geometry.CoordGeom.cartesian_distance(
                        (xs, ys), (secondary_offset[0], secondary_offset[1]))
                    in_secondary_plume = PlumeModel.InPlume(
                        xs, ys, u, 1., a, plume_factor=f_plume, xmax=x_max)
                    in_plume = in_plume or in_secondary_plume

                    in_secondary_background = PlumeModel.InBackground(
                        xs, ys, secondary_dist, u, 1., a, **bg_kwargs)
                    in_background = in_background and in_secondary_background

            if in_plume:
                plume_data.append(full_file, i)
            elif in_background:
                background_data.append(full_file, i)
            else:
                else_data.append(full_file, i)
        else:
            failed_quality_data.append(full_file, i)

    max_dist = Geometry.CoordGeom(wind).distance(lat0, lon0, lat0 + delta_lat,
                                                 lon0)
    min_dist = -Geometry.CoordGeom(wind).distance(lat0, lon0, lat0 - delta_lat,
                                                  lon0)
    background_mean = numpy.mean(background_data[co2])

    print "Background mean:", background_mean

    ticks_plus = numpy.append(numpy.arange(0, plot_max, 50), [plot_max])
    ticks_minus = sorted(
        -1 * numpy.append(numpy.arange(50, plot_min, 50), [plot_min]))

    dist_ticks = numpy.append(ticks_minus, ticks_plus)

    fig = plt.figure(figsize=_fig_size)
    ax1 = fig.add_subplot(111)
    ax1.scatter(plume_data[co2],
                plume_data.retrieval_latitude,
                color=_plume_colour,
                s=_size,
                label=_plume_lbl)
    ax1.scatter(background_data[co2],
                background_data.retrieval_latitude,
                color=_bg_colour,
                s=_size,
                label=_bg_lbl)
    ax1.scatter(else_data[co2],
                else_data.retrieval_latitude,
                color=_other_colour,
                s=_size,
                label=_other_lbl)
    ax1.scatter(failed_quality_data[co2],
                failed_quality_data.retrieval_latitude,
                color=failed_quality_color,
                s=_size,
                label=_qual_lbl)
    ax1.plot([background_mean, background_mean], [-plot_min, plot_max],
             color=_bg_mean_colour)
    ax1.set_ylim(lat_min, lat_max)
    ax1.set_xlim(xco2_min, xco2_max)
    ax1.set_ylabel('Distance from source (km)',
                   fontsize=labelfont,
                   labelpad=leftlabelpad,
                   fontname=Formats.globalfont)
    ax1.set_xlabel('Xco$_2$ (ppm)',
                   fontsize=labelfont,
                   fontname=Formats.globalfont)
    ax1.set_xticks(numpy.linspace(xco2_min, xco2_max, 5))
    ax1.plot(background_mean,
             weighted_avg_lat,
             marker='.',
             color=_source_colour,
             markersize=_source_markersize,
             lw=5)
    ax1.set_title('Background: %s ppm' % (Formats.ppmformat % background_mean),
                  fontsize=titlefont,
                  fontname=Formats.globalfont)

    ax2 = ax1.twinx()
    ax1.tick_params(labelsize=ticklabelfont)
    ax2.tick_params(labelsize=ticklabelfont)
    ax2.set_ylim(-plot_min, plot_max)
    if show_latitude:
        ax2.set_ylabel('Latitude ($^{\circ}$N)',
                       fontsize=labelfont,
                       labelpad=rightlabelpad,
                       fontname=Formats.globalfont)
    ax2.set_yticks(dist_ticks)
    ax2.set_ylim(-plot_min, plot_max)
    ax2.tick_params('y',
                    left=True,
                    labelleft=True,
                    right=False,
                    labelright=False)

    if show_latitude:
        ax1.tick_params('y',
                        left=False,
                        right=True,
                        labelleft=False,
                        labelright=True)
    else:
        ax1.tick_params('y',
                        left=False,
                        right=False,
                        labelleft=False,
                        labelright=False)
        ax1.set_yticks([])
    Formats.set_tickfont(ax1)
    Formats.set_tickfont(ax2)
    plt.subplots_adjust(**_subplot_adjustments)
    plt.savefig(file_name, dpi=_dpi, bbox_inches='tight')
    plt.close()
示例#9
0
def box_plot(overpass,
             file_name,
             bias_correction="corrected",
             x_max=75.e3,
             y_max_negative=50.e3,
             y_max_positive=50.e3,
             f_plume=0.10,
             f_background=0.01,
             wind_adjustment=0.,
             wind_source="Average",
             y_min_positive=0.,
             y_min_negative=0.,
             offset=3.e3,
             direction='y',
             plot_min=125,
             plot_max=125,
             max_distance=100.e3,
             snr_strong_co2_min=None,
             chi_squared_max=None,
             albedo_min=None,
             albedo_max=None,
             surface_pressure_min=None,
             surface_pressure_max=None,
             smooth=False,
             units='g/s',
             outcome_flags={1, 2},
             secondary_sources=False,
             stability="new",
             force_wind=None,
             surface_stability=None):
    """vertical_plot makes so-called vertical plots.
    
    Args:
      * overpass: a PST.Overpass instance
      * file_name: str, valid file path to save the image as
      
    Keyword Args:
      * see keyword arguments document
    """
    quality_args = {
        'chi_squared_max': chi_squared_max,
        'snr_strong_co2_min': snr_strong_co2_min,
        'albedo_min': albedo_min,
        'albedo_max': albedo_max,
        'outcome_flags': outcome_flags,
        'surface_pressure_min': surface_pressure_min,
        'surface_pressure_max': surface_pressure_max
    }

    bg_kwargs = {
        'ymax_negative': y_max_negative,
        'ymax_positive': y_max_positive,
        'background_factor': f_background,
        'ymin_negative': y_min_negative,
        'ymin_positive': y_min_positive,
        'offset': offset,
        'sign': direction
    }

    if bias_correction not in File.allowed_bias_correction:
        raise ValueError(
            "bias_correction must be one of {0}; given {1}".format(
                ', '.join(File.allowed_bias_correction), bias_correction))

    co2 = "{0}_xco2".format(bias_correction)
    if smooth:
        co2 = 'smoothed_' + co2

    try:
        wind = getattr(overpass, wind_source).rotate(wind_adjustment)
    except AttributeError:
        raise TypeError('wind_sources must be one of {0}; given {1}'.format(
            ", ".join(PST.AllWinds.valid_keys), wind_source))

    if force_wind:
        wind = force_wind

    u = wind.speed
    if surface_stability:
        a = surface_stability
    else:
        a = overpass.a if stability == "new" else overpass.a_old
    F = overpass.get_emissions(units)

    print "Using stability parameter a={0}".format(a)
    print("Opening and reading Full File")
    full_file = File.full(overpass)

    (x0, y0, index_min) = full_file.get_offset(overpass,
                                               wind,
                                               return_index=True)

    if secondary_sources:
        if hasattr(secondary_sources, "__iter__"):
            overpass.source.secondary = secondary_sources
            secondary_sources = True
        secondary_offsets = full_file.get_secondary_offset(overpass, wind)
        print "Using secondary sources {0}".format(overpass.source.secondary)

    if secondary_sources:
        all_source_latitudes = [overpass.lat] + [
            second.lat for second in overpass.source.secondary
        ]
    else:
        all_source_latitudes = [overpass.lat]

    weighted_avg_lat = numpy.average(all_source_latitudes,
                                     weights=all_source_latitudes)
    lat_offset = overpass.lat - weighted_avg_lat

    lat0 = full_file.retrieval_latitude[index_min]
    lon0 = full_file.retrieval_longitude[index_min]

    lat_length = 0.001 * Geometry.CoordGeom(wind).distance(
        overpass.lat, overpass.lon, overpass.lat + 1, overpass.lon)

    plume_data = File.File()
    else_data = File.File()
    background_data = File.File()
    failed_quality_data = File.File()

    delta_lat = 3.
    lat_max = weighted_avg_lat + plot_max / lat_length
    lat_min = weighted_avg_lat - plot_min / lat_length

    i = 0
    print("Classifying data")
    for i in range(len(full_file)):
        if full_file.quality(i, **quality_args):
            coordinate = Geometry.CoordGeom(wind)
            x, y = coordinate.coord_to_wind_basis(
                overpass.lat, overpass.lon, full_file.retrieval_latitude[i],
                full_file.retrieval_longitude[i])
            dist = Geometry.CoordGeom.cartesian_distance((x, y), (x0, y0))

            in_background = PlumeModel.InBackground(x, y, dist, u, F, a,
                                                    **bg_kwargs)

            in_plume = PlumeModel.InPlume(x,
                                          y,
                                          u,
                                          F,
                                          a,
                                          plume_factor=f_plume,
                                          xmax=x_max)
            if secondary_sources:
                for ind, secondary in enumerate(overpass.source.secondary):
                    xs, ys = Geometry.CoordGeom(wind).coord_to_wind_basis(
                        secondary.lat, secondary.lon,
                        full_file.retrieval_latitude[i],
                        full_file.retrieval_longitude[i])
                    secondary_offset = secondary_offsets[ind]
                    secondary_dist = Geometry.CoordGeom.cartesian_distance(
                        (xs, ys), (secondary_offset[0], secondary_offset[1]))
                    in_secondary_plume = PlumeModel.InPlume(
                        xs, ys, u, 1., a, plume_factor=f_plume, xmax=x_max)
                    in_plume = in_plume or in_secondary_plume

                    in_secondary_background = PlumeModel.InBackground(
                        xs, ys, secondary_dist, u, 1., a, **bg_kwargs)
                    in_background = in_background and in_secondary_background

            if in_plume:
                plume_data.append(full_file, i)
            elif in_background:
                background_data.append(full_file, i)
            elif dist <= max_distance:
                else_data.append(full_file, i)
        else:
            failed_quality_data.append(full_file, i)

    max_dist = Geometry.CoordGeom(wind).distance(lat0, lon0, lat0 + delta_lat,
                                                 lon0)
    min_dist = -Geometry.CoordGeom(wind).distance(lat0, lon0, lat0 - delta_lat,
                                                  lon0)
    background_mean = numpy.mean(background_data[co2])

    print "Background mean:", background_mean

    ticks_plus = numpy.append(numpy.arange(0, plot_max, 50), [plot_max])
    ticks_minus = sorted(
        -1 * numpy.append(numpy.arange(50, plot_min, 50), [plot_min]))

    dist_ticks = numpy.append(ticks_minus, ticks_plus)

    fig, ax = plt.subplots(figsize=_fig_size)
    plot_data = [plume_data[co2], background_data[co2], else_data[co2]]
    ax.boxplot(plot_data)
    ax.set_xticklabels([
        'Plume', 'Background',
        'All Points (d$\leq$%s km)' % (max_distance / 1000.)
    ])
    ax.set_ylabel('Xco$_2$ (ppm)')
    ax.set_title('Boxplot for Xco$_2$, %s' % overpass)
    ax.axhline(background_mean,
               color='g',
               label='Background Mean: %.3f ppm' % background_mean)
    ax.legend(loc=3, prop={'size': 8})
    plt.savefig(file_name, dpi=400)
    plt.close()