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.
- {blobmodel-1.1.2 → blobmodel-1.2.2}/PKG-INFO +1 -1
- {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel/blob_shape.py +21 -41
- blobmodel-1.2.2/blobmodel/blobs.py +294 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel/model.py +6 -5
- {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel/stochasticality.py +46 -46
- {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel.egg-info/PKG-INFO +1 -1
- {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel.egg-info/SOURCES.txt +1 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/changing_t_drain_plot.py +1 -1
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/create_logo.py +4 -4
- {blobmodel-1.1.2 → blobmodel-1.2.2}/examples/2_sided_exp_pulse.py +2 -2
- {blobmodel-1.1.2 → blobmodel-1.2.2}/examples/blob_tilting.py +4 -4
- {blobmodel-1.1.2 → blobmodel-1.2.2}/examples/changing_t_drain.py +0 -1
- blobmodel-1.2.2/examples/compare_to_analytical_sol.py +45 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/examples/custom_blobfactory.py +4 -4
- blobmodel-1.2.2/examples/point_process.py +132 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/pyproject.toml +1 -1
- {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_analytical.py +0 -1
- {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_blob.py +97 -34
- {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_changing_t_drain.py +0 -1
- {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_docs.py +12 -12
- {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_drain.py +4 -4
- {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_labels.py +4 -4
- {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_model.py +2 -2
- {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_one_dim.py +0 -1
- {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_pulse_shape.py +6 -6
- {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_show_model.py +0 -1
- {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_vx_or_vy=0.py +8 -8
- blobmodel-1.1.2/blobmodel/blobs.py +0 -451
- blobmodel-1.1.2/examples/compare_to_analytical_sol.py +0 -49
- {blobmodel-1.1.2 → blobmodel-1.2.2}/.coveragerc +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/.github/workflows/draft-pdf.yml +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/.github/workflows/workflow.yml +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/.gitignore +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/.readthedocs.yml +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/LICENSE +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/README.md +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel/__init__.py +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel/distributions.py +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel/geometry.py +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel/plotting.py +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel.egg-info/dependency_links.txt +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel.egg-info/requires.txt +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/blobmodel.egg-info/top_level.txt +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/1d_animation.gif +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/2-sided_pulse_shape.png +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/2d_animation.gif +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/alignment_false.gif +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/alignment_true.gif +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/blob_factory.rst +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/blob_labels.rst +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/blob_shapes.rst +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/blob_tilt.rst +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/blobmodel.rst +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/change_t_drain_plot.png +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/conf.py +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/contributor_guide.rst +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/drainage_time.rst +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/getting_started.rst +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/index.rst +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/install.rst +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/labels_labels.png +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/labels_n.png +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/logo.png +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/model_geometry.rst +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/modules.rst +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/one_dim.rst +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/plot_pulses.py +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/pulse_shapes.png +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/requirements.txt +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/visualize_model.rst +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/xarray_example.png +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/docs/y-periodicity.gif +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/examples/1d_animation.py +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/examples/2d_animation.py +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/examples/analyse_output.py +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/examples/show_labels.py +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/examples/single_blob.py +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/paper/paper.bib +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/paper/paper.md +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/readme_files/1d_blobs.gif +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/readme_files/2d_blobs.gif +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/readme_files/logo.png +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/readme_files/tmp5kfvrjp5.svg +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/readme_files/tmpp0mi4n8p.svg +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/requirements.txt +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/setup.cfg +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/.gitignore +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_stochasticality.py +0 -0
- {blobmodel-1.1.2 → blobmodel-1.2.2}/tests/test_str.py +0 -0
|
@@ -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(
|
|
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
|
|
32
|
+
def get_blob_shape_p(self, theta: np.ndarray, **kwargs) -> np.ndarray:
|
|
31
33
|
raise NotImplementedError
|
|
32
34
|
|
|
33
35
|
@abstractmethod
|
|
34
|
-
def
|
|
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
|
-
|
|
177
|
-
|
|
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
|
-
|
|
184
|
-
Type of pulse shape in the
|
|
185
|
-
|
|
186
|
-
Type of pulse shape
|
|
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
|
-
|
|
190
|
-
or
|
|
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.
|
|
196
|
-
self.
|
|
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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
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
|
|
216
|
-
"""
|
|
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.
|
|
339
|
-
+ blob.
|
|
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.
|
|
352
|
+
- blob.width_p * np.log(error * np.sqrt(np.pi))
|
|
352
353
|
+ self._geometry.Lx
|
|
353
|
-
- blob.
|
|
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
|
-
|
|
48
|
-
|
|
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
|
-
|
|
52
|
-
|
|
51
|
+
spp_dist: DistributionEnum = DistributionEnum.deg,
|
|
52
|
+
sps_dist: DistributionEnum = DistributionEnum.deg,
|
|
53
53
|
A_parameter: float = 1.0,
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
59
|
-
|
|
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
|
-
|
|
73
|
-
Distribution type for width in the
|
|
74
|
-
|
|
75
|
-
Distribution type for width in the
|
|
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
|
-
|
|
81
|
-
Distribution type for shape parameter in the
|
|
82
|
-
|
|
83
|
-
Distribution type for shape parameter in the
|
|
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
|
-
|
|
87
|
-
Free parameter for the width distribution in the
|
|
88
|
-
|
|
89
|
-
Free parameter for the width distribution in the
|
|
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
|
-
|
|
95
|
-
Free parameter for the shape parameter distribution in the
|
|
96
|
-
|
|
97
|
-
Free parameter for the shape parameter distribution in the
|
|
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(
|
|
116
|
-
assert isinstance(
|
|
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(
|
|
120
|
-
assert isinstance(
|
|
119
|
+
assert isinstance(spp_dist, DistributionEnum)
|
|
120
|
+
assert isinstance(sps_dist, DistributionEnum)
|
|
121
121
|
|
|
122
122
|
self.amplitude_dist = A_dist
|
|
123
|
-
self.
|
|
124
|
-
self.
|
|
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.
|
|
128
|
-
self.
|
|
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.
|
|
131
|
-
self.
|
|
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.
|
|
135
|
-
self.
|
|
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.
|
|
182
|
+
self.width_p_dist, self.width_p_parameter, num_blobs
|
|
183
183
|
)
|
|
184
184
|
wys = self._draw_random_variables(
|
|
185
|
-
self.
|
|
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.
|
|
194
|
+
self.shape_param_p_dist, self.shape_param_p_parameter, num_blobs
|
|
195
195
|
)
|
|
196
196
|
spys = self._draw_random_variables(
|
|
197
|
-
self.
|
|
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
|
-
|
|
212
|
-
|
|
211
|
+
width_p=wxs[i],
|
|
212
|
+
width_s=wys[i],
|
|
213
213
|
v_x=vxs[i],
|
|
214
214
|
v_y=vys[i],
|
|
215
|
-
|
|
216
|
-
|
|
215
|
+
pos_x0=posxs[i],
|
|
216
|
+
pos_y0=posys[i],
|
|
217
217
|
t_init=t_inits[i],
|
|
218
218
|
t_drain=t_drain,
|
|
219
|
-
|
|
220
|
-
|
|
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
|
)
|
|
@@ -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",
|
|
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
|
-
|
|
45
|
-
|
|
44
|
+
width_p=width[i],
|
|
45
|
+
width_s=width[i],
|
|
46
46
|
v_x=vx[i],
|
|
47
47
|
v_y=vy[i],
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
14
|
-
|
|
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
|
-
|
|
27
|
-
|
|
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
|
-
|
|
59
|
-
|
|
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.
|