Coverage for yasfpy/particles.py: 85%
54 statements
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-15 20:36 +0100
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-15 20:36 +0100
1import yasfpy.log as log
3import numpy as np
4from scipy.spatial import ConvexHull
5from scipy.spatial.distance import pdist
7from yasfpy.functions.material_handler import material_handler
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 """
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.
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.
36 """
37 self.position = position
38 self.r = r
39 self.refractive_index = refractive_index
40 self.type = shape_type
42 self.log = log.scattering_logger(__name__)
44 # TODO: Keep it for now, remove later...
45 self.refractive_index_table = refractive_index_table
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
60 self.number = r.shape[0]
61 self.__setup_impl()
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.
68 Args:
69 urls (list): A list of URLs representing different materials.
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.
75 """
76 data = [None] * len(urls)
77 for k, url in enumerate(urls):
78 data[k] = material_handler(url)
80 return data
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]
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]
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.
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 )
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.
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]
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
126 # self.single_unique_idx, self.single_unique_array_idx = np.unique(
127 # pairedArray,
128 # return_inverse=True,
129 # axis=0)
131 self.num_unique_pairs = self.unique_radius_index_pairs.shape[0]
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))
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)
144 def __setup_impl(self):
145 """The function sets up various computations related to refractive indices, radii, and particle
146 distances.
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()