AMS-BP 0.0.231__py3-none-any.whl → 0.2.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.
@@ -0,0 +1,68 @@
1
+ import numpy as np
2
+
3
+
4
+ def generate_nup96_positions(
5
+ ring_diameter: float = 107.0,
6
+ molecule_spacing: float = 12.0,
7
+ ring_spacing: float = 50.0,
8
+ ) -> np.ndarray:
9
+ """
10
+ Generate the 3D coordinates of Nup96 proteins in the nuclear pore complex.
11
+
12
+ Parameters:
13
+ -----------
14
+ ring_diameter : float
15
+ Diameter of the main ring in nanometers (default: 107.0 nm)
16
+ molecule_spacing : float
17
+ Distance between two Nup96 molecules within same section (default: 12.0 nm)
18
+ ring_spacing : float
19
+ Distance between nuclear and cytoplasmic rings in z-direction (default: 50.0 nm)
20
+
21
+ Returns:
22
+ --------
23
+ numpy.ndarray
24
+ Array of shape (32, 3) containing x, y, z coordinates for all Nup96 proteins in um
25
+ First 32 coordinates are the main structural Nup96 (16 nuclear, 16 cytoplasmic)
26
+ """
27
+
28
+ # Initialize array to store coordinates
29
+ coordinates = np.zeros((32, 3))
30
+ ring_radius = ring_diameter / 2
31
+
32
+ # Generate positions for both main rings (nuclear and cytoplasmic)
33
+ for ring in range(2): # 0 = nuclear side, 1 = cytoplasmic side
34
+ z = ring_spacing / 2 if ring == 0 else -ring_spacing / 2
35
+
36
+ for octant in range(8):
37
+ # Calculate base angle for this octant
38
+ base_angle = octant * 2 * np.pi / 8
39
+
40
+ # Calculate the center position of this octamer
41
+ center_x = ring_radius * np.cos(base_angle)
42
+ center_y = ring_radius * np.sin(base_angle)
43
+
44
+ # Place two Nup96 molecules in each octant section
45
+ for molecule in range(2):
46
+ # Calculate the offset direction perpendicular to the radius
47
+ perpendicular_angle = (
48
+ base_angle
49
+ + np.pi / 2
50
+ + molecule_spacing / 3 * (1 if molecule == 0 else -1)
51
+ )
52
+
53
+ # Offset from center position
54
+ offset = (molecule_spacing / 3) * (-1 if molecule == 0 else 1) + (
55
+ molecule_spacing / 5
56
+ ) * (-1 if ring == 0 else 1)
57
+
58
+ # Calculate final x and y coordinates
59
+ x = center_x + offset * np.cos(perpendicular_angle)
60
+ y = center_y + offset * np.sin(perpendicular_angle)
61
+
62
+ # Store coordinates
63
+ idx = ring * 16 + octant * 2 + molecule
64
+ coordinates[idx] = [x, y, z]
65
+ # add 1 nm gitter
66
+ coordinates[idx] += np.random.normal(0, 1, 3)
67
+
68
+ return coordinates / 1000.0
@@ -15,16 +15,19 @@ Usage:
15
15
  "units_position":'um',
16
16
  "condensate_id":0,
17
17
  "initial_scale":0,
18
+ "oversample_motion_time":20,
18
19
  })
19
20
  Call the class object as follows to get the position and scale of the condensate at a given time:
20
21
  condensate(times, time_unit) -> dict{"Position":np.ndarray, "Scale":float}
21
22
  """
22
23
 
24
+ from typing import Optional
25
+
23
26
  import numpy as np
24
27
 
25
- from ..cells.rectangular_cell import RectangularCell
28
+ from ..cells import BaseCell
26
29
  from ..utils.decorators import cache
27
- from .track_gen import Track_generator as sf
30
+ from .track_gen import Track_generator
28
31
 
29
32
 
30
33
  def create_condensate_dict(
@@ -32,7 +35,7 @@ def create_condensate_dict(
32
35
  initial_scale: np.ndarray,
33
36
  diffusion_coefficient: np.ndarray,
34
37
  hurst_exponent: np.ndarray,
35
- cell: RectangularCell,
38
+ cell: BaseCell,
36
39
  **kwargs,
37
40
  ) -> dict:
38
41
  """
@@ -48,11 +51,14 @@ def create_condensate_dict(
48
51
  Array of shape (num_condensates, 2) representing the diffusion coefficients of the condensates.
49
52
  hurst_exponent : np.ndarray
50
53
  Array of shape (num_condensates, 2) representing the Hurst exponents of the condensates.
51
- cell : RectangularCell
52
- The rectangular cell that contains the condensates.
54
+ cell : BaseCell
55
+ The cell that contains the condensates.
53
56
  **kwargs : dict
54
57
  Additional arguments passed to `Condensate` class.
55
58
 
59
+ oversample_motion_time : int
60
+ smallest time unit for motion (time resolution for motion) (ms)
61
+
56
62
  Returns:
57
63
  --------
58
64
  dict
@@ -99,8 +105,10 @@ class Condensate:
99
105
  ID of the condensate.
100
106
  initial_scale: float = 0
101
107
  Initial scale of the condensate.
102
- cell: RectangularCell = None
103
- The rectangular cell that contains the condensates.
108
+ cell: BaseCell = None
109
+ The cell that contains the condensates.
110
+ oversample_motion_time: int = None
111
+ motion resolution
104
112
 
105
113
  """
106
114
 
@@ -114,7 +122,8 @@ class Condensate:
114
122
  units_position: str = "um",
115
123
  condensate_id: int = 0,
116
124
  initial_scale: float = 0,
117
- cell: RectangularCell = None,
125
+ cell: Optional[BaseCell] = None,
126
+ oversample_motion_time: Optional[int] = None,
118
127
  ):
119
128
  self.initial_position = (
120
129
  np.array(initial_position)
@@ -138,13 +147,11 @@ class Condensate:
138
147
  self.units_position = units_position
139
148
  self.condensate_id = condensate_id
140
149
  self.initial_scale = initial_scale
141
- if cell is None:
142
- cell = RectangularCell(
143
- origin=np.array([0, 0]), dimensions=np.array([0, 0, 0])
144
- )
150
+
145
151
  self.cell = cell
146
152
  self.dim = self.initial_position.shape[0]
147
153
 
154
+ self.oversample_motion_time = oversample_motion_time
148
155
  # initialize the properties of the condensate
149
156
  self._initialize_properties()
150
157
 
@@ -261,28 +268,20 @@ class Condensate:
261
268
  # find the time difference
262
269
  time_difference = time - self.times[-1]
263
270
  # make a time array starting from the last time +1 and goin to the time inclusive
264
- time_array = np.arange(self.times[-1] + 1, time + 1)
265
- # Get cell bounds for track generator
266
- min_bound, max_bound = self.cell.get_bounds()
267
- cell_space = np.array(
268
- [
269
- [min_bound[0], max_bound[0]], # x bounds
270
- [min_bound[1], max_bound[1]], # y bounds
271
- ]
271
+ time_array = np.arange(
272
+ self.times[-1] + self.oversample_motion_time,
273
+ time + self.oversample_motion_time,
272
274
  )
273
- cell_axial_range = (max_bound[2] - min_bound[2]) / 2.0
274
- track_generator = sf.Track_generator(
275
- cell_space=cell_space,
276
- cell_axial_range=cell_axial_range,
277
- cycle_count=500,
278
- exposure_time=20,
279
- interval_time=0,
280
- oversample_motion_time=20,
275
+
276
+ track_generator = Track_generator(
277
+ cell=self.cell,
278
+ total_time=time,
279
+ oversample_motion_time=self.oversample_motion_time,
281
280
  )
282
281
  track = track_generator.track_generation_no_transition(
283
282
  diffusion_coefficient=self.diffusion_coefficient,
284
283
  hurst_exponent=self.hurst_exponent,
285
- track_length=time_difference,
284
+ track_length=int(time_difference / self.oversample_motion_time),
286
285
  initials=self.condensate_positions[-1],
287
286
  start_time=self.times[-1],
288
287
  )
@@ -1,10 +1,5 @@
1
- from .fbm_BP import FBM_BP
2
- from .boundary_conditions import _refecting_boundary, _absorbing_boundary
3
- from ...probabilityfuncs.markov_chain import MCMC_state_selection
1
+ from boundedfbm import FBM_BP
4
2
 
5
3
  __all__ = [
6
4
  "FBM_BP",
7
- "_refecting_boundary",
8
- "_absorbing_boundary",
9
- "MCMC_state_selection",
10
5
  ]
@@ -1,11 +1,19 @@
1
+ """
2
+ Deprecated module due to switching to the Pyvista model for 3D cell shapes.
3
+ Removal Time: NDY (not determined yet)
4
+ """
5
+
1
6
  import numpy as np
2
7
 
3
- from ...utils.decorators import _catch_recursion_error
8
+ from ...utils.decorators import _catch_recursion_error, deprecated
4
9
 
5
10
  # Reflecting boundary condition which is a recursive function so that even if the first candidate
6
11
  # is out of the space limit, the function will keep calling itself until the candidate is within the space limit
7
12
 
8
13
 
14
+ @deprecated(
15
+ reason="Not used explicitly due to the use of Pyvista mesh objects to define shapes."
16
+ )
9
17
  @_catch_recursion_error
10
18
  def _refecting_boundary(
11
19
  fbm_store_last: float, fbm_candidate: float, space_lim: np.ndarray
@@ -47,6 +55,9 @@ def _refecting_boundary(
47
55
  # Boundary condition where the step is set at the boundary limit if the candidate is out of the space limit
48
56
 
49
57
 
58
+ @deprecated(
59
+ reason="Not used explicitly due to the use of Pyvista mesh objects to define shapes."
60
+ )
50
61
  @_catch_recursion_error
51
62
  def _absorbing_boundary(
52
63
  fbm_store_last: float, fbm_candidate: float, space_lim: np.ndarray
@@ -11,16 +11,12 @@ Classes:
11
11
  """
12
12
 
13
13
  import random
14
- from typing import Union, overload
14
+ from typing import overload
15
15
 
16
16
  import numpy as np
17
+ from boundedfbm.motion.FBM import FBM_BP
17
18
 
18
- from ..cells.rectangular_cell import RectangularCell
19
- from ..cells.rod_cell import RodCell
20
- from ..cells.spherical_cell import SphericalCell
21
- from .movement.fbm_BP import FBM_BP
22
-
23
- CellType = Union[SphericalCell, RodCell, RectangularCell]
19
+ from ..cells import BaseCell
24
20
 
25
21
 
26
22
  class Track_generator:
@@ -29,60 +25,33 @@ class Track_generator:
29
25
 
30
26
  Parameters:
31
27
  -----------
32
- cell : CellType
28
+ cell : BaseCell
33
29
  Cell object defining the space for track generation
34
- cycle_count : int
35
- The number of frames for the simulation.
36
- exposure_time : int | float
37
- Exposure time in milliseconds.
38
- interval_time : int | float
39
- Interval time between frames in milliseconds.
40
30
  oversample_motion_time : int | float
41
31
  Time for oversampling motion in milliseconds.
42
32
  """
43
33
 
44
34
  def __init__(
45
35
  self,
46
- cell: CellType,
47
- cycle_count: int,
48
- exposure_time: int | float,
49
- interval_time: int | float,
36
+ cell: BaseCell,
37
+ total_time: int | float,
50
38
  oversample_motion_time: int | float,
51
39
  ) -> None:
52
40
  self.cell = cell
53
41
  self._allowable_cell_types()
54
- min_point, max_point = self.cell.get_bounds()
55
-
56
- # Extract space limits from cell bounds
57
- self.min_x = min_point[0]
58
- self.max_x = max_point[0]
59
- self.min_y = min_point[1]
60
- self.max_y = max_point[1]
61
- self.min_z = min_point[2]
62
- self.max_z = max_point[2]
63
-
64
- self.space_lim = np.array(
65
- [
66
- [self.min_x, self.max_x],
67
- [self.min_y, self.max_y],
68
- [self.min_z, self.max_z],
69
- ]
70
- )
71
42
 
72
- self.cycle_count = cycle_count # count of frames
73
- self.exposure_time = exposure_time # in ms
74
- self.interval_time = interval_time # in ms
75
43
  self.oversample_motion_time = oversample_motion_time # in ms
76
44
  # total time in ms is the exposure time + interval time * (cycle_count) / oversample_motion_time
77
45
  # in ms
78
- self.total_time = self._convert_frame_to_time(self.cycle_count)
46
+ self.total_time = total_time
79
47
 
80
48
  def _allowable_cell_types(self):
81
49
  # only allow rectangular cells for now
82
- if not isinstance(self.cell, RectangularCell):
83
- raise ValueError(
84
- "Only rectangular cells are supported for track generation"
85
- )
50
+ # if not isinstance(self.cell, RectangularCell):
51
+ # raise ValueError(
52
+ # "Only rectangular cells are supported for track generation"
53
+ # )
54
+ pass
86
55
 
87
56
  def track_generation_no_transition(
88
57
  self,
@@ -118,42 +87,30 @@ class Track_generator:
118
87
  if np.shape(initials) == (2,):
119
88
  # change the shape to (3,)
120
89
  initials = np.array([initials[0], initials[1], 0])
121
- # subtract each element of the first dimension of self.space_lim by the first element of initials
122
- rel_space_lim = np.zeros((3, 2))
123
- for i in range(3):
124
- rel_space_lim[i] = self.space_lim[i] - initials[i]
125
-
126
90
  # convert the diffusion_coefficients
127
- diffusion_coefficient = self._convert_diffcoef_um2s_um2xms(
128
- diffusion_coefficient
129
- )
91
+ # diffusion_coefficient = self._convert_diffcoef_um2s_um2xms(
92
+ # diffusion_coefficient
93
+ # )
130
94
  fbm = FBM_BP(
131
95
  n=track_length,
132
- dt=1,
96
+ dt=self.oversample_motion_time / 1000.0,
133
97
  hurst_parameters=[hurst_exponent],
134
98
  diffusion_parameters=[diffusion_coefficient],
135
99
  diffusion_parameter_transition_matrix=[1],
136
100
  hurst_parameter_transition_matrix=[1],
137
101
  state_probability_diffusion=[1],
138
102
  state_probability_hurst=[1],
139
- space_lim=rel_space_lim[0],
103
+ cell=self.cell,
104
+ initial_position=initials,
140
105
  )
141
- x = fbm.fbm()
142
- # repeat for y,z
143
- fbm.space_lim = rel_space_lim[1]
144
- y = fbm.fbm()
145
- fbm.space_lim = rel_space_lim[2]
146
- z = fbm.fbm()
147
- # convert to format [[x1,y1,z1],[x2,y2,z2],...]
148
- xyz = np.stack((x, y, z), axis=-1)
106
+ xyz = fbm.fbm(dims=3)
149
107
  # make the times starting from the starting time
150
108
  track_times = np.arange(
151
109
  start_time,
152
110
  (track_length) * self.oversample_motion_time,
153
111
  self.oversample_motion_time,
154
112
  )
155
- # add back the initial position to the track
156
- track_xyz = xyz + initials
113
+ track_xyz = xyz
157
114
  # create the dict
158
115
  track_data = {
159
116
  "xy": track_xyz,
@@ -212,39 +169,30 @@ class Track_generator:
212
169
  # change the shape to (3,)
213
170
  initials = np.array([initials[0], initials[1], 0])
214
171
  # subtract each element of the first dimension of self.space_lim by the first element of initials
215
- rel_space_lim = np.zeros((3, 2))
216
- for i in range(3):
217
- rel_space_lim[i] = self.space_lim[i] - initials[i]
172
+
218
173
  # convert the diffusion_coefficients
219
- diffusion_parameters = self._convert_diffcoef_um2s_um2xms(diffusion_parameters)
174
+ # diffusion_parameters = self._convert_diffcoef_um2s_um2xms(diffusion_parameters)
220
175
  # initialize the fbm class
221
176
  fbm = FBM_BP(
222
177
  n=track_length,
223
- dt=1,
178
+ dt=self.oversample_motion_time / 1000.0,
224
179
  hurst_parameters=hurst_parameters,
225
180
  diffusion_parameters=diffusion_parameters,
226
181
  diffusion_parameter_transition_matrix=diffusion_transition_matrix,
227
182
  hurst_parameter_transition_matrix=hurst_transition_matrix,
228
183
  state_probability_diffusion=diffusion_state_probability,
229
184
  state_probability_hurst=hurst_state_probability,
230
- space_lim=rel_space_lim[0],
185
+ cell=self.cell,
186
+ initial_position=initials,
231
187
  )
232
- x = fbm.fbm()
233
- # repeat for y,z
234
- fbm.space_lim = rel_space_lim[1]
235
- y = fbm.fbm()
236
- fbm.space_lim = rel_space_lim[2]
237
- z = fbm.fbm()
238
- # convert to format [[x1,y1,z1],[x2,y2,z2],...]
239
- xyz = np.stack((x, y, z), axis=-1)
188
+ xyz = fbm.fbm(dims=3)
240
189
  # make the times starting from the starting time
241
190
  track_times = np.arange(
242
191
  start_time,
243
192
  track_length * self.oversample_motion_time,
244
193
  self.oversample_motion_time,
245
194
  )
246
- # add back the initial position to the track
247
- track_xyz = xyz + initials
195
+ track_xyz = xyz
248
196
  # create the dict
249
197
  track_data = {
250
198
  "xy": track_xyz,
@@ -321,7 +269,9 @@ class Track_generator:
321
269
  else:
322
270
  raise TypeError(f"Unsupported type: {type(diffusion_coefficient)}")
323
271
 
324
- def _convert_time_to_frame(self, time: int) -> int:
272
+ def _convert_time_to_frame(
273
+ self, time: int, exposure_time: int, interval_time: int
274
+ ) -> int:
325
275
  """
326
276
  Parameters:
327
277
  -----------
@@ -333,11 +283,12 @@ class Track_generator:
333
283
  int: frame number
334
284
  """
335
285
  return int(
336
- (time * self.oversample_motion_time)
337
- / (self.exposure_time + self.interval_time)
286
+ (time * self.oversample_motion_time) / (exposure_time + interval_time)
338
287
  )
339
288
 
340
- def _convert_frame_to_time(self, frame: int) -> int:
289
+ def _convert_frame_to_time(
290
+ self, frame: int, exposure_time: int, interval_time: int
291
+ ) -> int:
341
292
  """
342
293
  Parameters:
343
294
  -----------
@@ -348,7 +299,7 @@ class Track_generator:
348
299
  --------
349
300
  int: time in ms
350
301
  """
351
- return int((frame * (self.exposure_time + self.interval_time)))
302
+ return int((frame * (exposure_time + interval_time)))
352
303
 
353
304
 
354
305
  def _initialize_points_per_time(total_time: int, oversample_motion_time: int) -> dict: