Coverage for yasfpy/particles.py: 85%

54 statements  

« prev     ^ index     » next       coverage.py v7.4.1, created at 2024-02-15 20:36 +0100

1import yasfpy.log as log 

2 

3import numpy as np 

4from scipy.spatial import ConvexHull 

5from scipy.spatial.distance import pdist 

6 

7from yasfpy.functions.material_handler import material_handler 

8 

9 

10class Particles: 

11 """The `Particles` class represents a collection of particles with various properties such as position, 

12 radius, and refractive index, and provides methods for computing unique properties and 

13 characteristics of the particles. 

14 """ 

15 

16 def __init__( 

17 self, 

18 position: np.array, 

19 r: np.array, 

20 refractive_index: np.array, 

21 refractive_index_table: list = None, 

22 shape_type: str = "sphere", 

23 ): 

24 """Initializes an object with position, radius, refractive index, refractive index table, and shape type attributes. 

25 

26 Args: 

27 position (np.array): A numpy array representing the position of the shape. 

28 r (np.array): A numpy array containing the radius values for each shape in the system. 

29 refractive_index (np.array): A numpy array representing the refractive index of the shape. 

30 It can be either a complex number or a two-column matrix. 

31 refractive_index_table (list): A list containing the refractive index values for different materials. 

32 Each element in the list represents a material, and the refractive index values for that material are stored as a complex number. 

33 shape_type (str, optional): A string specifying the type of shape for the object. 

34 Defaults to "sphere" or any other supported shape type. 

35 

36 """ 

37 self.position = position 

38 self.r = r 

39 self.refractive_index = refractive_index 

40 self.type = shape_type 

41 

42 self.log = log.scattering_logger(__name__) 

43 

44 # TODO: Keep it for now, remove later... 

45 self.refractive_index_table = refractive_index_table 

46 

47 if refractive_index_table is None: 

48 if self.refractive_index.shape[1] == 2: 

49 self.refractive_index = ( 

50 self.refractive_index[:, 0] + 1j * self.refractive_index[:, 1] 

51 ) 

52 elif self.refractive_index.shape[1] > 2: 

53 self.log.error( 

54 "Refractive index should be either complex or a two column matrix!" 

55 ) 

56 else: 

57 self.refractive_index = refractive_index.astype(int) 

58 self.refractive_index_table = refractive_index_table 

59 

60 self.number = r.shape[0] 

61 self.__setup_impl() 

62 

63 @staticmethod 

64 def generate_refractive_index_table(urls: list): 

65 """The function `generate_refractive_index_table` takes a list of URLs, retrieves data from each 

66 URL using the `material_handler` function, and returns a list of the retrieved data. 

67 

68 Args: 

69 urls (list): A list of URLs representing different materials. 

70 

71 Returns: 

72 data (list): A list of data. Each element in the list corresponds to a URL in the input list, 

73 and the data is obtained by calling the `material_handler` function on each URL. 

74 

75 """ 

76 data = [None] * len(urls) 

77 for k, url in enumerate(urls): 

78 data[k] = material_handler(url) 

79 

80 return data 

81 

82 def compute_unique_refractive_indices(self): 

83 """Computes the unique refractive indices and their indices.""" 

84 self.unique_refractive_indices, self.refractive_index_array_idx = np.unique( 

85 self.refractive_index, return_inverse=True, axis=0 

86 ) 

87 self.num_unique_refractive_indices = self.unique_refractive_indices.shape[0] 

88 

89 def compute_unique_radii(self): 

90 """The function computes the unique radii from an array and stores them in a variable.""" 

91 self.unqiue_radii, self.radius_array_idx = np.unique( 

92 self.r, return_inverse=True, axis=0 

93 ) 

94 self.num_unique_radii = self.unqiue_radii.shape[0] 

95 

96 def compute_unique_radii_index_pairs(self): 

97 """The function computes unique pairs of radii and refractive indices and stores them in different 

98 arrays. 

99 

100 """ 

101 self.unique_radius_index_pairs, self.single_unique_array_idx = np.unique( 

102 np.column_stack((self.r, self.refractive_index)), 

103 return_inverse=True, 

104 axis=0, 

105 ) 

106 self.unique_single_radius_index_pairs = np.unique( 

107 np.column_stack((self.radius_array_idx, self.refractive_index_array_idx)), 

108 axis=0, 

109 ) 

110 

111 def compute_single_unique_idx(self): 

112 """The function computes a single unique index based on the sum of pairs of values and their 

113 corresponding indices. 

114 

115 """ 

116 self.single_unique_idx = ( 

117 np.sum(self.unique_single_radius_index_pairs, axis=1) 

118 * (np.sum(self.unique_single_radius_index_pairs, axis=1) + 1) 

119 ) // 2 + self.unique_single_radius_index_pairs[:, 1] 

120 

121 # pairedArray = ( 

122 # self.radius_array_idx + self.refractive_index_array_idx * 

123 # (self.radius_array_idx + self.refractive_index_array_idx + 1) 

124 # ) // 2 + self.refractive_index_array_idx 

125 

126 # self.single_unique_idx, self.single_unique_array_idx = np.unique( 

127 # pairedArray, 

128 # return_inverse=True, 

129 # axis=0) 

130 

131 self.num_unique_pairs = self.unique_radius_index_pairs.shape[0] 

132 

133 def compute_maximal_particle_distance(self): 

134 """The function computes the maximum distance between particles using the ConvexHull algorithm.""" 

135 hull = ConvexHull(self.position) 

136 vert = self.position[hull.vertices, :] 

137 self.max_particle_distance = max(pdist(vert)) 

138 

139 def compute_volume_equivalent_area(self): 

140 """The function computes the volume equivalent area by calculating the geometric projection.""" 

141 r3 = np.power(self.r, 3) 

142 self.geometric_projection = np.pi * np.power(np.sum(r3), 2 / 3) 

143 

144 def __setup_impl(self): 

145 """The function sets up various computations related to refractive indices, radii, and particle 

146 distances. 

147 

148 """ 

149 self.compute_unique_refractive_indices() 

150 self.compute_unique_radii() 

151 self.compute_unique_radii_index_pairs() 

152 self.compute_single_unique_idx() 

153 self.compute_maximal_particle_distance() 

154 self.compute_volume_equivalent_area()