Пример #1
0
    def specular_reflection_matrix(self, frequency, eps_1, eps_2, mu1, npol):
        """compute the reflection coefficients for an array of incidence angles (given by their cosine)
           in medium 1. Medium 2 is where the beam is transmitted.

        :param eps_1: permittivity of the medium where the incident beam is propagating.
        :param eps_2: permittivity of the other medium.
        :param mu1: array of cosine of incident angles.
        :param npol: number of polarization.

        :return: the reflection matrix
"""

        R01_v, R01_h, R1t_v, R1t_h, exp_kd, exp_2kd, mu_t = self._prepare_computation(frequency, eps_1, eps_2, mu1)

        R_v = (R01_v + R1t_v * exp_2kd) / (1 + R01_v * R1t_v * exp_2kd)
        R_h = (R01_h + R1t_h * exp_2kd) / (1 + R01_h * R1t_h * exp_2kd)

        reflection_coefficients = smrt_matrix.ones((npol, len(mu1)))

        reflection_coefficients[0] = abs2(R_v)
        reflection_coefficients[1] = abs2(R_h)

        if npol >= 3:
            reflection_coefficients[2] = (R_v * np.conj(R_h)).real   # TsangI  Eq 7.2.93

        return reflection_coefficients
Пример #2
0
    def coherent_transmission_matrix(self, frequency, eps_1, eps_2, mu1, npol):
        """compute the transmission coefficients for the azimuthal mode m
           and for an array of incidence angles (given by their cosine)
           in medium 1. Medium 2 is where the beam is transmitted.

        :param eps_1: permittivity of the medium where the incident beam is propagating.
        :param eps_2: permittivity of the other medium.
        :param mu1: array of cosine of incident angles.
        :param npol: number of polarization.

        :return: the transmission matrix
"""

        R01_v, R01_h, R1t_v, R1t_h, exp_kd, exp_2kd, mu_t = self._prepare_computation(frequency, eps_1, eps_2, mu1)

        T_v = (1 + R01_v) * (1 + R1t_v) * exp_kd / (1 + R01_v * R1t_v * exp_2kd)  # see TsnagI 5.2.10-12
        T_h = (1 + R01_h) * (1 + R1t_h) * exp_kd / (1 + R01_h * R1t_h * exp_2kd)

        transmission_coefficients = smrt_matrix.ones((npol, len(mu1)))

        nt = np.sqrt(eps_2 / eps_1).real
        transmission_coefficients[0] = abs2(T_v) * mu_t / mu1 / nt  # for the coef see TsangIII 2.1.140b
        transmission_coefficients[1] = abs2(T_h) * mu_t / mu1 * nt  # for the coef see TsangIII 2.1.140a

        if npol >= 3:
            # this part is to be confirmed.
            R_v = (R01_v + R1t_v * exp_2kd) / (1 + R01_v * R1t_v * exp_2kd)
            R_h = (R01_h + R1t_h * exp_2kd) / (1 + R01_h * R1t_h * exp_2kd)

            transmission_coefficients[2] = mu_t / mu1 * ((1 + R_v) * np.conj(1 + R_h)).real  # TsangI  Eq 7.2.95

        return transmission_coefficients
Пример #3
0
def fresnel_reflection_matrix(eps_1, eps_2, mu1, npol):
    """compute the fresnel reflection matrix for/in medium 1 laying above medium 2.

    :param npol: number of polarizations to return.
    :param eps_1: permittivity of medium 1.
    :param eps_2: permittivity of medium 2.
    :param mu1: cosine zenith angle in medium 1.

    :returns: a matrix or the diagional depending on `return_as_diagonal`
"""

    mu1 = np.atleast_1d(mu1)
    assert len(mu1.shape) == 1  # 1D array

    reflection_coefficients = smrt_matrix.ones((npol, len(mu1)))

    rv, rh, _ = fresnel_coefficients(eps_1, eps_2, mu1)

    reflection_coefficients[0] = abs2(rv)
    reflection_coefficients[1] = abs2(rh)

    if npol >= 3:
        reflection_coefficients[2] = (rv *
                                      np.conj(rh)).real  # TsangI  Eq 7.2.93

    return reflection_coefficients
Пример #4
0
def fresnel_transmission_matrix(eps_1, eps_2, mu1, npol):
    """compute the fresnel reflection matrix for/in medium 1 laying above medium 2.

    :param npol: number of polarizations to return.
    :param eps_1: permittivity of medium 1.
    :param eps_2: permittivity of medium 2.
    :param mu1: cosine zenith angle in medium 1.

    :returns: a matrix or the diagional depending on `return_as_diagonal`
"""

    mu1 = np.atleast_1d(mu1)
    assert len(mu1.shape) == 1  # 1D array

    transmission_coefficients = smrt_matrix.zeros((npol, len(mu1)))

    rv, rh, mu2 = fresnel_coefficients(eps_1, eps_2, mu1)

    transmission_coefficients[0] = 1 - abs2(rv)
    transmission_coefficients[1] = 1 - abs2(rh)
    if npol >= 3:
        transmission_coefficients[2] = mu2 / mu1 * (
            (1 + rv) * np.conj(1 + rh)).real  # TsangI  Eq 7.2.95
    if npol == 4:
        raise Exception(
            "to be implemented, the matrix is not diagonal anymore")

    return transmission_coefficients
Пример #5
0
    def transmission_integrand_for_energy_conservation_test(self, frequency, eps_1, eps_2, mu_t, mu_i, dphi):
        """function relevant to compute energy conservation. See p87 in Tsang_tomeIII.
"""
        n_2 = np.sqrt(eps_2)
        n_1 = np.sqrt(eps_1)

        mu_i = np.atleast_1d(mu_i)[np.newaxis, np.newaxis, :]
        mu_t = np.atleast_1d(mu_t)[np.newaxis, :, np.newaxis]
        dphi = np.atleast_1d(dphi)[:, np.newaxis, np.newaxis]

        sin_i = np.sqrt(1 - mu_i**2)
        sin_t = np.sqrt(1 - mu_t**2)

        cos_phi = np.cos(dphi)
        sin_phi = np.sin(dphi)

        ki = vector3.from_xyz(sin_i, 0, -mu_i)
        kt = vector3.from_xyz(sin_t * cos_phi, sin_t * sin_phi, -mu_t)

        # compute the local transmission Fresnel coefficient
        ktd = n_1.real * ki - n_2.real * kt   # Eq 2.1.87

        n = ktd / (np.sign(ktd.z) * ktd.norm)  # Eq 2.1.128

        mu_local = -vector3.dot(n, ki)

        Rv, Rh, _ = fresnel_coefficients(eps_1, eps_2, mu_local)
 
        # define polarizations
        ht = vector3.from_xyz(-sin_phi, cos_phi, 0)
        vt = vector3.from_xyz(-mu_t * cos_phi, -mu_t * sin_phi, -sin_t)

        #print(vector3.cross(vt, ht), kt)

        hi = vector3.from_xyz(0, 1, 0)
        vi = vector3.from_xyz(-mu_i, 0, -sin_i)

        #print(vector3.cross(vi, hi), ki)

        ht_ki = vector3.dot(ht, ki)
        vt_ki = vector3.dot(vt, ki)

        hi_kt = vector3.dot(hi, kt)
        vi_kt = vector3.dot(vi, kt)

        Tv =  (hi_kt**2) * (1-abs2(Rh)) + (vi_kt**2) * (1-abs2(Rv))
        Th =  (vi_kt**2) * (1-abs2(Rh)) + (hi_kt**2) * (1-abs2(Rv))

        coef = 1/(2 * np.pi * self.mean_square_slope) * eps_2 * ktd.norm2 * vector3.dot(n, kt) * vector3.dot(n, ki)  \
                / (mu_i * vector3.cross(ki, kt).norm2 * ktd.z**4 ) * \
                np.exp(-(ktd.x**2 + ktd.y**2) / (2 * ktd.z**2 * self.mean_square_slope))   # Eq. 2.1.130   NB: k1^2 -> eps_2

        #return Tv, Th  #
        return coef*Tv, coef*Th
Пример #6
0
    def reflection_integrand_for_energy_conservation_test(self, frequency, eps_1, eps_2, mu_s, mu_i, dphi):
        """function relevant to compute energy conservation. See p87 in Tsang_tomeIII.
"""
        mu_i = np.atleast_1d(mu_i)[np.newaxis, np.newaxis, :]
        mu_s = np.atleast_1d(mu_s)[np.newaxis, :, np.newaxis]
        dphi = np.atleast_1d(dphi)[:, np.newaxis, np.newaxis]

        sin_i = np.sqrt(1 - mu_i**2)
        sin_s = np.sqrt(1 - mu_s**2)

        cos_phi = np.cos(dphi)
        sin_phi = np.sin(dphi)

        ki = vector3.from_xyz(sin_i, 0, -mu_i)
        ks = vector3.from_xyz(sin_s * cos_phi, sin_s * sin_phi, mu_s)

        # compute the local reflection Fresnel coefficient
        kd = ki - ks   # in principe: *sqrt(eps_1), but in the following it appears everywhere as a ratio

        n = kd / (np.sign(kd.z) * kd.norm)  # EQ 2.1.223 #equivalent to np.vector3(kd_x / kd_z, kd_y / kd_z, 1)

        mu_local = -vector3.dot(n, ki)

        Rv, Rh, _ = fresnel_coefficients(eps_1, eps_2, mu_local)
 
        # define polarizations
        hs = vector3.from_xyz(-sin_phi, cos_phi, 0)
        vs = vector3.from_xyz(mu_s * cos_phi, mu_s * sin_phi, -sin_s)

        #print(vector3.cross(vs, hs), ks)

        hi = vector3.from_xyz(0, 1, 0)
        vi = vector3.from_xyz(-mu_i, 0, -sin_i)

        #print(vector3.cross(vi, hi), ki)

        hs_ki = vector3.dot(hs, ki)
        vs_ki = vector3.dot(vs, ki)

        hi_ks = vector3.dot(hi, ks)
        vi_ks = vector3.dot(vi, ks)

        coef = 1/(2 * np.pi * self.mean_square_slope) * kd.norm2**2 / (4 * mu_i * vector3.cross(ki, ks).norm2 * kd.z**4) * \
                         np.exp( - (kd.x**2 + kd.y**2)/ (2 * kd.z**2 * self.mean_square_slope))  # Eq. 2.1.124 

        return coef * (hi_ks**2 * abs2(Rh) + vi_ks**2 * abs2(Rv)), \
               coef * (vi_ks**2 * abs2(Rh) + hi_ks**2 * abs2(Rv)) 
Пример #7
0
    def specular_reflection_matrix(self, frequency, eps_1, eps_2, mu1, npol):
        """compute the reflection coefficients for an array of incidence angles (given by their cosine)
           in medium 1. Medium 2 is where the beam is transmitted.

        :param eps_1: permittivity of the medium where the incident beam is propagating.
        :param eps_2: permittivity of the other medium
        :param mu1: array of cosine of incident angles
        :param npol: number of polarization

        :return: the reflection matrix
"""
        k2 = (2 * np.pi * frequency / C_SPEED) ** 2 * abs2(eps_1)
        return fresnel_reflection_matrix(eps_1, eps_2, mu1, npol) * np.exp(-4 * k2 * self.roughness_rms**2 * mu1**2)    # Eq: 2.1.94 in Tsang 2001 Tome I
Пример #8
0
    def diffuse_reflection_matrix(self,
                                  frequency,
                                  eps_1,
                                  eps_2,
                                  mu_s,
                                  mu_i,
                                  dphi,
                                  npol,
                                  debug=False):
        """compute the reflection coefficients for an array of incident, scattered and azimuth angles 
           in medium 1. Medium 2 is where the beam is transmitted.

        :param eps_1: permittivity of the medium where the incident beam is propagating.
        :param eps_2: permittivity of the other medium
        :param mu1: array of cosine of incident angles
        :param npol: number of polarization

        :return: the reflection matrix
"""
        mu_s = np.atleast_1d(mu_s)
        mu_i = np.atleast_1d(mu_i)

        if not np.allclose(mu_s, mu_i) or not np.allclose(dphi, np.pi):
            raise NotImplementedError(
                "Only the backscattering coefficient is implemented at this stage. This is a very preliminary implementation"
            )

        if len(np.atleast_1d(dphi)) != 1:
            raise NotImplementedError(
                "Only the backscattering coefficient is implemented at this stage. "
            )

        mu = mu_i[None, :]
        k = vector3.from_angles(
            2 * np.pi * frequency / C_SPEED * np.sqrt(eps_1).real, mu, 0)
        eps_r = eps_2 / eps_1

        # check validity
        warning = None
        ks = abs(k.norm * self.roughness_rms)
        if ks > 3:
            warning = "Warning, roughness_rms is too high for the given wavelength. Limit is ks < 3. Here ks=%g" % ks

        kskl = abs(ks * k.norm * self.corr_length)
        if kskl > np.sqrt(eps_r):
            warning = "Warning, roughness_rms or correlation_length are too high for the given wavelength. Limit is ks * kl < sqrt(eps_r). Here ks*kl=%g and sqrt(eps_r)=%g" % (
                kskl, np.sqrt(eps_r))

        if warning:
            if self.warning_handling == "print":
                print(warning)
            elif self.warning_handling == "nan":
                return smrt_matrix.full((npol, len(mu_i)), np.nan)
        # chekc validity done

        Rv, Rh, _ = fresnel_coefficients(eps_1, eps_2, mu_i)

        fvv = 2 * Rv / mu  # Eq 44 in Fung et al. 1992
        fhh = -2 * Rh / mu  # Eq 45 in Fung et al. 1992

        # prepare the series
        N = self.series_truncation
        n = np.arange(1, N + 1, dtype=np.float64)[:, None]

        rms2 = self.roughness_rms**2

        # Kirchoff term
        Iscalar_n = (2 * k.z)**n * np.exp(-rms2 * k.z**2)
        Ivv_n = Iscalar_n * fvv  # Eq 82 in Fung et al. 1992
        Ihh_n = Iscalar_n * fhh

        # Complementary term
        mu2 = mu**2
        sin2 = 1 - mu2
        tan2 = sin2 / mu2
        Ivv_n += k.z**n * (
            sin2 / mu * (1 + Rv)**2 * (1 - 1 / eps_r) * (1 + tan2 / eps_r)
        )  # part of Eq 91. We don't use all the simplification because we want validity for n>1, especially not np.exp(-rms2*k.z**2)=1
        Ihh_n += -k.z**n * (sin2 / mu * (1 + Rh)**2 *
                            (eps_r - 1) / mu2)  # part of Eq 95.

        # compute the series
        rms2_over_fractorial = np.cumprod(rms2 / n)[:, None]

        # Eq 82 in Fung et al. 1992
        coef = k.norm2 / 2 * np.exp(-2 * rms2 * k.z**2)
        coef_n = rms2_over_fractorial * self.W_n(n, -2 * k.x)

        sigma_vv = coef * np.sum(coef_n * abs2(Ivv_n), axis=0)
        sigma_hh = coef * np.sum(coef_n * abs2(Ihh_n), axis=0)

        #if debug:
        #    self.sigma_vv_1 = ( 8*k.norm2**2*rms2*abs2(Rv*mu2 + (1-mu2)*(1+Rv)**2 / 2 * (1 - 1 / eps_r)) * self.W_n(1, -2 * k.x) ).flat
        #    self.sigma_hh_1 = ( 8*k.norm2**2*rms2*abs2(Rh*mu2) * self.W_n(1, -2 * k.x) ).flat

        reflection_coefficients = smrt_matrix.zeros((npol, len(mu_i)))
        reflection_coefficients[0] = sigma_vv / (4 * np.pi * mu_i)
        reflection_coefficients[1] = sigma_hh / (4 * np.pi * mu_i)

        return reflection_coefficients
Пример #9
0
    def diffuse_reflection_matrix(self, frequency, eps_1, eps_2, mu_s, mu_i, dphi, npol):
        """compute the reflection coefficients for an array of incident, scattered and azimuth angles 
           in medium 1. Medium 2 is where the beam is transmitted.

        :param eps_1: permittivity of the medium where the incident beam is propagating.
        :param eps_2: permittivity of the other medium
        :param mu1: array of cosine of incident angles
        :param npol: number of polarization

        :return: the reflection matrix
"""
        mu_i = np.atleast_1d(mu_i)[np.newaxis, np.newaxis, :]
        mu_s = np.atleast_1d(mu_s)[np.newaxis, :, np.newaxis]
        dphi = np.atleast_1d(dphi)[:, np.newaxis, np.newaxis]

        sin_i = np.sqrt(1 - mu_i**2)
        sin_s = np.sqrt(1 - mu_s**2)

        cos_phi = np.cos(dphi)
        sin_phi = np.sin(dphi)

        ki = vector3.from_xyz(sin_i, 0, -mu_i)
        ks = vector3.from_xyz(sin_s * cos_phi, sin_s * sin_phi, mu_s)

        # compute the local reflection Fresnel coefficient
        kd = ki - ks   # in principe: *sqrt(eps_1), but in the following it appears everywhere as a ratio

        n = kd / (np.sign(kd.z) * kd.norm)  # EQ 2.1.223 #equivalent to np.vector3(kd_x / kd_z, kd_y / kd_z, 1)

        mu_local = -vector3.dot(n, ki)

        Rv, Rh, _ = fresnel_coefficients(eps_1, eps_2, mu_local)
 
        # define polarizations
        hs = vector3.from_xyz(-sin_phi, cos_phi, 0)
        vs = vector3.from_xyz(mu_s * cos_phi, mu_s * sin_phi, -sin_s)

        hi = vector3.from_xyz(0, 1, 0)
        vi = vector3.from_xyz(-mu_i, 0, -sin_i)

        # compute the dot products
        hs_ki = vector3.dot(hs, ki)
        vs_ki = vector3.dot(vs, ki)

        hi_ks = vector3.dot(hi, ks)
        vi_ks = vector3.dot(vi, ks)

        fvv = abs2( hs_ki * hi_ks * Rh + vs_ki* vi_ks * Rv)   # Eqs 2.1.122 in Tsang_tomeIII
        fhh = abs2( vs_ki * vi_ks * Rh + hs_ki* hi_ks * Rv)

        fhv = abs2( vs_ki * hi_ks * Rh - hs_ki* vi_ks * Rv)
        fvh = abs2( hs_ki * vi_ks * Rh + vs_ki* hi_ks * Rv)
        
        reflection_coefficients = smrt_matrix.zeros((npol, npol, dphi.shape[0], mu_s.shape[1], mu_i.shape[2]))
        reflection_coefficients[0, 0] = fvv
        reflection_coefficients[0, 1] = fvh
        reflection_coefficients[1, 0] = fhv
        reflection_coefficients[1, 1] = fhh

        smrt_norm = 1 / (4 * np.pi)  #  divide by 4*pi because this is the norm for SMRT

        coef = smrt_norm / (2 * self.mean_square_slope) / mu_i * kd.norm2**2 / (vector3.cross(ki, ks).norm2**2 * kd.z**4) * \
                         np.exp( - (kd.x**2 + kd.y**2)/ (2 * kd.z**2 * self.mean_square_slope))  # Eq. 2.1.124 

        if self.shadow_correction:

            backward = dphi == np.pi
            higher_thetas = mu_s <= mu_i
            zero_i = backward & higher_thetas
            zero_s = backward & ~higher_thetas

            s = 1 / (1 + zero_i * shadow_function(self.mean_square_slope, mu_i/sin_i) + zero_s * shadow_function(self.mean_square_slope, mu_s/sin_s))
            coef *= s

        return reflection_coefficients * coef
Пример #10
0
    def diffuse_transmission_matrix(self, frequency, eps_1, eps_2, mu_t, mu_i, dphi, npol):
        """compute the transmission coefficients for an array of incident, scattered and azimuth angles 
           in medium 1. Medium 2 is where the beam is transmitted.

        :param eps_1: permittivity of the medium where the incident beam is propagating.
        :param eps_2: permittivity of the other medium
        :param mu_i: array of cosine of incident angles
        :param mu_t: array of cosine of transmitted wave angles
        :param npol: number of polarization

        :return: the transmission matrix
"""
        n_2 = np.sqrt(eps_2)
        n_1 = np.sqrt(eps_1)

        eta1_eta = n_1 / n_2  # eta1 is the impedance in medium 2 and eta in medium 1. Impedance is sqrt(permeability/permittivity)

        mu_i = np.atleast_1d(mu_i)[np.newaxis, np.newaxis, :]
        mu_t = np.atleast_1d(mu_t)[np.newaxis, :, np.newaxis]
        dphi = np.atleast_1d(dphi)[:, np.newaxis, np.newaxis]

        sin_i = np.sqrt(1 - mu_i**2)
        sin_t = np.sqrt(1 - mu_t**2)

        cos_phi = np.cos(dphi)
        sin_phi = np.sin(dphi)

        ki = vector3.from_xyz(sin_i, 0, -mu_i)
        kt = vector3.from_xyz(sin_t * cos_phi, sin_t * sin_phi, -mu_t)

        # compute the local transmission Fresnel coefficient
        ktd = n_1.real * ki - n_2.real * kt   # Eq 2.1.87

        n = ktd / (np.sign(ktd.z) * ktd.norm)  # Eq 2.1.128

        mu_local = -vector3.dot(n, ki)

        Rv, Rh, _ = fresnel_coefficients(eps_1, eps_2, mu_local)

        n_kt = vector3.dot(n, kt)
        n_kt[mu_local < 0] = 0
 
        # define polarizations
        ht = vector3.from_xyz(-sin_phi, cos_phi, 0)
        vt = vector3.from_xyz(-mu_t * cos_phi, -mu_t * sin_phi, -sin_t)

        hi = vector3.from_xyz(0, 1, 0)
        vi = vector3.from_xyz(-mu_i, 0, -sin_i)

        # compute the cosines

        ht_ki = vector3.dot(ht, ki)
        vt_ki = vector3.dot(vt, ki)

        hi_kt = vector3.dot(hi, kt)
        vi_kt = vector3.dot(vi, kt)

        Wvv = abs2( ht_ki * hi_kt * (1 + Rh) + vt_ki * vi_kt * (1 + Rv) * eta1_eta)   # Eqs 2.1.130 in Tsang_tomeIII
        Whh = abs2( vt_ki * vi_kt * (1 + Rh) + ht_ki * hi_kt * (1 + Rv) * eta1_eta)

        Whv = abs2(-vt_ki * hi_kt * (1 + Rh) + ht_ki * vi_kt * (1 + Rv) * eta1_eta)
        Wvh = abs2( ht_ki * vi_kt * (1 + Rh) - vt_ki * hi_kt * (1 + Rv) * eta1_eta)
        
        transmission_coefficients = smrt_matrix.zeros((npol, npol, dphi.shape[0], mu_t.shape[1], mu_i.shape[2]))

        transmission_coefficients[0, 0] = Wvv
        transmission_coefficients[0, 1] = Wvh
        transmission_coefficients[1, 0] = Whv
        transmission_coefficients[1, 1] = Whh

        smrt_norm = 1 / (4 * np.pi)   # SMRT requires scattering coefficient / 4 * pi

        coef = smrt_norm * 2 * eps_2 / (eta1_eta * self.mean_square_slope) / mu_i * \
                ktd.norm2 * n_kt**2 / (vector3.cross(ki, kt).norm2**2 * ktd.z**4) * \
                np.exp(-(ktd.x**2 + ktd.y**2) / (2 * ktd.z**2 * self.mean_square_slope))   # Eq. 2.1.130   NB: k1^2 -> eps_2

        if self.shadow_correction:
            s = 1 / (1 + shadow_function(self.mean_square_slope, mu_i/sin_i) + shadow_function(self.mean_square_slope, mu_t/sin_t))
            coef *= s

        return transmission_coefficients * coef.real
Пример #11
0
    def diffuse_reflection_matrix(self, frequency, eps_1, eps_2, mu_s, mu_i,
                                  dphi, npol):
        """compute the reflection coefficients for an array of incident, scattered and azimuth angles 
           in medium 1. Medium 2 is where the beam is transmitted.

        :param eps_1: permittivity of the medium where the incident beam is propagating.
        :param eps_2: permittivity of the other medium
        :param mu1: array of cosine of incident angles
        :param npol: number of polarization

        :return: the reflection matrix
"""
        mu_i = np.atleast_1d(self.clip_mu(mu_i))[np.newaxis, np.newaxis, :]
        mu_s = np.atleast_1d(self.clip_mu(mu_s))[np.newaxis, :, np.newaxis]
        dphi = np.atleast_1d(dphi)[:, np.newaxis, np.newaxis]

        sin_i = np.sqrt(1 - mu_i**2)
        sin_s = np.sqrt(1 - mu_s**2)

        cos_phi = np.cos(dphi)
        sin_phi = np.sin(dphi)

        ki = vector3.from_xyz(sin_i, 0, -mu_i)
        ks = vector3.from_xyz(sin_s * cos_phi, sin_s * sin_phi, mu_s)

        # compute the local reflection Fresnel coefficient
        kd = ki - ks  # in principe: *sqrt(eps_1), but in the following it appears everywhere as a ratio

        n = kd / (
            np.sign(kd.z) * kd.norm
        )  # EQ 2.1.123 #equivalent to np.vector3(kd_x / kd_z, kd_y / kd_z, 1)

        mu_local = -vector3.dot(n, ki)
        assert (np.all(mu_local >= 0))
        assert (np.all(mu_local <= 1.0001))  # compare with some tolerance
        Rv, Rh, _ = fresnel_coefficients(eps_1, eps_2, self.clip_mu(mu_local))

        # define polarizations
        hs = vector3.from_xyz(-sin_phi, cos_phi, 0)
        vs = vector3.from_xyz(mu_s * cos_phi, mu_s * sin_phi, -sin_s)

        hi = vector3.from_xyz(0, 1, 0)
        vi = vector3.from_xyz(-mu_i, 0, -sin_i)

        # compute the dot products
        cross_ki_ks_norm = vector3.cross(ki, ks).norm
        colinear = cross_ki_ks_norm < 1e-4
        # avoid warning due to divide error, the colinear case is solved independantly:
        cross_ki_ks_norm[colinear] = 1

        hs_ki = vector3.dot(hs, ki) / cross_ki_ks_norm
        hs_ki[colinear] = -1
        vs_ki = vector3.dot(vs, ki) / cross_ki_ks_norm
        vs_ki[colinear] = 0

        hi_ks = vector3.dot(hi, ks) / cross_ki_ks_norm
        hi_ks[colinear] = 1

        vi_ks = vector3.dot(vi, ks) / cross_ki_ks_norm
        vi_ks[colinear] = 0

        fvv = abs2(hs_ki * hi_ks * Rh +
                   vs_ki * vi_ks * Rv)  # Eqs 2.1.122 in Tsang_tomeIII
        fhh = abs2(vs_ki * vi_ks * Rh + hs_ki * hi_ks * Rv)

        fhv = abs2(vs_ki * hi_ks * Rh - hs_ki * vi_ks * Rv)
        fvh = abs2(hs_ki * vi_ks * Rh - vs_ki * hi_ks * Rv)

        reflection_coefficients = smrt_matrix.zeros(
            (npol, npol, dphi.shape[0], mu_s.shape[1], mu_i.shape[2]))
        reflection_coefficients[0, 0] = fvv
        reflection_coefficients[0, 1] = fvh
        reflection_coefficients[1, 0] = fhv
        reflection_coefficients[1, 1] = fhh

        smrt_norm = 1 / (4 * np.pi
                         )  # divide by 4*pi because this is the norm for SMRT

        coef = smrt_norm / (2 * self.mean_square_slope) / mu_i * kd.norm2**2 / kd.z**4 * \
            np.exp(-(kd.x**2 + kd.y**2) / (2 * kd.z**2 * self.mean_square_slope))  # Eq. 2.1.124

        if self.shadow_correction:
            backward = dphi == np.pi
            higher_thetas = mu_s <= mu_i
            zero_i = backward & higher_thetas
            zero_s = backward & ~higher_thetas
            # this hack to avoid division-by-zero is safe, because the shadow_function is only important for large angles
            sin_i[sin_i < 1e-3] = 1e-3
            sin_s[sin_s < 1e-3] = 1e-3

            s = 1 / (1 + (~zero_i) *
                     shadow_function(self.mean_square_slope, mu_i / sin_i) +
                     (~zero_s) *
                     shadow_function(self.mean_square_slope, mu_s / sin_s))
            coef *= s

        return reflection_coefficients * coef
Пример #12
0
    def transmission_integrand_for_energy_conservation_test(
            self, frequency, eps_1, eps_2, mu_t, mu_i, dphi):
        """function relevant to compute energy conservation. See p87 in Tsang_tomeIII.
"""
        n_2 = np.sqrt(eps_2)
        n_1 = np.sqrt(eps_1)

        mu_i = np.atleast_1d(self.clip_mu(mu_i))[np.newaxis, np.newaxis, :]
        mu_t = np.atleast_1d(self.clip_mu(mu_t))[np.newaxis, :, np.newaxis]
        dphi = np.atleast_1d(dphi)[:, np.newaxis, np.newaxis]

        sin_i = np.sqrt(1 - mu_i**2)
        sin_t = np.sqrt(1 - mu_t**2)

        cos_phi = np.cos(dphi)
        sin_phi = np.sin(dphi)

        ki = vector3.from_xyz(sin_i, 0, -mu_i)
        kt = vector3.from_xyz(sin_t * cos_phi, sin_t * sin_phi, -mu_t)

        # compute the local transmission Fresnel coefficient
        ktd = n_1.real * ki - n_2.real * kt  # Eq 2.1.87

        n = ktd / (np.sign(ktd.z) * ktd.norm)  # Eq 2.1.128

        # compute Fresnel coefficients at stationary point
        n_kt = -vector3.dot(n, kt)
        n_ki = -vector3.dot(n, ki)

        Rh = (n_1.real * n_ki - n_2.real * n_kt) / (
            n_1.real * n_ki + n_2.real * n_kt)  # Eq. 2.1.132a
        Rv = (n_2.real * n_ki - n_1.real * n_kt) / (
            n_2.real * n_ki + n_1.real * n_kt)  # Eq. 2.1.132b

        no_compatible_slopes = (n_kt < 0) | (n_ki < 0)

        Rh[no_compatible_slopes] = -1
        Rv[no_compatible_slopes] = -1

        # define polarizations

        hi = vector3.from_xyz(0, 1, 0)
        vi = vector3.from_xyz(-mu_i, 0, -sin_i)

        hi_kt = vector3.dot(hi, kt)
        vi_kt = vector3.dot(vi, kt)

        Tv = (hi_kt**2) * (1 - abs2(Rh)) + (vi_kt**2) * (1 - abs2(Rv))
        Th = (vi_kt**2) * (1 - abs2(Rh)) + (hi_kt**2) * (1 - abs2(Rv))

        coef = eps_2 / (2 * np.pi * self.mean_square_slope) * ktd.norm2 * n_kt * n_ki  \
            / (mu_i * vector3.cross(ki, kt).norm2 * ktd.z**4) * \
            np.exp(- (ktd.x**2 + ktd.y**2) / (2 * ktd.z**2 * self.mean_square_slope))   # Eq. 2.1.130 NB: k1^2 -> eps_2

        if self.shadow_correction:
            sin_i[sin_i < 1e-3] = 1e-3
            sin_t[sin_t < 1e-3] = 1e-3
            s = 1 / (1 + shadow_function(self.mean_square_slope, mu_i / sin_i)
                     + shadow_function(self.mean_square_slope, mu_t / sin_t))
            coef *= s

        return coef * Tv, coef * Th
Пример #13
0
    def diffuse_transmission_matrix(self, frequency, eps_1, eps_2, mu_t, mu_i,
                                    dphi, npol):
        """compute the transmission coefficients for an array of incident, scattered and azimuth angles
           in medium 1. Medium 2 is where the beam is transmitted.

        :param eps_1: permittivity of the medium where the incident beam is propagating.
        :param eps_2: permittivity of the other medium
        :param mu_i: array of cosine of incident angles
        :param mu_t: array of cosine of transmitted wave angles
        :param npol: number of polarization

        :return: the transmission matrix
"""
        n_2 = np.sqrt(eps_2)
        n_1 = np.sqrt(eps_1)

        eta1_eta = n_1 / n_2  # eta1 is the impedance in medium 2 and eta in medium 1. Impedance is sqrt(permeability/permittivity)

        if abs(eta1_eta - 1) < 1e-6:
            raise NotImplementedError(
                "the case of successive layers with identical index (%g) is not implemented"
                % n_2)
            return 1 / (
                4 * np.pi
            )  # return the identity matrix. The coef is to be checked.

        mu_i = np.atleast_1d(self.clip_mu(mu_i))[np.newaxis, np.newaxis, :]
        mu_t = np.atleast_1d(self.clip_mu(mu_t))[np.newaxis, :, np.newaxis]
        dphi = np.atleast_1d(dphi)[:, np.newaxis, np.newaxis]

        sin_i = np.sqrt(1 - mu_i**2)
        sin_t = np.sqrt(1 - mu_t**2)

        cos_phi = np.cos(dphi)
        sin_phi = np.sin(dphi)

        ki = vector3.from_xyz(sin_i, 0, -mu_i)
        kt = vector3.from_xyz(sin_t * cos_phi, sin_t * sin_phi, -mu_t)

        # compute the local transmission Fresnel coefficient
        ktd = ki * n_1.real - kt * n_2.real  # Eq 2.1.87

        n = ktd / (np.sign(ktd.z) * ktd.norm)  # Eq 2.1.128

        n_kt = -vector3.dot(n, kt)
        n_ki = -vector3.dot(n, ki)

        # compute Fresnel coefficients at stationary point
        Rh = (n_1.real * n_ki - n_2.real * n_kt) / (
            n_1.real * n_ki + n_2.real * n_kt)  # Eq. 2.1.132a
        Rv = (n_2.real * n_ki - n_1.real * n_kt) / (
            n_2.real * n_ki + n_1.real * n_kt)  # Eq. 2.1.132b

        no_compatible_slopes = (n_kt < 0) | (n_ki < 0)

        Rh[no_compatible_slopes] = -1
        Rv[no_compatible_slopes] = -1

        # define polarizations
        ht = vector3.from_xyz(-sin_phi, cos_phi, 0)
        vt = vector3.from_xyz(-mu_t * cos_phi, -mu_t * sin_phi, -sin_t)

        hi = vector3.from_xyz(0, 1, 0)
        vi = vector3.from_xyz(-mu_i, 0, -sin_i)

        # compute the cosines
        cross_ki_kt_norm = vector3.cross(ki, kt).norm
        colinear = cross_ki_kt_norm < 1e-4
        # avoid warning due to divide error, the colinear case is solved independantly:
        cross_ki_kt_norm[colinear] = 1

        ht_ki = vector3.dot(ht, ki) / cross_ki_kt_norm
        ht_ki[colinear] = -1  # checked with sympy

        vt_ki = vector3.dot(vt, ki) / cross_ki_kt_norm
        vt_ki[colinear] = 0  # checked with sympy

        hi_kt = vector3.dot(hi, kt) / cross_ki_kt_norm
        hi_kt[colinear] = 1  # checked with sympy
        vi_kt = vector3.dot(vi, kt) / cross_ki_kt_norm
        vi_kt[colinear] = 0  # checked with sympy

        Wvv = abs2(ht_ki * hi_kt * (1 + Rh) + vt_ki * vi_kt *
                   (1 + Rv) * eta1_eta)  # Eqs 2.1.130 in Tsang_tomeIII
        Whh = abs2(vt_ki * vi_kt * (1 + Rh) + ht_ki * hi_kt *
                   (1 + Rv) * eta1_eta)

        Whv = abs2(-vt_ki * hi_kt * (1 + Rh) + ht_ki * vi_kt *
                   (1 + Rv) * eta1_eta)
        Wvh = abs2(ht_ki * vi_kt * (1 + Rh) - vt_ki * hi_kt *
                   (1 + Rv) * eta1_eta)

        transmission_coefficients = smrt_matrix.zeros(
            (npol, npol, dphi.shape[0], mu_t.shape[1], mu_i.shape[2]))

        transmission_coefficients[0, 0] = Wvv
        transmission_coefficients[0, 1] = Wvh
        transmission_coefficients[1, 0] = Whv
        transmission_coefficients[1, 1] = Whh

        smrt_norm = 1 / (4 * np.pi
                         )  # SMRT requires scattering coefficient / 4 * pi

        coef = smrt_norm * 2 * eps_2 * ktd.norm2 * n_kt**2 / (eta1_eta * self.mean_square_slope * mu_i * ktd.z**4) * \
            np.exp(-(ktd.x**2 + ktd.y**2) / (2 * ktd.z**2 * self.mean_square_slope))   # Eq. 2.1.130   NB: k1^2 -> eps_2

        if self.shadow_correction:
            # this hack to avoid division-by-zero is safe, because the shadow_function is only important for large angles
            sin_i[sin_i < 1e-3] = 1e-3
            sin_t[sin_t < 1e-3] = 1e-3
            s = 1 / (1 + shadow_function(self.mean_square_slope, mu_i / sin_i)
                     + shadow_function(self.mean_square_slope, mu_t / sin_t))
            coef *= s

        return transmission_coefficients * coef.real