Source code for cana.composition.shkuratov

r"""Shkuratov Model."""

import numpy as np
from .. import Spectrum
from numba import jit


[docs]class Shkuratov(object): r"""Shkuratov Reflectance Model. Adapted from Shkuratov (1999). """ def __init__(self, sample=None, grainsize=30, porosity=0.5): r"""Init Shkuratov model class. Parameters ---------- sample: Sample object The sample containing the information of the optical constant and grainsize porosity: float Positiy of the sample """ self.sample = sample self.porosity = porosity self.grain = grainsize @property def sample(self): """Contain Optical constant data array.""" return self._sample @sample.setter def sample(self, val): self._sample = val
[docs] def optical_density(self): r"""Calculate Optical Density.""" tau = (4 * np.pi * self.sample.k * self.grain) / self.sample.w return tau
[docs] def fresnel_coef(self): r"""Calculate Fresnel coeficient.""" r_0 = (self.sample.n - 1) ** 2 / (self.sample.n + 1) ** 2 return r_0
[docs] def scattering_coef(self): r"""Scatering coeficients based on Shkuratov (1999) approximations.""" # calculating internal_particle_reflection r_b, r_f = self.scattering_coef_aux( self.sample.n, self.sample.k, self.grain, self.sample.w ) # creating output scat = np.zeros(len(r_b), dtype=[("b", np.float64), ("f", np.float64)]) scat["b"] = r_b scat["f"] = r_f return scat
[docs] @staticmethod @jit(nopython=True) def scattering_coef_aux(n, k, grain, w): r"""Calculate the Scatering coeficient.""" tau = (4 * np.pi * k * grain) / w r0 = (n - 1) ** 2 / (n + 1) ** 2 Ri = 1.04 - (1 / n ** 2) # Using approximations for reflection Re = r0 + 0.05 Rb = (0.28 * n - 0.2) * Re Rf = r0 + 0.05 - (0.28 * n - 0.2) * Re # calculating transmision coeficients Te = 1 - Re Ti = 1 - Ri # average light scattering indicatrix of a particle rb = Rb + 0.5 * Te * Ti * Ri * np.exp(-2 * tau) / (1 - Ri * np.exp(-1 * tau)) rf = ( Rf + Ti * Te * (np.exp(-1 * tau)) + (0.5 * Te * Ti * Ri * np.exp(-2 * tau)) / (1 - Ri * np.exp(-1 * tau)) ) # print(rb,rf) return rb, rf
[docs] def build_spec(self, coef=None, albedo_w=0.55, wavelengths=None): r"""Build the modeled spectra from the optical constants. Returns ------- Spectrum, Geometric Albedo """ if wavelengths is not None: self.sample = self.sample.rebase(wavelengths) if coef is None: coef = self.scattering_coef() # albedo indicatrix rho_b = self.porosity * coef["b"] rho_f = (self.porosity * coef["f"]) + 1 - self.porosity # building albedo aux = (1 + rho_b ** 2 - rho_f ** 2) / (2 * rho_b) albedo = aux - np.sqrt(aux ** 2 - 1) # building Spectrum spec = Spectrum(self.sample.w, albedo, label="modeled_spec", unit="micron") # return albedo if albedo_w is not None: geom_alb = np.interp(albedo_w, self.sample.w, albedo) else: geom_alb = None return spec, geom_alb