def ft_even_diffuse_reflection_matrix(self, frequency, eps_1, mu_s, mu_i, m_max, npol): assert mu_s is mu_i if isinstance(self.backscattering_coefficient, dict): # we have a dictionary with polarization diffuse_refl_coeff = smrt_matrix.zeros( (npol, m_max + 1, len(mu_i))) for m in range(m_max + 1): if m == 0: coef = 0.5 elif (m % 2) == 1: coef = -1.0 else: coef = 1.0 coef /= 4 * np.pi * mu_i # SMRT requires scattering coefficient / 4 * pi coef /= m_max + 0.5 # ad hoc normalization to get the right backscatter. This is a trick to deal with the dirac. diffuse_refl_coeff[0, m, :] += coef * self._get_refl( self.backscattering_coefficient['VV'], mu_i) diffuse_refl_coeff[1, m, :] += coef * self._get_refl( self.backscattering_coefficient['HH'], mu_i) elif self.backscattering_coefficient is not None: raise SMRTError( "backscattering_coefficient must be a dictionary with keys VV and HH" ) else: return smrt_matrix(0) return diffuse_refl_coeff
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
def ft_even_diffuse_reflection_matrix(self, frequency, eps_1, eps_2, mu_s, mu_i, m_max, npol): assert mu_s is mu_i diffuse_refl_coeff = smrt_matrix.zeros((npol, m_max + 1, len(mu_i))) gamma = self.diffuse_reflection_matrix(frequency, eps_1, eps_2, mu_s, mu_i, dphi=np.pi, npol=npol) for m in range(m_max + 1): if m == 0: coef = 0.5 elif (m % 2) == 1: coef = -1.0 else: coef = 1.0 coef /= ( m_max + 0.5 ) # ad hoc normalization to get the right backscatter. This is a trick to deal with the dirac. diffuse_refl_coeff[:, m, :] = coef * gamma[:, :] return diffuse_refl_coeff
def phase(self, mu_s, mu_i, dphi, npol=2): """Non-scattering phase matrix. Returns : null phase matrix """ return smrt_matrix.zeros((npol, npol, len(dphi), len(mu_s), len(mu_i)))
def ft_even_diffuse_reflection_matrix(self, frequency, eps_1, eps_2, mu_s, mu_i, m_max, npol): m = smrt_matrix.zeros((npol, m_max + 1, len_atleast_1d(mu_s))) # only mode 0, pola 0 and 1, are non-null m[0:2, 0, :] = 1. return m
def ft_even_phase(self, mu_s, mu_i, m_max, npol=None): """ Non-scattering phase matrix. Returns : null phase matrix """ if npol is None: npol = 2 if m_max == 0 else 3 return smrt_matrix.zeros((npol, npol, m_max + 1, len(mu_s), len(mu_i)))
def specular_reflection_matrix(self, frequency, eps_1, eps_2, mu1, npol): """compute the reflection 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 mhu1: array of cosine of incident angles :param npol: number of polarization """ assert len(mu1.shape) == 1 # 1D array return smrt_matrix.zeros((npol, len(mu1)))
def emissivity_matrix(self, frequency, eps_1, mu1, npol): if self.specular_reflection is None and self.backscatter_coefficient is None: self.specular_reflection = 1 if npol > 2: raise NotImplementedError("active model is not yet implemented, need modification for the third compunant") emissivity = smrt_matrix.zeros((npol, len(mu1))) if isinstance(self.specular_reflection, dict): # we have a dictionary with polarization emissivity[0] = 1 - self._get_refl(self.specular_reflection['V'], mu1) emissivity[1] = 1 - self._get_refl(self.specular_reflection['H'], mu1) else: # we have a scalar, both polarization are the same emissivity[0] = emissivity[1] = 1 - self._get_refl(self.specular_reflection, mu1) return emissivity
def specular_reflection_matrix(self, frequency, eps_1, mu1, npol): if npol > 2 and not hasattr(Reflector, "stop_pol2_warning"): print("active model is not yet fully implemented, need modification for the third component") # !!! Reflector.stop_pol2_warning = True if self.specular_reflection is None and self.backscattering_coefficient is None: self.specular_reflection = 1 spec_refl_coeff = smrt_matrix.zeros((npol, len(mu1))) if isinstance(self.specular_reflection, dict): # we have a dictionary with polarization spec_refl_coeff[0] = self._get_refl(self.specular_reflection['V'], mu1) spec_refl_coeff[1] = self._get_refl(self.specular_reflection['H'], mu1) else: # we have a scalar, both polarization are the same spec_refl_coeff[0] = spec_refl_coeff[1] = self._get_refl(self.specular_reflection, mu1) return spec_refl_coeff
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_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. " ) R_normal, _, _ = fresnel_coefficients(eps_1, eps_2, np.ones(1)) tantheta_i2 = 1 / mu_i**2 - 1 smrt_norm = 1 / (4 * np.pi) gamma = smrt_norm / (2 * self.mean_square_slope) * np.abs( R_normal)**2 / mu_i**5 * np.exp(-tantheta_i2 / (2 * self.mean_square_slope)) if self.shadow_correction: gamma *= 1 / (1 + shadow_function(self.mean_square_slope, 1 / np.sqrt(tantheta_i2))) reflection_coefficients = smrt_matrix.zeros((npol, len(mu_i))) reflection_coefficients[0] = gamma reflection_coefficients[1] = gamma return reflection_coefficients
def coherent_transmission_matrix(self, frequency, eps_1, eps_2, mu1, npol): """compute the transmission coefficients for an array of incidence angles (given by their cosine) in medium 1. Medium 2 is where the beam is transmitted. While Geometrical Optics, we here consider that power not reflected is scattered in the specular transmitted direction. This is an approximation which is reasonable in the context of a "1st order" geometrical optics. :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 """ go = GeometricalOptics(mean_square_slope=self.mean_square_slope, shadow_function=self.shadow_correction) total_reflection = go.reflection_coefficients(frequency, eps_1, eps_2, mu1) transmission_matrix = smrt_matrix.zeros((npol, len_atleast_1d(mu1))) transmission_matrix[0] = 1 - total_reflection[0] transmission_matrix[1] = 1 - total_reflection[1] return transmission_matrix
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
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
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
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
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
def diffuse_reflection_matrix(self, frequency, eps_1, eps_2, mu_s, mu_i, dphi, npol): m = smrt_matrix.zeros((npol, len_atleast_1d(dphi), len_atleast_1d(mu_i))) m[0:2, :, :] = 1. return m