FlowCyPy 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. FlowCyPy/__init__.py +13 -0
  2. FlowCyPy/_version.py +16 -0
  3. FlowCyPy/acquisition.py +652 -0
  4. FlowCyPy/classifier.py +208 -0
  5. FlowCyPy/coupling_mechanism/__init__.py +4 -0
  6. FlowCyPy/coupling_mechanism/empirical.py +47 -0
  7. FlowCyPy/coupling_mechanism/mie.py +207 -0
  8. FlowCyPy/coupling_mechanism/rayleigh.py +116 -0
  9. FlowCyPy/coupling_mechanism/uniform.py +40 -0
  10. FlowCyPy/coupling_mechanism.py +205 -0
  11. FlowCyPy/cytometer.py +314 -0
  12. FlowCyPy/detector.py +439 -0
  13. FlowCyPy/directories.py +36 -0
  14. FlowCyPy/distribution/__init__.py +16 -0
  15. FlowCyPy/distribution/base_class.py +79 -0
  16. FlowCyPy/distribution/delta.py +104 -0
  17. FlowCyPy/distribution/lognormal.py +124 -0
  18. FlowCyPy/distribution/normal.py +128 -0
  19. FlowCyPy/distribution/particle_size_distribution.py +132 -0
  20. FlowCyPy/distribution/uniform.py +117 -0
  21. FlowCyPy/distribution/weibull.py +115 -0
  22. FlowCyPy/flow_cell.py +198 -0
  23. FlowCyPy/helper.py +81 -0
  24. FlowCyPy/logger.py +136 -0
  25. FlowCyPy/noises.py +34 -0
  26. FlowCyPy/particle_count.py +127 -0
  27. FlowCyPy/peak_locator/__init__.py +4 -0
  28. FlowCyPy/peak_locator/base_class.py +163 -0
  29. FlowCyPy/peak_locator/basic.py +108 -0
  30. FlowCyPy/peak_locator/derivative.py +143 -0
  31. FlowCyPy/peak_locator/moving_average.py +166 -0
  32. FlowCyPy/physical_constant.py +19 -0
  33. FlowCyPy/plottings.py +269 -0
  34. FlowCyPy/population.py +136 -0
  35. FlowCyPy/populations_instances.py +65 -0
  36. FlowCyPy/scatterer_collection.py +306 -0
  37. FlowCyPy/signal_digitizer.py +90 -0
  38. FlowCyPy/source.py +249 -0
  39. FlowCyPy/units.py +30 -0
  40. FlowCyPy/utils.py +191 -0
  41. FlowCyPy-0.7.0.dist-info/LICENSE +21 -0
  42. FlowCyPy-0.7.0.dist-info/METADATA +252 -0
  43. FlowCyPy-0.7.0.dist-info/RECORD +45 -0
  44. FlowCyPy-0.7.0.dist-info/WHEEL +5 -0
  45. FlowCyPy-0.7.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,124 @@
1
+ from FlowCyPy.distribution.base_class import Base, config_dict
2
+ import numpy as np
3
+ from typing import Tuple
4
+ from scipy.stats import lognorm
5
+ from PyMieSim.units import Quantity
6
+ from pydantic.dataclasses import dataclass
7
+
8
+
9
+ @dataclass(config=config_dict)
10
+ class LogNormal(Base):
11
+ r"""
12
+ Represents a log-normal distribution for particle sizes.
13
+
14
+ The log-normal distribution is described by its mean and standard deviation of the logarithm of the values:
15
+
16
+ .. math::
17
+ f(x) = \frac{1}{x \sigma \sqrt{2 \pi}} \exp \left( - \frac{(\ln(x) - \mu)^2}{2 \sigma^2} \right)
18
+
19
+ where:
20
+ - :math:`\mu` is the mean of the natural logarithm of the particle sizes.
21
+ - :math:`\sigma` is the standard deviation of the logarithm of particle sizes.
22
+
23
+ Parameters
24
+ ----------
25
+ mean : Quantity
26
+ The mean particle size in meters.
27
+ std_dev : Quantity
28
+ The standard deviation of the logarithm of particle sizes.
29
+ scale_factor : float, optional
30
+ A scaling factor applied to the PDF (not the sizes).
31
+ """
32
+
33
+ mean: Quantity
34
+ std_dev: Quantity
35
+
36
+ @property
37
+ def _units(self) -> Quantity:
38
+ return self.mean.units
39
+
40
+ @property
41
+ def _mean(self) -> Quantity:
42
+ return self.mean.to(self._units)
43
+
44
+ @property
45
+ def _std_dev(self) -> Quantity:
46
+ return self.std_dev.to(self._units)
47
+
48
+ @Base.pre_generate
49
+ def generate(self, n_samples: int) -> Quantity:
50
+ """
51
+ Generates a log-normal distribution of scatterer sizes.
52
+
53
+ The generated sizes follow a log-normal distribution, where the logarithm of the sizes is normally distributed.
54
+
55
+ Parameters
56
+ ----------
57
+ n_samples : Quantity
58
+ The number of particle sizes to generate.
59
+
60
+ Returns
61
+ -------
62
+ Quantity
63
+ An array of scatterer sizes in meters.
64
+ """
65
+ return np.random.lognormal(
66
+ mean=self._mean.magnitude,
67
+ sigma=self._std_dev.magnitude,
68
+ size=n_samples
69
+ )
70
+
71
+ def _generate_default_x(self, x_min: float = 0.01, x_max: float = 5, n_samples: int = 40) -> np.ndarray:
72
+ """
73
+ Generates a range of x-values based on the log-normal distribution parameters.
74
+
75
+ Parameters
76
+ ----------
77
+ x_min : float, optional
78
+ Factor for the minimum x-value as a multiple of the mean. Default is 0.01.
79
+ x_max : float, optional
80
+ Factor for the maximum x-value as a multiple of the mean. Default is 5.
81
+ n_samples : int, optional
82
+ Number of points in the generated range. Default is 500.
83
+
84
+ Returns
85
+ -------
86
+ np.ndarray
87
+ A range of x-values with appropriate units.
88
+ """
89
+ if x_min <= 0:
90
+ raise ValueError("x_min must be greater than 0.")
91
+ if x_min >= x_max:
92
+ raise ValueError("x_min must be less than x_max.")
93
+
94
+ scale = self.mean.magnitude
95
+ x_min_value = x_min * scale
96
+ x_max_value = x_max * scale
97
+ return np.linspace(x_min_value, x_max_value, n_samples) * self._units
98
+
99
+ def get_pdf(self, x_min: float = 0.9, x_max: float = 1.1, n_samples: int = 40) -> Tuple[np.ndarray, np.ndarray]:
100
+ """
101
+ Returns the x-values and the PDF values for the log-normal distribution.
102
+
103
+ Parameters
104
+ ----------
105
+ x_min : float, optional
106
+ Factor for the minimum x-value as a multiple of the mean. Default is 0.01.
107
+ x_max : float, optional
108
+ Factor for the maximum x-value as a multiple of the mean. Default is 5.
109
+ n_samples : int, optional
110
+ Number of points in the generated range. Default is 500.
111
+
112
+ Returns
113
+ -------
114
+ Tuple[np.ndarray, np.ndarray]
115
+ The input x-values and the corresponding PDF values.
116
+ """
117
+ x = self._generate_default_x(x_min=x_min, x_max=x_max, n_samples=n_samples)
118
+
119
+ pdf = lognorm.pdf(x.magnitude, s=self._std_dev, scale=self._mean.magnitude)
120
+
121
+ return x, pdf
122
+
123
+ def __repr__(self) -> str:
124
+ return f"Log-Normal({self.mean:.3f~P}, {self.std_dev:.3f~P})"
@@ -0,0 +1,128 @@
1
+ from FlowCyPy.distribution.base_class import Base, config_dict
2
+ import numpy as np
3
+ from typing import Tuple
4
+ from scipy.stats import norm
5
+ from PyMieSim.units import Quantity
6
+ from pydantic.dataclasses import dataclass
7
+
8
+
9
+ @dataclass(config=config_dict)
10
+ class Normal(Base):
11
+ r"""
12
+ Represents a normal (Gaussian) distribution for particle sizes.
13
+
14
+ The normal distribution is described by its mean and standard deviation:
15
+
16
+ .. math::
17
+ f(x) = \frac{1}{\sqrt{2 \pi \sigma^2}} \exp \left( - \frac{(x - \mu)^2}{2 \sigma^2} \right)
18
+
19
+ where:
20
+ - :math:`\mu` is the mean of the distribution (average particle size).
21
+ - :math:`\sigma` is the standard deviation (width of the distribution).
22
+ - :math:`x` represents particle sizes.
23
+
24
+ Parameters
25
+ ----------
26
+ mean : Quantity
27
+ The mean (average) particle size in meters.
28
+ std_dev : Quantity
29
+ The standard deviation of particle sizes in meters.
30
+ """
31
+
32
+ mean: Quantity
33
+ std_dev: Quantity
34
+
35
+ @property
36
+ def _units(self) -> Quantity:
37
+ return self.mean.units
38
+
39
+ @property
40
+ def _mean(self) -> Quantity:
41
+ return self.mean.to(self._units)
42
+
43
+ @property
44
+ def _std_dev(self) -> Quantity:
45
+ return self.std_dev.to(self._units)
46
+
47
+ @Base.pre_generate
48
+ def generate(self, n_samples: int) -> np.ndarray:
49
+ """
50
+ Generates a normal distribution of scatterer sizes.
51
+
52
+ The generated sizes are based on the normal distribution's mean and standard deviation.
53
+
54
+ Parameters
55
+ ----------
56
+ n_samples : int
57
+ The number of particle sizes to generate.
58
+
59
+ Returns
60
+ -------
61
+ np.ndarray
62
+ An array of scatterer sizes in meters.
63
+ """
64
+ return np.random.normal(
65
+ loc=self._mean.magnitude,
66
+ scale=self._std_dev.magnitude,
67
+ size=n_samples
68
+ )
69
+
70
+ def _generate_default_x(self, x_min: float = -3, x_max: float = 3, n_samples: int = 20) -> np.ndarray:
71
+ """
72
+ Generates a range of x-values based on the mean and standard deviation.
73
+
74
+ Parameters
75
+ ----------
76
+ x_min : float, optional
77
+ Factor for the minimum x-value as a multiple of the standard deviation from the mean. Default is -3.
78
+ x_max : float, optional
79
+ Factor for the maximum x-value as a multiple of the standard deviation from the mean. Default is 3.
80
+ n_samples : int, optional
81
+ Number of points in the generated range. Default is 500.
82
+
83
+ Returns
84
+ -------
85
+ np.ndarray
86
+ A range of x-values with appropriate units.
87
+ """
88
+ if x_min >= x_max:
89
+ raise ValueError("x_min must be less than x_max.")
90
+
91
+ mu = self._mean.magnitude
92
+ sigma = self._std_dev.magnitude
93
+ x_min_value = mu + x_min * sigma
94
+ x_max_value = mu + x_max * sigma
95
+ return np.linspace(x_min_value, x_max_value, n_samples) * self._units
96
+
97
+ def get_pdf(self, x: np.ndarray = None, x_min: float = -3, x_max: float = 3, n_samples: int = 20) -> Tuple[np.ndarray, np.ndarray]:
98
+ """
99
+ Returns the x-values and the scaled PDF values for the normal distribution.
100
+
101
+ Parameters
102
+ ----------
103
+ x : np.ndarray, optional
104
+ The input x-values (particle sizes) over which to compute the PDF. If not provided, a range is generated.
105
+ x_min : float, optional
106
+ Factor for the minimum x-value as a multiple of the standard deviation from the mean. Default is -3.
107
+ x_max : float, optional
108
+ Factor for the maximum x-value as a multiple of the standard deviation from the mean. Default is 3.
109
+ n_samples : int, optional
110
+ Number of points in the generated range. Default is 500.
111
+
112
+ Returns
113
+ -------
114
+ Tuple[np.ndarray, np.ndarray]
115
+ The input x-values and the corresponding PDF values.
116
+ """
117
+ x = self._generate_default_x(x_min=x_min, x_max=x_max, n_samples=n_samples)
118
+
119
+ pdf = norm.pdf(
120
+ x.magnitude,
121
+ loc=self.mean.magnitude,
122
+ scale=self.std_dev.magnitude
123
+ )
124
+
125
+ return x, pdf
126
+
127
+ def __repr__(self) -> str:
128
+ return f"Normal({self.mean:.3f~P}, {self.std_dev:.3f~P})"
@@ -0,0 +1,132 @@
1
+ from FlowCyPy.distribution.base_class import Base, config_dict
2
+ import numpy as np
3
+ from typing import Tuple
4
+ from PyMieSim.units import Quantity
5
+ from pydantic.dataclasses import dataclass
6
+
7
+
8
+ @dataclass(config=config_dict)
9
+ class RosinRammler(Base):
10
+ r"""
11
+ Represents a Particle Size Distribution using the Rosin-Rammler model.
12
+
13
+ The Rosin-Rammler distribution is described by its characteristic size and
14
+ spread parameter, and is used to model particle sizes in systems such as
15
+ powders or granular materials.
16
+
17
+ The distribution function is given by:
18
+
19
+ .. math::
20
+ F(x) = 1 - \exp \left( - \left( \frac{x}{d} \right)^k \right)
21
+
22
+ where:
23
+ - :math:`x` is the particle size.
24
+ - :math:`d` is the characteristic particle size.
25
+ - :math:`k` is the spread parameter.
26
+
27
+ Parameters
28
+ ----------
29
+ characteristic_size : Quantity
30
+ The characteristic particle size in meters.
31
+ spread : float
32
+ The spread parameter (shape factor).
33
+ """
34
+
35
+ characteristic_size: Quantity
36
+ spread: float
37
+
38
+ @property
39
+ def _units(self) -> Quantity:
40
+ return self.characteristic_size.units
41
+
42
+ @Base.pre_generate
43
+ def generate(self, n_samples: int) -> Quantity:
44
+ """
45
+ Generates a particle size distribution based on the Rosin-Rammler model.
46
+
47
+ Parameters
48
+ ----------
49
+ n_samples : Quantity
50
+ The number of particle sizes to generate (dimensionless).
51
+
52
+ Returns
53
+ -------
54
+ Quantity
55
+ An array of particle sizes in meters (or other units).
56
+ """
57
+ # Convert characteristic size to main units
58
+ d = self.characteristic_size.magnitude
59
+
60
+ # Generate uniform random samples in [0, 1)
61
+ u = np.random.uniform(size=n_samples)
62
+ u = np.clip(u, 1e-10, 1 - 1e-10) # Avoid numerical issues
63
+
64
+ # Apply inverse CDF of Rosin-Rammler distribution
65
+ return d * (-np.log(1 - u))**(1 / self.spread)
66
+
67
+ def _generate_default_x(self, x_min: float, x_max: float, n_samples: int = 20) -> np.ndarray:
68
+ """
69
+ Generates a default range for x-values based on the characteristic size
70
+ and spread of the Rosin-Rammler distribution.
71
+
72
+ Parameters
73
+ ----------
74
+ x_min : float
75
+ Factor for the minimum x-value as a fraction of the characteristic size.
76
+ x_max : float
77
+ Factor for the maximum x-value as a multiple of the characteristic size.
78
+ n_samples : int, optional
79
+ Number of points in the generated range. Default is 500.
80
+
81
+ Returns
82
+ -------
83
+ np.ndarray
84
+ A default range of x-values with appropriate units.
85
+ """
86
+ if x_min <= 0:
87
+ raise ValueError("x_min must be greater than 0.")
88
+ if x_max <= x_min:
89
+ raise ValueError("x_max must be greater than x_min.")
90
+
91
+ d = self.characteristic_size.magnitude # Characteristic size in base units
92
+ x_min = d * x_min # Scale x_min by characteristic size
93
+ x_max = d * x_max # Scale x_max by characteristic size
94
+ return np.linspace(x_min, x_max, n_samples) * self._units
95
+
96
+ def get_pdf(self, x_min: float = 0.01, x_max: float = 2, n_samples: int = 20) -> Tuple[np.ndarray, np.ndarray]:
97
+ r"""
98
+ Returns the x-values and the scaled PDF values for the particle size distribution.
99
+
100
+ The PDF for the Rosin-Rammler distribution is derived from the CDF:
101
+
102
+ .. math::
103
+ f(x) = \frac{k}{d} \left( \frac{x}{d} \right)^{k-1} \exp \left( - \left( \frac{x}{d} \right)^k \right)
104
+
105
+ Parameters
106
+ ----------
107
+ x_min : float, optional
108
+ Factor for the minimum x-value as a fraction of the characteristic size. Default is 0.01.
109
+ x_max : float, optional
110
+ Factor for the maximum x-value as a multiple of the characteristic size. Default is 5.
111
+ n_samples : int, optional
112
+ Number of points in the generated range. Default is 500.
113
+
114
+ Returns
115
+ -------
116
+ Tuple[np.ndarray, np.ndarray]
117
+ The input x-values and the corresponding scaled PDF values.
118
+ """
119
+ # Generate x-values based on user-defined or default parameters
120
+ x = self._generate_default_x(x_min=x_min, x_max=x_max, n_samples=n_samples)
121
+
122
+ common_units = x.units
123
+ d = self.characteristic_size.to(common_units).magnitude
124
+ k = self.spread
125
+
126
+ # Rosin-Rammler PDF formula
127
+ pdf = (k / d) * (x.magnitude / d)**(k - 1) * np.exp(-(x.magnitude / d)**k)
128
+
129
+ return x, pdf
130
+
131
+ def __repr__(self) -> str:
132
+ return f"RR({self.characteristic_size:.3f~P}, {self.spread:.3f})"
@@ -0,0 +1,117 @@
1
+ from FlowCyPy.distribution.base_class import Base, config_dict
2
+ import numpy as np
3
+ from typing import Tuple
4
+ from scipy.stats import uniform
5
+ from PyMieSim.units import Quantity
6
+ from pydantic.dataclasses import dataclass
7
+
8
+ @dataclass(config=config_dict)
9
+ class Uniform(Base):
10
+ r"""
11
+ Represents a uniform distribution for particle sizes.
12
+
13
+ The uniform distribution assigns equal probability to all particle sizes within a specified range:
14
+
15
+ .. math::
16
+ f(x) = \frac{1}{b - a} \quad \text{for} \quad a \leq x \leq b
17
+
18
+ where:
19
+ - :math:`a` is the lower bound of the distribution.
20
+ - :math:`b` is the upper bound of the distribution.
21
+
22
+ Parameters
23
+ ----------
24
+ lower_bound : Quantity
25
+ The lower bound for particle sizes in meters.
26
+ upper_bound : Quantity
27
+ The upper bound for particle sizes in meters.
28
+ """
29
+
30
+ lower_bound: Quantity
31
+ upper_bound: Quantity
32
+
33
+ @property
34
+ def _units(self) -> Quantity:
35
+ return self.lower_bound.units
36
+
37
+ @property
38
+ def _lower_bound(self) -> Quantity:
39
+ return self.lower_bound.to(self._units)
40
+
41
+ @property
42
+ def _upper_bound(self) -> Quantity:
43
+ return self.upper_bound.to(self._units)
44
+
45
+ def __post_init__(self):
46
+ self.lower_bound = self.lower_bound.to(self.upper_bound.units)
47
+
48
+ def _generate_default_x(self, n_samples: int = 100) -> Quantity:
49
+ """
50
+ Generates a default range of x-values for the uniform distribution.
51
+
52
+ Parameters
53
+ ----------
54
+ n_points : int, optional
55
+ Number of points in the generated range. Default is 100.
56
+
57
+ Returns
58
+ -------
59
+ Quantity
60
+ A range of x-values with appropriate units.
61
+ """
62
+ x_min = self._lower_bound.magnitude / 1.1
63
+ x_max = self._upper_bound.magnitude * 1.1
64
+
65
+ return np.linspace(x_min, x_max, n_samples) * self._units
66
+
67
+ @Base.pre_generate
68
+ def generate(self, n_samples: int) -> Quantity:
69
+ """
70
+ Generates a uniform distribution of scatterer sizes.
71
+
72
+ The generated sizes are uniformly distributed between the specified `lower_bound` and `upper_bound`.
73
+
74
+ Parameters
75
+ ----------
76
+ n_samples : int
77
+ The number of particle sizes to generate.
78
+
79
+ Returns
80
+ -------
81
+ Quantity
82
+ An array of scatterer sizes in meters.
83
+ """
84
+ return np.random.uniform(
85
+ self._lower_bound.magnitude,
86
+ self._upper_bound.magnitude,
87
+ n_samples
88
+ )
89
+
90
+ def get_pdf(self, n_samples: int = 100) -> Tuple[Quantity, np.ndarray]:
91
+ """
92
+ Returns the x-values and the PDF values for the uniform distribution.
93
+
94
+ If `x` is not provided, a default range of x-values is generated.
95
+
96
+ Parameters
97
+ ----------
98
+ n_samples : int, optional
99
+ Number of points in the generated range if `x` is not provided. Default is 100.
100
+
101
+ Returns
102
+ -------
103
+ Tuple[Quantity, np.ndarray]
104
+ The input x-values and the corresponding PDF values.
105
+ """
106
+ x = self._generate_default_x(n_samples=n_samples)
107
+
108
+ pdf = uniform.pdf(
109
+ x.magnitude,
110
+ loc=self._lower_bound.magnitude,
111
+ scale=self._upper_bound.magnitude - self._lower_bound.magnitude
112
+ )
113
+
114
+ return x, pdf
115
+
116
+ def __repr__(self) -> str:
117
+ return f"Uniform(lower_bound={self.lower_bound:.3f~P}, upper_bound={self.upper_bound:.3f~P})"
@@ -0,0 +1,115 @@
1
+ from FlowCyPy.distribution.base_class import Base, config_dict
2
+ import numpy as np
3
+ from typing import Tuple
4
+ from PyMieSim.units import Quantity
5
+ from pydantic.dataclasses import dataclass
6
+
7
+
8
+ @dataclass(config=config_dict)
9
+ class Weibull(Base):
10
+ r"""
11
+ Represents a Weibull distribution for particle sizes.
12
+
13
+ The Weibull distribution is commonly used for modeling size distributions in biological systems.
14
+
15
+ Parameters
16
+ ----------
17
+ shape : Quantity
18
+ The shape parameter (k), controls the skewness of the distribution.
19
+ scale : Quantity
20
+ The scale parameter (λ), controls the spread of the distribution.
21
+ """
22
+
23
+ shape: Quantity
24
+ scale: Quantity
25
+
26
+ @property
27
+ def _units(self) -> Quantity:
28
+ return self.shape.units
29
+
30
+ @property
31
+ def _shape(self) -> Quantity:
32
+ return self.shape.to(self._units)
33
+
34
+ @property
35
+ def _scale(self) -> Quantity:
36
+ return self.scale.to(self._units)
37
+
38
+ def _generate_default_x(self, n_samples: int, x_min_factor: float, x_max_factor: float) -> Quantity:
39
+ """
40
+ Generates a default range of x-values for the Weibull distribution.
41
+
42
+ Parameters
43
+ ----------
44
+ n_samples : int, optional
45
+ Number of points in the generated range.
46
+ x_min_factor : float, optional
47
+ Factor for the minimum x-value relative to the scale parameter.
48
+ x_max_factor : float, optional
49
+ Factor for the maximum x-value relative to the scale parameter.
50
+
51
+ Returns
52
+ -------
53
+ Quantity
54
+ A range of x-values with appropriate units.
55
+ """
56
+
57
+ if x_min_factor <= 0:
58
+ raise ValueError("x_min_factor must be greater than 0.")
59
+
60
+ x_min = self.scale.magnitude * x_min_factor
61
+ x_max = self.scale.magnitude * x_max_factor
62
+ return np.linspace(x_min, x_max, n_samples) * self.scale.units
63
+
64
+ @Base.pre_generate
65
+ def generate(self, n_samples: int) -> Quantity:
66
+ """
67
+ Generates a Weibull distribution of scatterer sizes.
68
+
69
+ Parameters
70
+ ----------
71
+ n_samples : int
72
+ The number of particle sizes to generate.
73
+
74
+ Returns
75
+ -------
76
+ Quantity
77
+ An array of particle sizes in meters.
78
+ """
79
+ return np.random.weibull(
80
+ self.shape.magnitude,
81
+ size=n_samples
82
+ )
83
+
84
+ def get_pdf(self, n_samples: int = 100) -> Tuple[Quantity, np.ndarray]:
85
+ """
86
+ Returns the x-values and the PDF values for the Weibull distribution.
87
+
88
+ If `x` is not provided, a default range of x-values is generated.
89
+
90
+ Parameters
91
+ ----------
92
+ x : Quantity, optional
93
+ The input x-values (particle sizes) over which to compute the PDF. If not provided, a range is generated.
94
+ n_points : int, optional
95
+ Number of points in the generated range if `x` is not provided. Default is 100.
96
+
97
+ Returns
98
+ -------
99
+ Tuple[Quantity, np.ndarray]
100
+ The input x-values and the corresponding PDF values.
101
+ """
102
+ x = self._generate_default_x(n_samples=n_samples)
103
+
104
+ common_units = self.scale.units
105
+ scale_magnitude = self.scale.to(common_units).magnitude
106
+ shape_magnitude = self.shape.to(common_units).magnitude
107
+
108
+ pdf = (shape_magnitude / scale_magnitude) * \
109
+ ((x.to(common_units).magnitude / scale_magnitude) ** (shape_magnitude - 1)) * \
110
+ np.exp(-(x.to(common_units).magnitude / scale_magnitude) ** shape_magnitude)
111
+
112
+ return x, pdf
113
+
114
+ def __repr__(self) -> str:
115
+ return f"Weibull(shape={self.shape:.3f~P}, scale={self.scale:.3f~P})"