Ejemplo n.º 1
0
 def run_forward_model(self):
     return sbc.forward_model(
         self.chl,
         self.cdom,
         self.nap,
         self.H,
         self.substrate1,
         self.wav,
         self.a_water,
         self.a_ph_star,
         551,
         substrate_fraction=self.q1,
         substrate2=self.substrate2,
         x_ph_lambda0x=self.x_ph_lambda0x,
         x_nap_lambda0x=self.x_nap_lambda0x,
         a_cdom_slope=self.slope_cdom,
         a_nap_slope=self.slope_nap,
         a_nap_lambda0nap=self.a_nap_lambda0nap,
         bb_ph_slope=self.slope_backscatter,
         bb_nap_slope=self.slope_backscatter,
         lambda0cdom=self.lambda0cdom,
         lambda0nap=self.lambda0nap,
         theta_air=self.theta_air,
         water_refractive_index=1.333,  # The hard-coded IDL value
         # self.off_nadir,
         q_factor=self.q_factor,
     )
Ejemplo n.º 2
0
    def test_default_substrate_fraction(self):
        # the default substrate_fraction should give r_substratum == substrate1
        results = sbc.forward_model(
            self.chl,
            self.cdom,
            self.nap,
            self.H,
            self.substrate1,
            self.wav,
            self.a_water,
            self.a_ph_star,
            551,
            substrate2=self.substrate2,
        )

        assert np.allclose(results.r_substratum, self.substrate1)
Ejemplo n.º 3
0
    def __call__(self, x, y, observed_rrs, parameters=None, nit=None, success=None):
        """
        Called by the parameter estimator when there is a result for a pixel.

        Args:
            x (int): The pixel x coordinate.
            y (int): The pixel y coordinate.
            observed_rrs (array-like): The observed remotely-sensed reflectance
                at this pixel.
            parameters (sambuca.FreeParameters): If the pixel converged,
                this contains the final parameters; otherwise None.
            id (int): The substrate combination index
            nit (int): The number of iterations performed
            success (bool): If the optimizer exited successfully
        """

        super().__call__(x, y, observed_rrs, parameters)

        # If this pixel did not converge, then there is nothing more to do
        if not parameters:
            return

        # Select the substrate pair from the list of substrates
        #id1 = self._fixed_parameters.substrate_combinations[id][0]
        #id2 = self._fixed_parameters.substrate_combinations[id][1]

        # Generate results from the given parameters
        model_results = sbc.forward_model(
            parameters.chl,
            parameters.cdom,
            parameters.nap,
            parameters.depth,
            parameters.sub1_frac,
            parameters.sub2_frac,
            parameters.sub3_frac,
            self._fixed_parameters.substrates[0],
            self._fixed_parameters.substrates[1],
            self._fixed_parameters.substrates[2],
            self._fixed_parameters.wavelengths,
            self._fixed_parameters.a_water,
            self._fixed_parameters.a_ph_star,
            self._fixed_parameters.num_bands,
            a_cdom_slope=self._fixed_parameters.a_cdom_slope,
            a_nap_slope=self._fixed_parameters.a_nap_slope,
            bb_ph_slope=self._fixed_parameters.bb_ph_slope,
            bb_nap_slope=self._fixed_parameters.bb_nap_slope,
            lambda0cdom=self._fixed_parameters.lambda0cdom,
            lambda0nap=self._fixed_parameters.lambda0nap,
            lambda0x=self._fixed_parameters.lambda0x,
            x_ph_lambda0x=self._fixed_parameters.x_ph_lambda0x,
            x_nap_lambda0x=self._fixed_parameters.x_nap_lambda0x,
            a_cdom_lambda0cdom=self._fixed_parameters.a_cdom_lambda0cdom,
            a_nap_lambda0nap=self._fixed_parameters.a_nap_lambda0nap,
            bb_lambda_ref=self._fixed_parameters.bb_lambda_ref,
            water_refractive_index=self._fixed_parameters.water_refractive_index,
            theta_air=self._fixed_parameters.theta_air,
            off_nadir=self._fixed_parameters.off_nadir,
            q_factor=self._fixed_parameters.q_factor)

        closed_rrs = sbc.apply_sensor_filter(
            model_results.rrs,
            self._sensor_filter)
        
        # set reference band in nm for Kd output
        kd_ref = np.where(self._fixed_parameters.wavelengths == 550)
        kd_out = model_results.kd[kd_ref]
        
        closed_rrsdp = sbc.apply_sensor_filter(
            model_results.rrsdp,
            self._sensor_filter)
        
        sdi = np.max(np.absolute(closed_rrs - closed_rrsdp) / self._nedr)

        error = error_all(observed_rrs, closed_rrs, self._nedr)

        # Write the results into our arrays
        self.error_alpha[x,y] = error.alpha
        self.error_alpha_f[x,y] = error.alpha_f
        self.error_f[x,y] = error.f
        self.error_lsq[x,y] = error.lsq
        self.chl[x,y] = parameters.chl
        self.cdom[x,y] = parameters.cdom
        self.nap[x,y] = parameters.nap
        self.depth[x,y] = parameters.depth
        self.sub1_frac[x,y] = parameters.sub1_frac
        self.sub2_frac[x,y] = parameters.sub2_frac
        self.sub3_frac[x,y] = parameters.sub3_frac
        self.closed_rrs[x,y,:] = closed_rrs
        self.nit[x,y] = nit
        self.success[x,y] = success
        # New outputs
        self.kd[x,y] = kd_out
        self.sdi[x,y] = sdi
        self.closed_rrsdp[x,y,:] = closed_rrsdp
Ejemplo n.º 4
0
    def __call__(self, parameters):
        """
        Returns an objective score for the given parameter set.

        Args:
            parameters (ndarray): The parameter array in the order
                (chl, cdom, nap, depth, substrate_fraction)
                as defined in the FreeParameters tuple
          
        """

        # TODO: do I need to implement this? Here or in a subclass?
        # To support algorithms without support for boundary values, we assign a high
        # score to out of range parameters. This may not be the best approach!!!
        # p_bounds is a tuple of (min, max) pairs for each parameter in p
        '''
        if p_bounds is not None:
            for _p, lu in zip(p, p_bounds):
                l, u = lu
                if _p < l or _p > u:
                    return 100000.0
        '''

        # Select the substrate pair from the list of substrates
        #id1 = self._fixed_parameters.substrate_combinations[self.id][0]
        #id2 = self._fixed_parameters.substrate_combinations[self.id][1]

        # Generate results from the given parameters
        model_results = sbc.forward_model(
            chl=parameters[0],
            cdom=parameters[1],
            nap=parameters[2],
            depth=parameters[3],
            sub1_frac=parameters[4],
            sub2_frac=parameters[5],
            sub3_frac=parameters[6],
            substrate1=self._fixed_parameters.substrates[0],
            substrate2=self._fixed_parameters.substrates[1],
            substrate3=self._fixed_parameters.substrates[2],
            wavelengths=self._fixed_parameters.wavelengths,
            a_water=self._fixed_parameters.a_water,
            a_ph_star=self._fixed_parameters.a_ph_star,
            num_bands=self._fixed_parameters.num_bands,
            a_cdom_slope=self._fixed_parameters.a_cdom_slope,
            a_nap_slope=self._fixed_parameters.a_nap_slope,
            bb_ph_slope=self._fixed_parameters.bb_ph_slope,
            bb_nap_slope=self._fixed_parameters.bb_nap_slope,
            lambda0cdom=self._fixed_parameters.lambda0cdom,
            lambda0nap=self._fixed_parameters.lambda0nap,
            lambda0x=self._fixed_parameters.lambda0x,
            x_ph_lambda0x=self._fixed_parameters.x_ph_lambda0x,
            x_nap_lambda0x=self._fixed_parameters.x_nap_lambda0x,
            a_cdom_lambda0cdom=self._fixed_parameters.a_cdom_lambda0cdom,
            a_nap_lambda0nap=self._fixed_parameters.a_nap_lambda0nap,
            bb_lambda_ref=self._fixed_parameters.bb_lambda_ref,
            water_refractive_index=self._fixed_parameters.water_refractive_index,
            theta_air=self._fixed_parameters.theta_air,
            off_nadir=self._fixed_parameters.off_nadir,
            q_factor=self._fixed_parameters.q_factor)

        closed_rrs = sbc.apply_sensor_filter(
            model_results.rrs,
            self._sensor_filter)

        return self._error_func(self.observed_rrs, closed_rrs, self._nedr)
Ejemplo n.º 5
0
    def __call__(self, parameters):
        """
        Returns an objective score for the given parameter set.

        Args:
            parameters (ndarray): The parameter array in the order
                (chl, cdom, nap, depth, substrate_fraction)
                as defined in the FreeParameters tuple
          
        """

        # TODO: do I need to implement this? Here or in a subclass?
        # To support algorithms without support for boundary values, we assign a high
        # score to out of range parameters. This may not be the best approach!!!
        # p_bounds is a tuple of (min, max) pairs for each parameter in p
        '''
        if p_bounds is not None:
            for _p, lu in zip(p, p_bounds):
                l, u = lu
                if _p < l or _p > u:
                    return 100000.0
        '''

        # Select the substrate pair from the list of substrates
        #id1 = self._fixed_parameters.substrate_combinations[self.id][0]
        #id2 = self._fixed_parameters.substrate_combinations[self.id][1]

        # Generate results from the given parameters
        model_results = sbc.forward_model(
            chl=parameters[0],
            cdom=parameters[1],
            nap=parameters[2],
            depth=parameters[3],
            sub1_frac=parameters[4],
            sub2_frac=parameters[5],
            sub3_frac=parameters[6],
            substrate1=self._fixed_parameters.substrates[0],
            substrate2=self._fixed_parameters.substrates[1],
            substrate3=self._fixed_parameters.substrates[2],
            wavelengths=self._fixed_parameters.wavelengths,
            a_water=self._fixed_parameters.a_water,
            a_ph_star=self._fixed_parameters.a_ph_star,
            num_bands=self._fixed_parameters.num_bands,
            a_cdom_slope=self._fixed_parameters.a_cdom_slope,
            a_nap_slope=self._fixed_parameters.a_nap_slope,
            bb_ph_slope=self._fixed_parameters.bb_ph_slope,
            bb_nap_slope=self._fixed_parameters.bb_nap_slope,
            lambda0cdom=self._fixed_parameters.lambda0cdom,
            lambda0nap=self._fixed_parameters.lambda0nap,
            lambda0x=self._fixed_parameters.lambda0x,
            x_ph_lambda0x=self._fixed_parameters.x_ph_lambda0x,
            x_nap_lambda0x=self._fixed_parameters.x_nap_lambda0x,
            a_cdom_lambda0cdom=self._fixed_parameters.a_cdom_lambda0cdom,
            a_nap_lambda0nap=self._fixed_parameters.a_nap_lambda0nap,
            bb_lambda_ref=self._fixed_parameters.bb_lambda_ref,
            water_refractive_index=self._fixed_parameters.
            water_refractive_index,
            theta_air=self._fixed_parameters.theta_air,
            off_nadir=self._fixed_parameters.off_nadir,
            q_factor=self._fixed_parameters.q_factor)

        closed_rrs = sbc.apply_sensor_filter(model_results.rrs,
                                             self._sensor_filter)
        closed_rrs_dchl = sbc.apply_sensor_filter(model_results.rrs_dchl,
                                                  self._sensor_filter)
        closed_rrs_dcdom = sbc.apply_sensor_filter(model_results.rrs_dcdom,
                                                   self._sensor_filter)
        closed_rrs_dnap = sbc.apply_sensor_filter(model_results.rrs_dnap,
                                                  self._sensor_filter)
        closed_rrs_ddepth = sbc.apply_sensor_filter(model_results.rrs_ddepth,
                                                    self._sensor_filter)
        closed_rrs_dfrac1 = sbc.apply_sensor_filter(model_results.rrs_dfrac1,
                                                    self._sensor_filter)
        closed_rrs_dfrac2 = sbc.apply_sensor_filter(model_results.rrs_dfrac2,
                                                    self._sensor_filter)
        closed_rrs_dfrac3 = sbc.apply_sensor_filter(model_results.rrs_dfrac3,
                                                    self._sensor_filter)

        if self._error_func_name == 'lsq':
            C = np.linalg.norm(closed_rrs - self.observed_rrs)
            C_dcdom = np.sum(
                (self.observed_rrs - closed_rrs) * (-closed_rrs_dcdom)) / C
            C_dchl = np.sum(
                (self.observed_rrs - closed_rrs) * (-closed_rrs_dchl)) / C
            C_dnap = np.sum(
                (self.observed_rrs - closed_rrs) * (-closed_rrs_dnap)) / C
            C_ddepth = np.sum(
                (self.observed_rrs - closed_rrs) * (-closed_rrs_ddepth)) / C
            C_dfrac1 = np.sum(
                (self.observed_rrs - closed_rrs) * (-closed_rrs_dfrac1)) / C
            C_dfrac2 = np.sum(
                (self.observed_rrs - closed_rrs) * (-closed_rrs_dfrac2)) / C
            C_dfrac3 = np.sum(
                (self.observed_rrs - closed_rrs) * (-closed_rrs_dfrac3)) / C
            jacobian = np.array([
                C_dchl, C_dcdom, C_dnap, C_ddepth, C_dfrac1, C_dfrac2, C_dfrac3
            ])
            return C, jacobian

        if self._nedr is not None:
            # deliberately avoiding an in-place divide as I want a copy of the
            # spectra to avoid side-effects due to pass by reference semantics
            closed_rrs_dchl = closed_rrs_dchl / self._nedr
            closed_rrs_dcdom = closed_rrs_dcdom / self._nedr
            closed_rrs_dnap = closed_rrs_dnap / self._nedr
            closed_rrs_ddepth = closed_rrs_ddepth / self._nedr
            closed_rrs_dfrac1 = closed_rrs_dfrac1 / self._nedr
            closed_rrs_dfrac2 = closed_rrs_dfrac2 / self._nedr
            closed_rrs_dfrac3 = closed_rrs_dfrac3 / self._nedr
            closed_rrs = closed_rrs / self._nedr
            observed_rrsNedr = self.observed_rrs / self._nedr
        #alpha_f=A*B
        normClosed_rss = np.linalg.norm(closed_rrs)
        normObserved_rss = np.linalg.norm(observed_rrsNedr)
        F = normClosed_rss * normObserved_rss
        F = np.clip(F, 1e-9, F)
        F2 = F * F
        #F2 = np.clip(F2, 1e-9, F2)
        E = np.sum(closed_rrs * observed_rrsNedr)
        G = E / F
        G = np.clip(G, 0.0, 1.0)
        G_div = np.power((1.0 - G * G), 0.5)
        #G_div = np.clip(G_div, 1e-9, G_div)
        D = np.sum(observed_rrsNedr)
        C = np.linalg.norm(closed_rrs - observed_rrsNedr)
        #C = np.clip(C, 1e-9, C)
        B = np.arccos(G)
        A = C / D
        F_dcdom = normObserved_rss * np.sum(
            closed_rrs * closed_rrs_dcdom) / normClosed_rss
        E_dcdom = np.sum(observed_rrsNedr * closed_rrs_dcdom)
        G_dcdom = (E_dcdom * F - F_dcdom * E) / F2
        C_dcdom = np.sum(
            (observed_rrsNedr - closed_rrs) * (-closed_rrs_dcdom)) / C
        B_dcdom = -G_dcdom / G_div
        A_dcdom = C_dcdom / D

        F_dchl = normObserved_rss * np.sum(
            closed_rrs * closed_rrs_dchl) / normClosed_rss
        E_dchl = np.sum(observed_rrsNedr * closed_rrs_dchl)
        G_dchl = (E_dchl * F - F_dchl * E) / F2
        C_dchl = np.sum(
            (observed_rrsNedr - closed_rrs) * (-closed_rrs_dchl)) / C
        B_dchl = -G_dchl / G_div
        A_dchl = C_dchl / D

        F_dnap = normObserved_rss * np.sum(
            closed_rrs * closed_rrs_dnap) / normClosed_rss
        E_dnap = np.sum(observed_rrsNedr * closed_rrs_dnap)
        G_dnap = (E_dnap * F - F_dnap * E) / F2
        C_dnap = np.sum(
            (observed_rrsNedr - closed_rrs) * (-closed_rrs_dnap)) / C
        B_dnap = -G_dnap / G_div
        A_dnap = C_dnap / D

        F_ddepth = normObserved_rss * np.sum(
            closed_rrs * closed_rrs_ddepth) / normClosed_rss
        E_ddepth = np.sum(observed_rrsNedr * closed_rrs_ddepth)
        G_ddepth = (E_ddepth * F - F_ddepth * E) / F2
        C_ddepth = np.sum(
            (observed_rrsNedr - closed_rrs) * (-closed_rrs_ddepth)) / C
        B_ddepth = -G_ddepth / G_div
        A_ddepth = C_ddepth / D

        F_dfrac1 = normObserved_rss * np.sum(
            closed_rrs * closed_rrs_dfrac1) / normClosed_rss
        E_dfrac1 = np.sum(observed_rrsNedr * closed_rrs_dfrac1)
        G_dfrac1 = (E_dfrac1 * F - F_dfrac1 * E) / F2
        C_dfrac1 = np.sum(
            (observed_rrsNedr - closed_rrs) * (-closed_rrs_dfrac1)) / C
        B_dfrac1 = -G_dfrac1 / G_div
        A_dfrac1 = C_dfrac1 / D

        F_dfrac2 = normObserved_rss * np.sum(
            closed_rrs * closed_rrs_dfrac2) / normClosed_rss
        E_dfrac2 = np.sum(observed_rrsNedr * closed_rrs_dfrac2)
        G_dfrac2 = (E_dfrac2 * F - F_dfrac2 * E) / F2
        C_dfrac2 = np.sum(
            (observed_rrsNedr - closed_rrs) * (-closed_rrs_dfrac2)) / C
        B_dfrac2 = -G_dfrac2 / G_div
        A_dfrac2 = C_dfrac2 / D

        F_dfrac3 = normObserved_rss * np.sum(
            closed_rrs * closed_rrs_dfrac3) / normClosed_rss
        E_dfrac3 = np.sum(observed_rrsNedr * closed_rrs_dfrac3)
        G_dfrac3 = (E_dfrac3 * F - F_dfrac3 * E) / F2
        C_dfrac3 = np.sum(
            (observed_rrsNedr - closed_rrs) * (-closed_rrs_dfrac3)) / C
        B_dfrac3 = -G_dfrac3 / G_div
        A_dfrac3 = C_dfrac3 / D

        if self._error_func_name == 'alpha_f':
            Jac_cdom = B * A_dcdom + B_dcdom * A
            Jac_chl = B * A_dchl + B_dchl * A
            Jac_nap = B * A_dnap + B_dnap * A
            Jac_depth = B * A_ddepth + B_ddepth * A
            Jac_frac1 = B * A_dfrac1 + B_dfrac1 * A
            Jac_frac2 = B * A_dfrac2 + B_dfrac2 * A
            Jac_frac3 = B * A_dfrac3 + B_dfrac3 * A
            jacobian = np.array([
                Jac_chl, Jac_cdom, Jac_nap, Jac_depth, Jac_frac1, Jac_frac2,
                Jac_frac3
            ])
            errorValue = A * B

        if self._error_func_name == 'alpha':
            jacobian = np.array([
                B_dchl, B_dcdom, B_dnap, B_ddepth, B_dfrac1, B_dfrac2, B_dfrac3
            ])
            errorValue = B

        if self._error_func_name == 'f':
            jacobian = np.array([
                A_dchl, A_dcdom, A_dnap, A_ddepth, A_dfrac1, A_dfrac2, A_dfrac3
            ])
            errorValue = A

        #return self._error_func(self.observed_rrs, closed_rrs, self._nedr),jacobian
        #print("A*B{0}  A*B{1:.6f} A*B{2:.6f} A*B{3:.6f} A*B{4:.6f} A*B{5:.6f} A*B{6:.6f} A*B{7:.6f}".format(A*B,jacobian[0],jacobian[1],jacobian[2],jacobian[3],jacobian[4],jacobian[5],jacobian[6]))
        #print("Z{0}  {1:.6f} {2:.6f} {3:.6f} {4:.6f} {5:.6f} {6:.6f}".format(parameters[0],parameters[1],parameters[2],parameters[3],parameters[4],parameters[5],parameters[6]))
        #print("A{0}  B{1:.6f} C{2:.6f} D{3:.6f} E{4:.6f} F{5:.6f} G{6:.6f}".format(A,B,C,D,E,F,G))
        return errorValue, jacobian