blobmodel 1.1.2__tar.gz → 1.2.2__tar.gz

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 (89) hide show
  1. {blobmodel-1.1.2 → blobmodel-1.2.2}/PKG-INFO +1 -1
  2. {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel/blob_shape.py +21 -41
  3. blobmodel-1.2.2/blobmodel/blobs.py +294 -0
  4. {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel/model.py +6 -5
  5. {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel/stochasticality.py +46 -46
  6. {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel.egg-info/PKG-INFO +1 -1
  7. {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel.egg-info/SOURCES.txt +1 -0
  8. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/changing_t_drain_plot.py +1 -1
  9. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/create_logo.py +4 -4
  10. {blobmodel-1.1.2 → blobmodel-1.2.2}/examples/2_sided_exp_pulse.py +2 -2
  11. {blobmodel-1.1.2 → blobmodel-1.2.2}/examples/blob_tilting.py +4 -4
  12. {blobmodel-1.1.2 → blobmodel-1.2.2}/examples/changing_t_drain.py +0 -1
  13. blobmodel-1.2.2/examples/compare_to_analytical_sol.py +45 -0
  14. {blobmodel-1.1.2 → blobmodel-1.2.2}/examples/custom_blobfactory.py +4 -4
  15. blobmodel-1.2.2/examples/point_process.py +132 -0
  16. {blobmodel-1.1.2 → blobmodel-1.2.2}/pyproject.toml +1 -1
  17. {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_analytical.py +0 -1
  18. {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_blob.py +97 -34
  19. {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_changing_t_drain.py +0 -1
  20. {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_docs.py +12 -12
  21. {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_drain.py +4 -4
  22. {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_labels.py +4 -4
  23. {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_model.py +2 -2
  24. {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_one_dim.py +0 -1
  25. {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_pulse_shape.py +6 -6
  26. {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_show_model.py +0 -1
  27. {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_vx_or_vy=0.py +8 -8
  28. blobmodel-1.1.2/blobmodel/blobs.py +0 -451
  29. blobmodel-1.1.2/examples/compare_to_analytical_sol.py +0 -49
  30. {blobmodel-1.1.2 → blobmodel-1.2.2}/.coveragerc +0 -0
  31. {blobmodel-1.1.2 → blobmodel-1.2.2}/.github/workflows/draft-pdf.yml +0 -0
  32. {blobmodel-1.1.2 → blobmodel-1.2.2}/.github/workflows/workflow.yml +0 -0
  33. {blobmodel-1.1.2 → blobmodel-1.2.2}/.gitignore +0 -0
  34. {blobmodel-1.1.2 → blobmodel-1.2.2}/.readthedocs.yml +0 -0
  35. {blobmodel-1.1.2 → blobmodel-1.2.2}/LICENSE +0 -0
  36. {blobmodel-1.1.2 → blobmodel-1.2.2}/README.md +0 -0
  37. {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel/__init__.py +0 -0
  38. {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel/distributions.py +0 -0
  39. {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel/geometry.py +0 -0
  40. {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel/plotting.py +0 -0
  41. {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel.egg-info/dependency_links.txt +0 -0
  42. {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel.egg-info/requires.txt +0 -0
  43. {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel.egg-info/top_level.txt +0 -0
  44. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/1d_animation.gif +0 -0
  45. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/2-sided_pulse_shape.png +0 -0
  46. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/2d_animation.gif +0 -0
  47. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/alignment_false.gif +0 -0
  48. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/alignment_true.gif +0 -0
  49. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/blob_factory.rst +0 -0
  50. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/blob_labels.rst +0 -0
  51. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/blob_shapes.rst +0 -0
  52. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/blob_tilt.rst +0 -0
  53. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/blobmodel.rst +0 -0
  54. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/change_t_drain_plot.png +0 -0
  55. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/conf.py +0 -0
  56. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/contributor_guide.rst +0 -0
  57. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/drainage_time.rst +0 -0
  58. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/getting_started.rst +0 -0
  59. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/index.rst +0 -0
  60. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/install.rst +0 -0
  61. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/labels_labels.png +0 -0
  62. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/labels_n.png +0 -0
  63. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/logo.png +0 -0
  64. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/model_geometry.rst +0 -0
  65. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/modules.rst +0 -0
  66. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/one_dim.rst +0 -0
  67. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/plot_pulses.py +0 -0
  68. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/pulse_shapes.png +0 -0
  69. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/requirements.txt +0 -0
  70. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/visualize_model.rst +0 -0
  71. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/xarray_example.png +0 -0
  72. {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/y-periodicity.gif +0 -0
  73. {blobmodel-1.1.2 → blobmodel-1.2.2}/examples/1d_animation.py +0 -0
  74. {blobmodel-1.1.2 → blobmodel-1.2.2}/examples/2d_animation.py +0 -0
  75. {blobmodel-1.1.2 → blobmodel-1.2.2}/examples/analyse_output.py +0 -0
  76. {blobmodel-1.1.2 → blobmodel-1.2.2}/examples/show_labels.py +0 -0
  77. {blobmodel-1.1.2 → blobmodel-1.2.2}/examples/single_blob.py +0 -0
  78. {blobmodel-1.1.2 → blobmodel-1.2.2}/paper/paper.bib +0 -0
  79. {blobmodel-1.1.2 → blobmodel-1.2.2}/paper/paper.md +0 -0
  80. {blobmodel-1.1.2 → blobmodel-1.2.2}/readme_files/1d_blobs.gif +0 -0
  81. {blobmodel-1.1.2 → blobmodel-1.2.2}/readme_files/2d_blobs.gif +0 -0
  82. {blobmodel-1.1.2 → blobmodel-1.2.2}/readme_files/logo.png +0 -0
  83. {blobmodel-1.1.2 → blobmodel-1.2.2}/readme_files/tmp5kfvrjp5.svg +0 -0
  84. {blobmodel-1.1.2 → blobmodel-1.2.2}/readme_files/tmpp0mi4n8p.svg +0 -0
  85. {blobmodel-1.1.2 → blobmodel-1.2.2}/requirements.txt +0 -0
  86. {blobmodel-1.1.2 → blobmodel-1.2.2}/setup.cfg +0 -0
  87. {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/.gitignore +0 -0
  88. {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_stochasticality.py +0 -0
  89. {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_str.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blobmodel
3
- Version: 1.1.2
3
+ Version: 1.2.2
4
4
  Summary: Two dimensional model of propagating blobs
5
5
  Author-email: gregordecristoforo <gregor.decristoforo@gmail.com>
6
6
  License: MIT License
@@ -23,15 +23,17 @@ class AbstractBlobShape(ABC):
23
23
  """Abstract class containing the blob pulse shapes. Two-dimensional blob
24
24
  pulse shapes are written in the form:
25
25
 
26
- ``phi(theta_x, theta_y) = phi_x(theta_x) * phi_y(theta_y)``
26
+ ``phi(theta_p, theta_s) = phi_p(theta_p) * phi_s(theta_s)``
27
+
28
+ Where the p and s subindexes stand for primary and secondary directions.
27
29
  """
28
30
 
29
31
  @abstractmethod
30
- def get_blob_shape_prop(self, theta: np.ndarray, **kwargs) -> np.ndarray:
32
+ def get_blob_shape_p(self, theta: np.ndarray, **kwargs) -> np.ndarray:
31
33
  raise NotImplementedError
32
34
 
33
35
  @abstractmethod
34
- def get_blob_shape_perp(self, theta: np.ndarray, **kwargs) -> np.ndarray:
36
+ def get_blob_shape_s(self, theta: np.ndarray, **kwargs) -> np.ndarray:
35
37
  raise NotImplementedError
36
38
 
37
39
 
@@ -173,59 +175,37 @@ class BlobShapeImpl(AbstractBlobShape):
173
175
 
174
176
  def __init__(
175
177
  self,
176
- pulse_shape_prop=BlobShapeEnum.gaussian,
177
- pulse_shape_perp=BlobShapeEnum.gaussian,
178
+ pulse_shape_p=BlobShapeEnum.gaussian,
179
+ pulse_shape_s=BlobShapeEnum.gaussian,
178
180
  ):
179
181
  """Initialize the BlobShapeImpl object.
180
182
 
181
183
  Attributes
182
184
  ----------
183
- pulse_shape_prop : str, optional
184
- Type of pulse shape in the propagation direction, by default "gauss".
185
- pulse_shape_perp : str, optional
186
- Type of pulse shape perpendicular to the propagation direction, by default "gauss".
185
+ pulse_shape_p : str, optional
186
+ Type of pulse shape in the principal direction, by default "gauss".
187
+ pulse_shape_s : str, optional
188
+ Type of pulse shape in the secondary direction, by default "gauss".
187
189
  """
188
190
  if (
189
- pulse_shape_prop not in BlobShapeImpl.__GENERATORS.keys()
190
- or pulse_shape_perp not in BlobShapeImpl.__GENERATORS.keys()
191
+ pulse_shape_p not in BlobShapeImpl.__GENERATORS.keys()
192
+ or pulse_shape_s not in BlobShapeImpl.__GENERATORS.keys()
191
193
  ):
192
194
  raise NotImplementedError(
193
195
  f"{self.__class__.__name__}.blob_shape not implemented"
194
196
  )
195
- self.get_blob_shape_prop = BlobShapeImpl.__GENERATORS.get(pulse_shape_prop)
196
- self.get_blob_shape_perp = BlobShapeImpl.__GENERATORS.get(pulse_shape_perp)
197
-
198
- def get_blob_shape_prop(self, theta: np.ndarray, **kwargs) -> np.ndarray:
199
- """Compute the pulse shape in the propagation direction.
197
+ self.get_blob_shape_p = BlobShapeImpl.__GENERATORS.get(pulse_shape_p)
198
+ self.get_blob_shape_s = BlobShapeImpl.__GENERATORS.get(pulse_shape_s)
200
199
 
201
- Parameters
202
- ----------
203
- theta : np.ndarray
204
- Array of theta values.
205
- kwargs
206
- Additional keyword arguments.
207
-
208
- Returns
209
- -------
210
- np.ndarray
211
- Array representing the pulse shape in the propagation direction.
200
+ def get_blob_shape_p(self, theta: np.ndarray, **kwargs) -> np.ndarray:
201
+ """
202
+ Compute the pulse shape in the principal direction.
212
203
  """
213
204
  raise NotImplementedError
214
205
 
215
- def get_blob_shape_perp(self, theta: np.ndarray, **kwargs) -> np.ndarray:
216
- """Compute the pulse shape perpendicular to the propagation direction.
217
-
218
- Parameters
219
- ----------
220
- theta : np.ndarray
221
- Array of theta values.
222
- kwargs
223
- Additional keyword arguments.
224
-
225
- Returns
226
- -------
227
- np.ndarray
228
- Array representing the pulse shape perpendicular to the propagation direction.
206
+ def get_blob_shape_s(self, theta: np.ndarray, **kwargs) -> np.ndarray:
207
+ """
208
+ Compute the pulse shape in the secondary direction.
229
209
  """
230
210
  raise NotImplementedError
231
211
 
@@ -0,0 +1,294 @@
1
+ """This module defines a Blob class and related functions for discretizing and manipulating blobs."""
2
+
3
+ import warnings
4
+ from typing import Union, Any
5
+ from nptyping import NDArray
6
+ import numpy as np
7
+ from .blob_shape import AbstractBlobShape
8
+ import cmath
9
+
10
+
11
+ class Blob:
12
+ """
13
+ Class representing a single blob. It stores all blob parameters and discretizes the blob on a grid through
14
+ the function `discretize_blob`. The contribution of a single blob to a grid defined by `x`, `y` and `t` is given by:
15
+
16
+ .. math::
17
+ a e^{-(t-t_k)/\\tau_\\shortparallel}\\varphi\\left( \\frac{x-v(t-t_k)}{\ell_x}, \\frac{(y-y_k)-w(t-t_k)}{\ell_y} \\right)
18
+
19
+ Where:
20
+ - :math:`a` is the blob amplitude, `amplitude`.
21
+ - :math:`\ell_x` is the blob width in the principal direction, `width_p`.
22
+ - :math:`\ell_y` is the blob width in the secondary direction, `width_s`.
23
+ - :math:`v` is the horizontal blob velocity.
24
+ - :math:`w` is the vertical blob velocity.
25
+ - :math:`t_k` is the blob arriving time at the position x=0, `t_init`.
26
+ - :math:`\\tau_\\shortparallel` is the drainage time, `t_drain`.
27
+ - :math:`\\varphi` is the blob pulse shape, `blob_shape`.
28
+
29
+ Additionally, a tilt angle can be provided through `theta`.
30
+ """
31
+
32
+ def __init__(
33
+ self,
34
+ blob_id: int,
35
+ blob_shape: AbstractBlobShape,
36
+ amplitude: float,
37
+ width_p: float,
38
+ width_s: float,
39
+ v_x: float,
40
+ v_y: float,
41
+ pos_x0: float,
42
+ pos_y0: float,
43
+ t_init: float,
44
+ t_drain: Union[float, NDArray],
45
+ shape_parameters_p: Union[dict, None] = None,
46
+ shape_parameters_s: Union[dict, None] = None,
47
+ blob_alignment: bool = False,
48
+ theta: float = 0,
49
+ ) -> None:
50
+ """
51
+ Initialize a single blob.
52
+
53
+ Parameters
54
+ ----------
55
+ blob_id : int
56
+ Identifier for the blob.
57
+ blob_shape : AbstractBlobShape
58
+ Shape of the blob.
59
+ amplitude : float
60
+ Amplitude of the blob.
61
+ width_p : float
62
+ Width of the blob in the propagation direction.
63
+ width_s : float
64
+ Width of the blob in the perpendicular direction.
65
+ v_x : float
66
+ Velocity of the blob in the x-direction.
67
+ v_y : float
68
+ Velocity of the blob in the y-direction.
69
+ pos_x0 : float
70
+ Initial position of the blob in the x-direction.
71
+ pos_y0 : float
72
+ Initial position of the blob in the y-direction.
73
+ t_init : float
74
+ Initial time of the blob.
75
+ t_drain : Union[float, NDArray]
76
+ Time scale for the blob to drain.
77
+ shape_parameters_p : dict
78
+ Additional shape parameters for the propagation direction.
79
+ shape_parameters_s : dict
80
+ Additional shape parameters for the perpendicular direction.
81
+ blob_alignment : bool, optional
82
+ If blob_alignment == True, the blob shapes are rotated in the propagation direction of the blob
83
+ If blob_alignment == False, the blob shapes are independent of the propagation direction
84
+ theta : float
85
+ Blob rotation with respect to the x-axis.
86
+
87
+ it is computed according to blob_alignment. If set to a no None value,
88
+ the blob alignment flag is ignored. Important: the blob angle is measured with respect to the x axis, not with
89
+ respect to the velocity vector.
90
+
91
+ """
92
+ assert isinstance(blob_shape, AbstractBlobShape)
93
+
94
+ self.int = int
95
+ self.blob_id = blob_id
96
+ self.blob_shape = blob_shape
97
+ self.amplitude = amplitude
98
+ self.width_p = width_p # Primary width
99
+ self.width_s = width_s # Secondary width
100
+ self.v_x = v_x
101
+ self.v_y = v_y
102
+ self.pos_x0 = pos_x0
103
+ self.pos_y0 = pos_y0
104
+ self.t_init = t_init
105
+ self.t_drain = t_drain
106
+ self.shape_parameters_p = (
107
+ {} if shape_parameters_p is None else shape_parameters_p
108
+ )
109
+ self.shape_parameters_s = (
110
+ {} if shape_parameters_s is None else shape_parameters_s
111
+ )
112
+ self.blob_alignment = blob_alignment
113
+ self._theta = theta
114
+ if blob_alignment:
115
+ self._theta = cmath.phase(self.v_x + self.v_y * 1j)
116
+
117
+ def discretize_blob(
118
+ self,
119
+ x: NDArray,
120
+ y: NDArray,
121
+ t: NDArray,
122
+ Ly: float,
123
+ periodic_y: bool = False,
124
+ one_dimensional: bool = False,
125
+ ) -> NDArray:
126
+ """
127
+ Discretize blob on grid. If one_dimensional the secondary pulse shape is ignored.
128
+
129
+ Parameters
130
+ ----------
131
+ x : NDArray
132
+ Grid coordinates in the x-direction.
133
+ y : NDArray
134
+ Grid coordinates in the y-direction.
135
+ t : NDArray
136
+ Time coordinates.
137
+ Ly : float
138
+ Length of domain in the y-direction.
139
+ periodic_y : bool, optional
140
+ Flag indicating periodicity in the y-direction (default: False).
141
+ one_dimensional : bool, optional
142
+ Flag indicating a one-dimensional blob (default: False).
143
+
144
+ Notes
145
+ -----
146
+ The periodicity in the y direction is implemented by first substracting the number of full domain Ly
147
+ propagations made by the blob and by summing mirror blobs at vertical positions +-Ly.
148
+
149
+ Returns
150
+ -------
151
+ discretized_blob : NDArray
152
+ Discretized blob on a 3D array with dimensions (x, y, t).
153
+
154
+ """
155
+ # If one_dimensional, then Ly should be 0.
156
+ assert (one_dimensional and Ly == 0) or not one_dimensional
157
+
158
+ if (self.width_s > Ly / 3 or self.width_p > Ly / 3) and periodic_y:
159
+ warnings.warn(
160
+ "blob width big compared to Ly, mirrored blobs might become apparent."
161
+ )
162
+
163
+ if not periodic_y or one_dimensional:
164
+ return self._single_blob(
165
+ x, y, t, Ly, periodic_y, one_dimensional=one_dimensional
166
+ )
167
+
168
+ time = t if type(t) in [int, float] else t[0][0]
169
+ vertical_prop = self.v_y * (time - self.t_init) + self.pos_y0
170
+ number_of_y_propagations = vertical_prop // Ly
171
+
172
+ # Sum of a centered blob is two "ghost blobs" at vertical positions +-Ly.
173
+ return (
174
+ self._single_blob(
175
+ x,
176
+ y,
177
+ t,
178
+ Ly,
179
+ periodic_y,
180
+ number_of_y_propagations,
181
+ one_dimensional=one_dimensional,
182
+ )
183
+ + self._single_blob(
184
+ x,
185
+ y + Ly,
186
+ t,
187
+ Ly,
188
+ periodic_y,
189
+ number_of_y_propagations,
190
+ one_dimensional=one_dimensional,
191
+ )
192
+ + self._single_blob(
193
+ x,
194
+ y - Ly,
195
+ t,
196
+ Ly,
197
+ periodic_y,
198
+ number_of_y_propagations,
199
+ one_dimensional=one_dimensional,
200
+ )
201
+ )
202
+
203
+ def _single_blob(
204
+ self,
205
+ x: Union[int, NDArray],
206
+ y: Union[int, NDArray],
207
+ t: Union[int, NDArray],
208
+ Ly: float,
209
+ periodic_y: bool,
210
+ number_of_y_propagations: Union[NDArray, int] = 0,
211
+ one_dimensional: bool = False,
212
+ ) -> NDArray:
213
+ """
214
+ Calculate the discretized blob for a single blob instance.
215
+
216
+ Parameters
217
+ ----------
218
+ x : NDArray
219
+ x-coordinate
220
+ y : NDArray
221
+ y-coordinate
222
+ t : NDArray
223
+ Time coordinates.
224
+ Ly : float
225
+ Length of domain in the y-direction.
226
+ periodic_y : bool
227
+ Flag indicating periodicity in the y-direction.
228
+ number_of_y_propagations : NDArray, optional
229
+ Number of times the blob propagates through the domain in y-direction (default: 0).
230
+ one_dimensional : bool, optional
231
+ Flag indicating a one-dimensional blob (default: False).
232
+
233
+ Returns
234
+ -------
235
+ blob : NDArray
236
+ Discretized blob.
237
+
238
+ """
239
+ # Blob position
240
+ pos_x = self._blob_trajectory_x(t)
241
+ pos_y = self._blob_trajectory_y(t)
242
+ if periodic_y:
243
+ pos_y -= number_of_y_propagations * Ly
244
+
245
+ # Blob frame coordinates
246
+ xb = np.cos(self._theta) * (x - pos_x) + np.sin(self._theta) * (y - pos_y)
247
+ yb = -np.sin(self._theta) * (x - pos_x) + np.cos(self._theta) * (y - pos_y)
248
+
249
+ theta_x = xb / self.width_p
250
+ theta_y = yb / self.width_s
251
+ primary_axis_shape = self.blob_shape.get_blob_shape_p(
252
+ theta_x, **self.shape_parameters_p
253
+ )
254
+
255
+ secondary_axis_shape = (
256
+ 1
257
+ if one_dimensional
258
+ else self.blob_shape.get_blob_shape_s(theta_y, **self.shape_parameters_s)
259
+ )
260
+
261
+ return (
262
+ self.amplitude * self._drain(t) * primary_axis_shape * secondary_axis_shape
263
+ )
264
+
265
+ def _drain(self, t: Union[int, NDArray]) -> NDArray:
266
+ """
267
+ Calculate the drain factor for the blob.
268
+
269
+ Parameters
270
+ ----------
271
+ t : NDArray
272
+ Time coordinates.
273
+
274
+ Returns
275
+ -------
276
+ drain_factor : NDArray
277
+ Drain factor.
278
+
279
+ """
280
+ if isinstance(self.t_drain, (int, float)):
281
+ return np.exp(-(t - self.t_init) / float(self.t_drain))
282
+ return np.exp(-(t - self.t_init) / self.t_drain[np.newaxis, :, np.newaxis])
283
+
284
+ def _blob_trajectory_x(self, t: Union[int, NDArray]) -> Any:
285
+ """
286
+ Position of the blob in the x-direction at a given time t.
287
+ """
288
+ return self.pos_x0 + self.v_x * (t - self.t_init)
289
+
290
+ def _blob_trajectory_y(self, t: Union[int, NDArray]) -> Any:
291
+ """
292
+ Position of the blob in the y-direction at a given time t.
293
+ """
294
+ return self.pos_y0 + self.v_y * (t - self.t_init)
@@ -335,22 +335,23 @@ class Model:
335
335
  int(
336
336
  (
337
337
  np.abs(blob.t_init * blob.v_x)
338
- + blob.width_prop * np.log(error * np.sqrt(np.pi))
339
- + blob.pos_x
340
- - self._geometry.t[0]
338
+ + blob.width_p * np.log(error * np.sqrt(np.pi))
339
+ + blob.pos_x0
340
+ - self._geometry.t[0] * blob.v_x
341
341
  )
342
342
  / np.abs(self._geometry.dt * blob.v_x)
343
343
  ),
344
344
  )
345
+ start = np.minimum(self._geometry.t.size, start)
345
346
  # ignores t_drain when calculating stop time
346
347
  stop = np.minimum(
347
348
  self._geometry.t.size,
348
349
  int(
349
350
  (
350
351
  np.abs(blob.t_init * blob.v_x)
351
- - blob.width_prop * np.log(error * np.sqrt(np.pi))
352
+ - blob.width_p * np.log(error * np.sqrt(np.pi))
352
353
  + self._geometry.Lx
353
- - blob.pos_x
354
+ - blob.pos_x0
354
355
  )
355
356
  / np.abs(blob.v_x * self._geometry.dt)
356
357
  ),
@@ -44,19 +44,19 @@ class DefaultBlobFactory(BlobFactory):
44
44
  def __init__(
45
45
  self,
46
46
  A_dist: DistributionEnum = DistributionEnum.exp,
47
- wx_dist: DistributionEnum = DistributionEnum.deg,
48
- wy_dist: DistributionEnum = DistributionEnum.deg,
47
+ wp_dist: DistributionEnum = DistributionEnum.deg,
48
+ ws_dist: DistributionEnum = DistributionEnum.deg,
49
49
  vx_dist: DistributionEnum = DistributionEnum.deg,
50
50
  vy_dist: DistributionEnum = DistributionEnum.deg,
51
- spx_dist: DistributionEnum = DistributionEnum.deg,
52
- spy_dist: DistributionEnum = DistributionEnum.deg,
51
+ spp_dist: DistributionEnum = DistributionEnum.deg,
52
+ sps_dist: DistributionEnum = DistributionEnum.deg,
53
53
  A_parameter: float = 1.0,
54
- wx_parameter: float = 1.0,
55
- wy_parameter: float = 1.0,
54
+ wp_parameter: float = 1.0,
55
+ ws_parameter: float = 1.0,
56
56
  vx_parameter: float = 1.0,
57
57
  vy_parameter: float = 1.0,
58
- shape_param_x_parameter: float = 0.5,
59
- shape_param_y_parameter: float = 0.5,
58
+ shape_param_p_parameter: float = 0.5,
59
+ shape_param_s_parameter: float = 0.5,
60
60
  blob_alignment: bool = True,
61
61
  ) -> None:
62
62
  """
@@ -69,32 +69,32 @@ class DefaultBlobFactory(BlobFactory):
69
69
  ----------
70
70
  A_dist : Distribution, optional
71
71
  Distribution type for amplitude, by default "Distribution.exp"
72
- wx_dist : Distribution, optional
73
- Distribution type for width in the x-direction, by default "Distribution.deg"
74
- wy_dist : Distribution, optional
75
- Distribution type for width in the y-direction, by default "Distribution.deg"
72
+ wp_dist : Distribution, optional
73
+ Distribution type for width in the principal blob direction, by default "Distribution.deg"
74
+ ws_dist : Distribution, optional
75
+ Distribution type for width in the secondary blob direction, by default "Distribution.deg"
76
76
  vx_dist : Distribution, optional
77
77
  Distribution type for velocity in the x-direction, by default "Distribution.deg"
78
78
  vy_dist : Distribution, optional
79
79
  Distribution type for velocity in the y-direction, by default "Distribution.deg"
80
- spx_dist : Distribution, optional
81
- Distribution type for shape parameter in the x-direction, by default "Distribution.deg"
82
- spy_dist : Distribution, optional
83
- Distribution type for shape parameter in the y-direction, by default "Distribution.deg"
80
+ spp_dist : Distribution, optional
81
+ Distribution type for shape parameter in the principal blob direction, by default "Distribution.deg"
82
+ sps_dist : Distribution, optional
83
+ Distribution type for shape parameter in the secondary blob direction, by default "Distribution.deg"
84
84
  A_parameter : float, optional
85
85
  Free parameter for the amplitude distribution, by default 1.0
86
- wx_parameter : float, optional
87
- Free parameter for the width distribution in the x-direction, by default 1.0
88
- wy_parameter : float, optional
89
- Free parameter for the width distribution in the y-direction, by default 1.0
86
+ wp_parameter : float, optional
87
+ Free parameter for the width distribution in the principal direction, by default 1.0
88
+ ws_parameter : float, optional
89
+ Free parameter for the width distribution in the secondary direction, by default 1.0
90
90
  vx_parameter : float, optional
91
91
  Free parameter for the velocity distribution in the x-direction, by default 1.0
92
92
  vy_parameter : float, optional
93
93
  Free parameter for the velocity distribution in the y-direction, by default 1.0
94
- shape_param_x_parameter : float, optional
95
- Free parameter for the shape parameter distribution in the x-direction, by default 0.5
96
- shape_param_y_parameter : float, optional
97
- Free parameter for the shape parameter distribution in the y-direction, by default 0.5
94
+ shape_param_p_parameter : float, optional
95
+ Free parameter for the shape parameter distribution in the principal direction, by default 0.5
96
+ shape_param_s_parameter : float, optional
97
+ Free parameter for the shape parameter distribution in the secondary direction, by default 0.5
98
98
  blob_alignment : bool, optional
99
99
  If blob_aligment == True, the blob shapes are rotated in the propagation direction of the blob
100
100
  If blob_aligment == False, the blob shapes are independent of the propagation direction
@@ -112,27 +112,27 @@ class DefaultBlobFactory(BlobFactory):
112
112
 
113
113
  """
114
114
  assert isinstance(A_dist, DistributionEnum)
115
- assert isinstance(wx_dist, DistributionEnum)
116
- assert isinstance(wy_dist, DistributionEnum)
115
+ assert isinstance(wp_dist, DistributionEnum)
116
+ assert isinstance(ws_dist, DistributionEnum)
117
117
  assert isinstance(vx_dist, DistributionEnum)
118
118
  assert isinstance(vy_dist, DistributionEnum)
119
- assert isinstance(spx_dist, DistributionEnum)
120
- assert isinstance(spy_dist, DistributionEnum)
119
+ assert isinstance(spp_dist, DistributionEnum)
120
+ assert isinstance(sps_dist, DistributionEnum)
121
121
 
122
122
  self.amplitude_dist = A_dist
123
- self.width_x_dist = wx_dist
124
- self.width_y_dist = wy_dist
123
+ self.width_p_dist = wp_dist
124
+ self.width_s_dist = ws_dist
125
125
  self.velocity_x_dist = vx_dist
126
126
  self.velocity_y_dist = vy_dist
127
- self.shape_param_x_dist = spx_dist
128
- self.shape_param_y_dist = spy_dist
127
+ self.shape_param_p_dist = spp_dist
128
+ self.shape_param_s_dist = sps_dist
129
129
  self.amplitude_parameter = A_parameter
130
- self.width_x_parameter = wx_parameter
131
- self.width_y_parameter = wy_parameter
130
+ self.width_p_parameter = wp_parameter
131
+ self.width_s_parameter = ws_parameter
132
132
  self.velocity_x_parameter = vx_parameter
133
133
  self.velocity_y_parameter = vy_parameter
134
- self.shape_param_x_parameter = shape_param_x_parameter
135
- self.shape_param_y_parameter = shape_param_y_parameter
134
+ self.shape_param_p_parameter = shape_param_p_parameter
135
+ self.shape_param_s_parameter = shape_param_s_parameter
136
136
  self.blob_alignment = blob_alignment
137
137
  self.theta_setter = lambda: 0
138
138
 
@@ -179,10 +179,10 @@ class DefaultBlobFactory(BlobFactory):
179
179
  num_blobs,
180
180
  )
181
181
  wxs = self._draw_random_variables(
182
- self.width_x_dist, self.width_x_parameter, num_blobs
182
+ self.width_p_dist, self.width_p_parameter, num_blobs
183
183
  )
184
184
  wys = self._draw_random_variables(
185
- self.width_y_dist, self.width_y_parameter, num_blobs
185
+ self.width_s_dist, self.width_s_parameter, num_blobs
186
186
  )
187
187
  vxs = self._draw_random_variables(
188
188
  self.velocity_x_dist, self.velocity_x_parameter, num_blobs
@@ -191,10 +191,10 @@ class DefaultBlobFactory(BlobFactory):
191
191
  self.velocity_y_dist, self.velocity_y_parameter, num_blobs
192
192
  )
193
193
  spxs = self._draw_random_variables(
194
- self.shape_param_x_dist, self.shape_param_x_parameter, num_blobs
194
+ self.shape_param_p_dist, self.shape_param_p_parameter, num_blobs
195
195
  )
196
196
  spys = self._draw_random_variables(
197
- self.shape_param_y_dist, self.shape_param_y_parameter, num_blobs
197
+ self.shape_param_s_dist, self.shape_param_s_parameter, num_blobs
198
198
  )
199
199
  # For now, only a lambda parameter is implemented
200
200
  spxs_dict = [{"lam": s} for s in spxs]
@@ -208,16 +208,16 @@ class DefaultBlobFactory(BlobFactory):
208
208
  blob_id=i,
209
209
  blob_shape=blob_shape,
210
210
  amplitude=amps[i],
211
- width_prop=wxs[i],
212
- width_perp=wys[i],
211
+ width_p=wxs[i],
212
+ width_s=wys[i],
213
213
  v_x=vxs[i],
214
214
  v_y=vys[i],
215
- pos_x=posxs[i],
216
- pos_y=posys[i],
215
+ pos_x0=posxs[i],
216
+ pos_y0=posys[i],
217
217
  t_init=t_inits[i],
218
218
  t_drain=t_drain,
219
- prop_shape_parameters=spxs_dict[i],
220
- perp_shape_parameters=spys_dict[i],
219
+ shape_parameters_p=spxs_dict[i],
220
+ shape_parameters_s=spys_dict[i],
221
221
  blob_alignment=self.blob_alignment,
222
222
  theta=self.theta_setter(),
223
223
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blobmodel
3
- Version: 1.1.2
3
+ Version: 1.2.2
4
4
  Summary: Two dimensional model of propagating blobs
5
5
  Author-email: gregordecristoforo <gregor.decristoforo@gmail.com>
6
6
  License: MIT License
@@ -59,6 +59,7 @@ examples/blob_tilting.py
59
59
  examples/changing_t_drain.py
60
60
  examples/compare_to_analytical_sol.py
61
61
  examples/custom_blobfactory.py
62
+ examples/point_process.py
62
63
  examples/show_labels.py
63
64
  examples/single_blob.py
64
65
  paper/paper.bib
@@ -2,7 +2,7 @@ from blobmodel import Model, DefaultBlobFactory
2
2
  import matplotlib.pyplot as plt
3
3
  import numpy as np
4
4
 
5
- bf = DefaultBlobFactory(A_dist="deg", wx_dist="deg", vx_dist="deg", vy_dist="zeros")
5
+ bf = DefaultBlobFactory(A_dist="deg", wp_dist="deg", vx_dist="deg", vy_dist="zeros")
6
6
 
7
7
  t_drain = np.linspace(2, 1, 100)
8
8
 
@@ -41,12 +41,12 @@ class CustomBlobFactory(BlobFactory):
41
41
  blob_id=i,
42
42
  blob_shape=blob_shape,
43
43
  amplitude=amp[i],
44
- width_prop=width[i],
45
- width_perp=width[i],
44
+ width_p=width[i],
45
+ width_s=width[i],
46
46
  v_x=vx[i],
47
47
  v_y=vy[i],
48
- pos_x=posx[i],
49
- pos_y=posy[i],
48
+ pos_x0=posx[i],
49
+ pos_y0=posy[i],
50
50
  t_init=t_init[i],
51
51
  t_drain=t_drain,
52
52
  )
@@ -10,8 +10,8 @@ import matplotlib.pyplot as plt
10
10
  # Example of use of extra blob shape parameters with a double exponential blob shape.
11
11
 
12
12
  bf = DefaultBlobFactory(
13
- shape_param_x_parameter=0.5,
14
- shape_param_y_parameter=0.5,
13
+ shape_param_p_parameter=0.5,
14
+ shape_param_s_parameter=0.5,
15
15
  blob_alignment=True,
16
16
  )
17
17
 
@@ -23,8 +23,8 @@ bf = DefaultBlobFactory(
23
23
  A_dist=DistributionEnum.deg,
24
24
  vy_parameter=vy,
25
25
  vx_parameter=vx,
26
- wx_parameter=wx,
27
- wy_parameter=wy,
26
+ wp_parameter=wx,
27
+ ws_parameter=wy,
28
28
  blob_alignment=True, # Blobs will be aligned with their velocities
29
29
  )
30
30
 
@@ -55,8 +55,8 @@ bf = DefaultBlobFactory(
55
55
  A_dist=DistributionEnum.deg,
56
56
  vy_parameter=vy,
57
57
  vx_parameter=vx,
58
- wx_parameter=wx,
59
- wy_parameter=wy,
58
+ wp_parameter=wx,
59
+ ws_parameter=wy,
60
60
  blob_alignment=False,
61
61
  )
62
62
  # Blobs will NOT be aligned with their velocities, instead they will be tilted by an angle given by theta.