Beispiel #1
0
    def smoothed_linear_interpolation_between_tiepoints(l2, ssh_tiepoint_indices, filter_width):
        """
        The main SLA computation method in this class
        :param l2: Level-2 data container
        :param ssh_tiepoint_indices:
        :param filter_width:
        :return: None
        """

        # Step 1: Get the observed (noisy) sea surface elevations
        sla_raw = np.full(l2.n_records, np.nan)
        sla_raw[ssh_tiepoint_indices] = l2.elev[ssh_tiepoint_indices] - l2.mss[ssh_tiepoint_indices]
        non_tiepoints = np.isnan(sla_raw)

        # Step 2: Create a filtered version of the raw SLA, but don't interpolate yet
        # Use python implementation of IDL SMOOTH:
        # idl_smooth(x, w) equivalent to SMOOTH(x, w, /edge_truncate, /nan)
        sla_filter1 = idl_smooth(sla_raw, filter_width)
        sla_filter1[non_tiepoints] = np.nan

        # Step 3: Fill nans with linear interpolation and constant values at borders
        # python: fill_nan(x) = IDL: FILL_NAN(x, /NEIGHBOUR)
        sla_filter2 = fill_nan(sla_filter1)

        # Step 4: The sea level anomaly is the smoothed version
        # of the gap filled sla
        sla = idl_smooth(sla_filter2, filter_width)

        # All done, return value
        return sla
Beispiel #2
0
    def _linear_smoothed_interpolation_between_tiepoints(self, l2):
        """ Based in cs2awi code from Robert Ricker """

        # Use ocean and lead elevations
        self._ssh_tiepoints = l2.surface_type.lead.indices
        if self._options.use_ocean_wfm:
            self._ssh_tiepoints.append(l2.surface_type.ocean.indices)
            self._ssh_tiepoints = np.sort(self._ssh_tiepoints)

        # Get initial elevation at tiepoint locations
        mss_frb = l2.elev - l2.mss

        # Remove ssh tiepoints from the list if their elevation
        # corrected by the median offset of all tiepoints from the mss
        # exceeds a certain threshold
        if self._options.pre_filtering:

            # Startup
            index_dict = np.arange(l2.surface_type.lead.num)
            threshold = self._options.pre_filter_maximum_mss_median_offset

            # Compute the mean distance to the mss
            tiepoint_mss_distance = mss_frb[self._ssh_tiepoints]
            valid_points = np.where(np.isfinite(tiepoint_mss_distance))[0]
            tiepoint_mss_distance = tiepoint_mss_distance[valid_points]
            median_mss_offset = np.median(tiepoint_mss_distance)

            # Filter points for outliers
            offset = np.abs(mss_frb[self._ssh_tiepoints] - median_mss_offset)
            valid = np.where(offset < threshold)
            self._ssh_tiepoints = self._ssh_tiepoints[index_dict[valid]]

        self.ssa_raw = np.ndarray(shape=(l2.n_records)) * np.nan
        self.ssa_raw[self._ssh_tiepoints] = mss_frb[self._ssh_tiepoints]
        non_tiepoints = np.where(np.isnan(self.ssa_raw))

        # Filtered raw values
        # Use custom implementation of IDL SMOOTH:
        # idl_smooth(x, w) equivalent to SMOOTH(x, w, /edge_truncate, /nan)
        ssa_filter1 = idl_smooth(self.ssa_raw, self.filter_width)

        # Leave only the original ssh tie points
        ssa_filter1[non_tiepoints] = np.nan

        # Fill nans with linear interpolation and contant values at borders
        # python: fill_nan(x) = IDL: FILL_NAN(x, /NEIGHBOUR)
        ssa_filter2 = fill_nan(ssa_filter1)

        # Final smoothing
        ssa = idl_smooth(ssa_filter2, self.filter_width)
        self._value = ssa
Beispiel #3
0
    def get_l2_track_vars(self, l2):

        # Set the requested data
        self.set_requested_date_from_l2(l2)

        # CAVEAT: The method `update_external_data()` will fail
        # if the requested date is February 29, since no
        # corresponding source file exists. As a fix, the data in
        # in this case is set back to the February 28.
        if self.month == "02" and self.day == "29":
            self.set_requested_date(int(self.year), int(self.month), 28)

        # Update the external data
        self.update_external_data()

        # Check if error with file I/O
        if self.error.status or self._data is None:
            # This will return an empty container
            snow = SnowParameterContainer()
            snow.set_dummy(l2.n_records)
        else:
            # Extract along track snow depth and density
            sd, sd_unc = self._get_snow_track(l2)

            # Apply along-track smoothing if required
            smooth_snowdepth = self.cfg.options.get("self.cfg.options", False)
            if smooth_snowdepth:
                filter_width = self.cfg.options.smooth_filter_width_m
                # Convert filter width to index
                filter_width /= l2.footprint_spacing
                # Round to odd number
                filter_width = np.floor(filter_width) // 2 * 2 + 1
                sd = idl_smooth(sd, filter_width)
                sd_unc = idl_smooth(sd_unc, filter_width)

            # Collect Parameters and return
            # (density and density uncertainty fixed from l2 settings)
            snow = SnowParameterContainer()
            snow.depth = sd
            snow.depth_uncertainty = sd_unc
            snow.density = np.full(sd.shape, self.cfg.options.snow_density)
            snow.density_uncertainty = np.full(
                sd.shape, self.cfg.options.snow_density_uncertainty)

        # Register Variables
        self.register_auxvar("sd", "snow_depth", snow.depth,
                             snow.depth_uncertainty)
        self.register_auxvar("sdens", "snow_density", snow.density,
                             snow.density_uncertainty)
Beispiel #4
0
    def get_l2_track_vars(self, l2):

        # Set the requested data
        self.set_requested_date_from_l2(l2)

        # Update the external data
        self.update_external_data()

        # Check if error with file I/O
        if self.error.status or self._data is None:
            # This will return an empty container
            snow = SnowParameterContainer()
            snow.set_dummy(l2.n_records)
        else:
            # Extract along track snow depth and density
            sd, sd_unc = self._get_snow_track(l2)

            # Apply along-track smoothing if required
            if self.cfg.options.smooth_snowdepth:
                filter_width = self.cfg.options.smooth_filter_width_m
                # Convert filter width to index
                filter_width /= l2.footprint_spacing
                # Round to odd number
                filter_width = np.floor(filter_width) // 2 * 2 + 1
                sd = idl_smooth(sd, filter_width)
                sd_unc = idl_smooth(sd_unc, filter_width)

            # Collect Parameters and return
            # (density and density uncertainty fixed from l2 settings)
            snow = SnowParameterContainer()
            snow.depth = sd
            snow.depth_uncertainty = sd_unc
            snow.density = np.full(sd.shape, self.cfg.options.snow_density)
            snow.density_uncertainty = np.full(
                sd.shape, self.cfg.options.snow_density_uncertainty)

        # Register Variables
        self.register_auxvar("sd", "snow_depth", snow.depth,
                             snow.depth_uncertainty)
        self.register_auxvar("sdens", "snow_density", snow.density,
                             snow.density_uncertainty)
Beispiel #5
0
    def get_l2_track_vars(self, l2):
        """ Get the snow depth, density and their uncertainties for the track in the l2 data object
        including the potential modification of the original climatology and filters """

        # Validate hemisphere
        if l2.hemisphere == "south":
            snow = SnowParameterContainer()
            snow.set_dummy(l2.n_records)
            msg = "Warren99 not valid for southern hemisphere, returning 0"
            self.error.add_error("warren99-invalid-hemisphere", msg)
            return snow

        # Get the original warren climatology values
        # NOTE: snow is a class with properties depth, depth_uncertainty, density & density_uncertainty
        snow = self._get_warren99_fit_from_l2(l2)

        # Filter invalid values
        valid_min, valid_max = self.cfg.options.valid_snow_depth_range
        invalid = np.logical_or(snow.depth < valid_min, snow.depth > valid_max)
        invalid_records = np.where(invalid)[0]
        snow.set_invalid(invalid_records)

        # Apply ice_type (myi_fraction correction)
        scale_factor = (1.0 -
                        l2.sitype) * self.cfg.options.fyi_correction_factor

        # The scaling factor affects the snow depth ...
        snow.depth = snow.depth - scale_factor * snow.depth

        # ... and the uncertainty. Here it is assumed that the uncertainty
        # is similar affected by the scaling factor.
        snow.depth_uncertainty = snow.depth_uncertainty - scale_factor * snow.depth_uncertainty

        # the uncertainty of the myi fraction is acknowledged by adding
        # an additional term that depends on snow depth, the magnitude of
        # scaling and the sea ice type uncertainty
        scaling_uncertainty = snow.depth * scale_factor * l2.sitype.uncertainty
        snow.depth_uncertainty = snow.depth_uncertainty + scaling_uncertainty

        # Smooth snow depth (if applicable)
        if self.cfg.options.smooth_snow_depth:
            filter_width = self.cfg.options.smooth_filter_width_m
            # Convert filter width to index
            filter_width /= l2.footprint_spacing
            # Round to odd number
            filter_width = np.floor(filter_width) // 2 * 2 + 1
            snow.depth = idl_smooth(snow.depth, filter_width)

        # Register Variables
        self.register_auxvar("sd", "snow_depth", snow.depth,
                             snow.depth_uncertainty)
        self.register_auxvar("sdens", "snow_density", snow.density,
                             snow.density_uncertainty)