| 8 | |
| 9 | |
| 10 | class Material(object): |
| 11 | def __init__(self, refractive_index: float, surface=None, components=None): |
| 12 | self.refractive_index = refractive_index |
| 13 | self.surface = Surface() if surface is None else surface |
| 14 | self.components = [] if components is None else components |
| 15 | |
| 16 | # Cache this function! |
| 17 | def total_attenutation_coefficient(self, wavelength: float) -> float: |
| 18 | coefs = [x.coefficient(wavelength) for x in self.components] |
| 19 | alpha = np.sum(coefs) |
| 20 | return alpha |
| 21 | |
| 22 | def is_absorbed(self, ray, full_distance) -> Tuple[bool, float]: |
| 23 | distance = self.penetration_depth(ray.wavelength) |
| 24 | return (distance < full_distance, distance) |
| 25 | |
| 26 | def penetration_depth(self, wavelength: float) -> float: |
| 27 | """ Monte-Carlo sampling to find penetration depth of ray due to total |
| 28 | attenuation coefficient of the material. |
| 29 | |
| 30 | Arguments |
| 31 | -------- |
| 32 | wavelength: float |
| 33 | The ray wavelength in nanometers. |
| 34 | |
| 35 | Returns |
| 36 | ------- |
| 37 | depth: float |
| 38 | The penetration depth in centimetres or `float('inf')`. |
| 39 | """ |
| 40 | alpha = self.total_attenutation_coefficient(wavelength) |
| 41 | if np.isclose(alpha, 0.0): |
| 42 | return float("inf") |
| 43 | elif not np.isfinite(alpha): |
| 44 | return 0.0 |
| 45 | # Sample exponential distribution |
| 46 | depth = -np.log(1 - np.random.uniform()) / alpha |
| 47 | return depth |
| 48 | |
| 49 | def component(self, wavelength: float) -> Component: |
| 50 | """ Monte-Carlo sampling to find which component captures the ray. |
| 51 | """ |
| 52 | coefs = np.array([x.coefficient(wavelength) for x in self.components]) |
| 53 | if np.any(coefs < 0.0): |
| 54 | raise ValueError("Must be positive.") |
| 55 | count = len(self.components) |
| 56 | bins = list(range(0, count + 1)) |
| 57 | cdf = np.cumsum(coefs) |
| 58 | pdf = cdf / max(cdf) |
| 59 | pdf = np.hstack([0, pdf[:]]) |
| 60 | pdfinv_lookup = np.interp(np.random.uniform(), pdf, bins) |
| 61 | index = int(np.floor(pdfinv_lookup)) |
| 62 | component = self.components[index] |
| 63 | return component |
no outgoing calls