AMS-BP 0.0.3__py3-none-any.whl → 0.0.21__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.
AMS_BP/__init__.py CHANGED
@@ -10,4 +10,4 @@ Last updated: 2024-12-16
10
10
 
11
11
  """
12
12
 
13
- __version__ = "0.0.3"
13
+ __version__ = "0.0.21"
@@ -21,7 +21,9 @@ class MoleculeParameters(BaseModel):
21
21
  diffusion_coefficient: List[List[float]] = Field(
22
22
  description="Diffusion coefficients in um^2/s"
23
23
  )
24
+ diffusion_track_amount: List[List[float]]
24
25
  hurst_exponent: List[List[float]]
26
+ hurst_track_amount: List[List[float]]
25
27
  allow_transition_probability: List[bool]
26
28
  transition_matrix_time_step: List[int] = Field(description="Time step in ms")
27
29
  diffusion_transition_matrix: List[List[List[float]]]
@@ -31,7 +33,9 @@ class MoleculeParameters(BaseModel):
31
33
 
32
34
  @field_validator(
33
35
  "diffusion_coefficient",
36
+ "diffusion_track_amount",
34
37
  "hurst_exponent",
38
+ "hurst_track_amount",
35
39
  "state_probability_diffusion",
36
40
  "state_probability_hurst",
37
41
  )
@@ -324,12 +324,11 @@ class ConfigLoader:
324
324
  ):
325
325
  # Create PSFParameters instance
326
326
  parameters = PSFParameters(
327
- emission_wavelength=wavelength,
327
+ wavelength=wavelength,
328
328
  numerical_aperture=float(params_config["numerical_aperture"]),
329
329
  pixel_size=pixel_size,
330
330
  z_step=float(params_config["z_step"]) if z_step is None else z_step,
331
331
  refractive_index=float(params_config.get("refractive_index", 1.0)),
332
- pinhole_diameter=params_config.get("pinhole_diameter", None),
333
332
  )
334
333
 
335
334
  # Create PSF engine
@@ -1,4 +1,4 @@
1
- from typing import Dict, Iterator, List, Literal, Union
1
+ from typing import Iterator, List, Literal, Union
2
2
 
3
3
  from pydantic import BaseModel
4
4
 
@@ -77,7 +77,7 @@ class MetaData(BaseModel):
77
77
  PhysicalSizeXUnit: Literal["nm", "m"]
78
78
  PhysicalSizeY: float
79
79
  PhysicalSizeYUnit: Literal["nm", "m"]
80
- Channel: Dict[Literal["Name"], List[str]]
80
+ # Channel: Dict[Literal["Name"], List[str]]
81
81
 
82
82
  def __post_init__(self):
83
83
  if isinstance(self.notes, (list, str)):
@@ -20,6 +20,7 @@ Usage:
20
20
  condensate(times, time_unit) -> dict{"Position":np.ndarray, "Scale":float}
21
21
  """
22
22
 
23
+ import matplotlib.pyplot as plt
23
24
  import numpy as np
24
25
 
25
26
  from ..cells.rectangular_cell import RectangularCell
@@ -309,3 +310,47 @@ class Condensate:
309
310
  # make array of length time with the last scale
310
311
  scale = np.full(time.shape, last_scale)
311
312
  return scale
313
+
314
+ def plot_condensate(self, ax, **kwargs):
315
+ """
316
+ Plots the condensate
317
+
318
+ Parameters:
319
+ -----------
320
+ ax: plt.Axes
321
+ Axes to plot the condensate on.
322
+ **kwargs:
323
+ Keyword arguments to pass to the plot function.
324
+ """
325
+ # check if the _condensate_positions exists
326
+ if not hasattr(self, "_condensate_positions"):
327
+ # if it doesn't then we need to generate the condensate positions
328
+ self.times = np.array([self.initial_time])
329
+ self.condensate_positions = np.array([self.initial_position])
330
+ self.scale = np.array([self.initial_scale])
331
+
332
+ # plot the condensate positions
333
+ ax.plot(
334
+ self.condensate_positions[:, 0], self.condensate_positions[:, 1], **kwargs
335
+ )
336
+
337
+ # plot a circle at all the positions with the scale as the radius
338
+ for i in range(len(self.condensate_positions)):
339
+ ax.add_patch(
340
+ plt.Circle(
341
+ self.condensate_positions[i], self.scale[i], color="r", fill=False
342
+ )
343
+ )
344
+
345
+ # plot the initial position in a different colour
346
+ ax.scatter(self.initial_position[0], self.initial_position[1], color="g")
347
+ # plot the final position in a different colour
348
+ ax.scatter(
349
+ self.condensate_positions[-1][0],
350
+ self.condensate_positions[-1][1],
351
+ color="b",
352
+ )
353
+ if "save_path" in kwargs:
354
+ plt.savefig(kwargs["save_path"])
355
+ # plt.show()
356
+ return ax
@@ -1,7 +1,6 @@
1
1
  import numpy as np
2
-
2
+ from .boundary_conditions import _refecting_boundary, _absorbing_boundary
3
3
  from ...probabilityfuncs.markov_chain import MCMC_state_selection
4
- from .boundary_conditions import _absorbing_boundary, _refecting_boundary
5
4
 
6
5
  BOUNDARY_CONDITIONS = {
7
6
  "reflecting": _refecting_boundary,
@@ -162,8 +161,10 @@ class FBM_BP:
162
161
  phi = np.zeros(self.n)
163
162
  psi = np.zeros(self.n)
164
163
  # construct a gaussian noise vector
165
- gn = np.random.normal(0, 1, self.n) * np.sqrt(
166
- 2 * self._diff_a_n * (self.dt ** (2 * self._hurst_n))
164
+ gn = (
165
+ np.random.normal(0, 1, self.n)
166
+ * np.sqrt(self.dt * 2 * self._diff_a_n)
167
+ * (self.dt ** (2 * self._hurst_n))
167
168
  )
168
169
  # catch is all hurst are 0.5 then use the gaussian noise vector corresponding to the scale defined by the diffusion parameter
169
170
  if np.all(self._hurst_n == 0.5):
@@ -124,12 +124,12 @@ class Track_generator:
124
124
  rel_space_lim[i] = self.space_lim[i] - initials[i]
125
125
 
126
126
  # convert the diffusion_coefficients
127
- # diffusion_coefficient = self._convert_diffcoef_um2s_um2xms(
128
- # diffusion_coefficient
129
- # )
127
+ diffusion_coefficient = self._convert_diffcoef_um2s_um2xms(
128
+ diffusion_coefficient
129
+ )
130
130
  fbm = FBM_BP(
131
131
  n=track_length,
132
- dt=self.oversample_motion_time / 1000.0,
132
+ dt=1,
133
133
  hurst_parameters=[hurst_exponent],
134
134
  diffusion_parameters=[diffusion_coefficient],
135
135
  diffusion_parameter_transition_matrix=[1],
@@ -216,11 +216,11 @@ class Track_generator:
216
216
  for i in range(3):
217
217
  rel_space_lim[i] = self.space_lim[i] - initials[i]
218
218
  # convert the diffusion_coefficients
219
- # diffusion_parameters = self._convert_diffcoef_um2s_um2xms(diffusion_parameters)
219
+ diffusion_parameters = self._convert_diffcoef_um2s_um2xms(diffusion_parameters)
220
220
  # initialize the fbm class
221
221
  fbm = FBM_BP(
222
222
  n=track_length,
223
- dt=self.oversample_motion_time / 1000.0,
223
+ dt=1,
224
224
  hurst_parameters=hurst_parameters,
225
225
  diffusion_parameters=diffusion_parameters,
226
226
  diffusion_parameter_transition_matrix=diffusion_transition_matrix,
@@ -305,7 +305,7 @@ def create_binning_function(input_shape, binning_size, mode="sum"):
305
305
  numpy.ndarray
306
306
  Binned array
307
307
  """
308
- if array.shape != tuple(input_shape):
308
+ if array.shape != input_shape:
309
309
  raise ValueError(
310
310
  f"Input array shape {array.shape} does not match expected shape {input_shape}"
311
311
  )
@@ -96,10 +96,7 @@ class LaserParameters:
96
96
  Power in watts
97
97
  """
98
98
  if callable(self.power):
99
- power = self.power(t)
100
- if power < 0:
101
- raise ValueError("Laser Power Cannot be Negative")
102
- return power
99
+ return self.power(t)
103
100
  return self.power
104
101
 
105
102
  def get_position(self, t: float) -> Tuple[float, float, float]:
@@ -371,16 +368,15 @@ class WidefieldBeam(LaserProfile):
371
368
  Returns:
372
369
  Intensity scaling factor between 0 and 1
373
370
  """
374
- # # Use error function for smooth transition at DoF boundaries
375
- # # Scale factor determines how sharp the transition is
376
- # scale_factor = 2.0 # Adjust this to change transition sharpness
377
- #
378
- # # Normalize z by DoF and create smooth falloff
379
- # normalized_z = scale_factor * (np.abs(z)) / self.dof
380
- #
381
- # # Use sigmoid function for smooth transition
382
- # return 1 / (1 + np.exp(normalized_z))
383
- return 1.0
371
+ # Use error function for smooth transition at DoF boundaries
372
+ # Scale factor determines how sharp the transition is
373
+ scale_factor = 2.0 # Adjust this to change transition sharpness
374
+
375
+ # Normalize z by DoF and create smooth falloff
376
+ normalized_z = scale_factor * (np.abs(z) - self.dof / 2) / self.dof
377
+
378
+ # Use sigmoid function for smooth transition
379
+ return 1 / (1 + np.exp(normalized_z))
384
380
 
385
381
  def calculate_intensity(
386
382
  self,
@@ -417,7 +413,7 @@ class WidefieldBeam(LaserProfile):
417
413
  base_intensity = power / (np.pi * self.max_radius**2)
418
414
 
419
415
  # Apply radial intensity profile with smooth falloff at edges
420
- edge_width = self.max_radius * 0.00001
416
+ edge_width = self.max_radius * 0.1 # 10% of max radius
421
417
  radial_profile = 0.5 * (1 - np.tanh((r - self.max_radius) / edge_width))
422
418
  # Apply DoF-based axial intensity profile
423
419
  axial_profile = self._calculate_dof_profile(z_shifted)
@@ -426,6 +422,32 @@ class WidefieldBeam(LaserProfile):
426
422
  return base_intensity * radial_profile * axial_profile
427
423
 
428
424
 
425
+ # Example usage
426
+ if __name__ == "__main__":
427
+ # Create parameters for a typical microscope objective
428
+ params = LaserParameters(
429
+ wavelength=488, # 488 nm
430
+ power=0.001, # 1 mW
431
+ beam_width=0.25, # 250 nm
432
+ numerical_aperture=1.4,
433
+ refractive_index=1.518, # Oil immersion
434
+ )
435
+
436
+ # Create beam object
437
+ beam = GaussianBeam(params)
438
+
439
+ # Get intensity map
440
+ result = beam.get_intensity_map(
441
+ volume_size=(5, 5, 10), # 5x5x10 microns
442
+ voxel_size=0.1, # 100 nm voxels
443
+ t=0, # t=0 seconds
444
+ )
445
+
446
+ # print(f"Beam waist: {params.beam_width:.3f} µm")
447
+ # print(f"Rayleigh range: {params.rayleigh_range:.3f} µm")
448
+ # print(f"Diffraction limit: {params.diffraction_limited_width:.3f} µm")
449
+
450
+
429
451
  class HiLoBeam(LaserProfile):
430
452
  """
431
453
  Highly Inclined Laminated Optical (HiLo) illumination profile.
@@ -527,3 +549,143 @@ class HiLoBeam(LaserProfile):
527
549
  lamination_factor = np.exp(-np.abs(z_shifted) / (2 * self.axial_resolution))
528
550
 
529
551
  return intensity * lamination_factor
552
+
553
+
554
+ class ConfocalBeam(LaserProfile):
555
+ """
556
+ Confocal microscopy beam profile with point scanning and pinhole characteristics.
557
+
558
+ Implements key optical principles of confocal microscopy:
559
+ - Point scanning illumination
560
+ - Pinhole-based rejection of out-of-focus light
561
+ - Depth-resolved imaging capabilities
562
+ """
563
+
564
+ def __init__(
565
+ self,
566
+ params: LaserParameters,
567
+ pinhole_diameter: float, # Pinhole diameter in microns
568
+ scanning_mode: str = "point", # 'point' or 'line'
569
+ line_orientation: str = "horizontal", # 'horizontal' or 'vertical'
570
+ ):
571
+ """
572
+ Initialize Confocal beam profile.
573
+
574
+ Args:
575
+ params: LaserParameters for the beam
576
+ pinhole_diameter: Diameter of the detection pinhole in microns
577
+ scanning_mode: Scanning method ('point' or 'line')
578
+ line_orientation: Orientation for line scanning
579
+ """
580
+ super().__init__(params)
581
+
582
+ # Validate numerical aperture
583
+ if params.numerical_aperture is None:
584
+ raise ValueError(
585
+ "Numerical aperture must be specified for confocal microscopy"
586
+ )
587
+
588
+ # Pinhole and optical characteristics
589
+ self.pinhole_diameter = pinhole_diameter
590
+ self.scanning_mode = scanning_mode
591
+ self.line_orientation = line_orientation
592
+
593
+ # Calculate optical parameters
594
+ wavelength_microns = params.wavelength / 1000.0
595
+ na = params.numerical_aperture
596
+
597
+ # Theoretical resolution calculations
598
+ self.lateral_resolution = 0.61 * wavelength_microns / na
599
+ self.axial_resolution = 0.5 * wavelength_microns / (na**2)
600
+
601
+ # Pinhole transmission calculation
602
+ # Airy disk radius calculation
603
+ self.airy_radius = 1.22 * wavelength_microns / (2 * na)
604
+
605
+ # Transmission through pinhole
606
+ def pinhole_transmission(z):
607
+ """
608
+ Calculate pinhole transmission as a function of z-position.
609
+ Uses an error function to model smooth transition.
610
+ """
611
+ # Normalized z-position relative to focal plane
612
+ z_norm = z / self.axial_resolution
613
+
614
+ # Smooth transition function
615
+ return 0.5 * (1 + np.tanh(-z_norm))
616
+
617
+ self.pinhole_transmission = pinhole_transmission
618
+
619
+ # print("Confocal Microscopy Configuration:")
620
+ # print(f" Scanning Mode: {scanning_mode}")
621
+ # print(f" Pinhole Diameter: {pinhole_diameter:.2f} µm")
622
+ # print(f" Lateral Resolution: {self.lateral_resolution:.3f} µm")
623
+ # print(f" Axial Resolution: {self.axial_resolution:.3f} µm")
624
+ # print(f" Airy Disk Radius: {self.airy_radius:.3f} µm")
625
+
626
+ def calculate_intensity(
627
+ self,
628
+ x: np.ndarray | float,
629
+ y: np.ndarray | float,
630
+ z: np.ndarray | float,
631
+ t: float,
632
+ ) -> np.ndarray:
633
+ """
634
+ Calculate the confocal illumination intensity distribution.
635
+
636
+ Args:
637
+ x: X coordinates in microns (3D array)
638
+ y: Y coordinates in microns (3D array)
639
+ z: Z coordinates in microns (3D array)
640
+ t: Time in seconds
641
+
642
+ Returns:
643
+ 3D array of intensities in W/µm²
644
+ """
645
+ # Get time-dependent parameters
646
+ power = self.params.get_power(t)
647
+ pos = self.params.get_position(t)
648
+
649
+ # Shift coordinates based on current beam position
650
+ x_shifted = x - pos[0]
651
+ y_shifted = y - pos[1]
652
+ z_shifted = z - pos[2]
653
+
654
+ # Base beam parameters
655
+ w0 = self.params.beam_width # Beam waist
656
+ zR = self.params.rayleigh_range # Rayleigh range
657
+
658
+ # Calculate beam width at z
659
+ w_z = w0 * np.sqrt(1 + (z_shifted / zR) ** 2)
660
+
661
+ # Peak intensity calculation
662
+ I0 = 2 * power / (np.pi * w0**2)
663
+
664
+ # Scanning mode intensity modification
665
+ if self.scanning_mode == "point":
666
+ # Point scanning: standard Gaussian beam
667
+ radial_intensity = (
668
+ I0
669
+ * (w0 / w_z) ** 2
670
+ * np.exp(-2 * (x_shifted**2 + y_shifted**2) / w_z**2)
671
+ )
672
+ elif self.scanning_mode == "line":
673
+ # Line scanning: different intensity distribution
674
+ if self.line_orientation == "horizontal":
675
+ line_intensity = (
676
+ I0 * (w0 / w_z) ** 2 * np.exp(-2 * y_shifted**2 / w_z**2)
677
+ )
678
+ radial_intensity = line_intensity
679
+ else: # vertical line scanning
680
+ line_intensity = (
681
+ I0 * (w0 / w_z) ** 2 * np.exp(-2 * x_shifted**2 / w_z**2)
682
+ )
683
+ radial_intensity = line_intensity
684
+ else:
685
+ raise ValueError(f"Unknown scanning mode: {self.scanning_mode}")
686
+
687
+ # Pinhole transmission effect
688
+ pinhole_effect = self.pinhole_transmission(z_shifted)
689
+
690
+ # Final intensity calculation
691
+ return radial_intensity * pinhole_effect
@@ -5,61 +5,52 @@ from typing import Literal, Optional, Tuple
5
5
  import numpy as np
6
6
  from numpy.typing import NDArray
7
7
 
8
- AIRYFACTOR = 1.0
9
-
10
8
 
11
9
  @dataclass(frozen=True)
12
10
  class PSFParameters:
13
- """Parameters for emission PSF (Point Spread Function) at the detector.
14
-
15
-
16
- This class defines parameters that determine how light from a point source
17
- (e.g., a fluorescent molecule) diffracts through the collection optics
18
- to form a pattern at the detector.
11
+ """Parameters for PSF (Point Spread Function) generation.
19
12
 
20
13
  Attributes:
21
- emission_wavelength: Emission wavelength in nanometers
22
- numerical_aperture: Numerical aperture of the collection objective
23
- pixel_size: Size of pixels in micrometers at the detector
14
+ wavelength: Light wavelength in nanometers
15
+ numerical_aperture: Numerical aperture of the optical system
16
+ pixel_size: Size of pixels in micrometers
24
17
  z_step: Axial step size in micrometers
25
18
  refractive_index: Refractive index of the medium (default: 1.0 for air)
26
- pinhole_diameter: Diameter of the pinhole in micrometers (default: None for widefield)
27
- The pinhole spatially filters the emitted light before it reaches
28
- the detector.
29
19
  """
30
20
 
31
- emission_wavelength: float
21
+ wavelength: float
32
22
  numerical_aperture: float
33
23
  pixel_size: float
34
24
  z_step: float
35
25
  refractive_index: float = 1.0
36
- pinhole_diameter: Optional[float] = None # um
37
26
 
38
- @cached_property
39
- def wavelength_um(self) -> float:
40
- """Emission wavelength in micrometers."""
41
- return self.emission_wavelength / 1000.0
27
+ # def __post_init__(self) -> None:
28
+ # """Validate parameters after initialization."""
29
+ # if any(
30
+ # param <= 0
31
+ # for param in (
32
+ # self.wavelength,
33
+ # self.numerical_aperture,
34
+ # self.pixel_size,
35
+ # self.z_step,
36
+ # self.refractive_index,
37
+ # )
38
+ # ):
39
+ # raise ValueError("All parameters must be positive numbers")
40
+ # if self.numerical_aperture >= self.refractive_index:
41
+ # raise ValueError("Numerical aperture must be less than refractive index")
42
42
 
43
43
  @cached_property
44
- def pinhole_radius(self) -> Optional[float]:
45
- """Pinhole radius in micrometers."""
46
- return (
47
- self.pinhole_diameter / 2.0 if self.pinhole_diameter is not None else None
48
- )
44
+ def wavelength_um(self) -> float:
45
+ """Wavelength in micrometers."""
46
+ return self.wavelength / 1000.0
49
47
 
50
48
 
51
49
  class PSFEngine:
52
- """Engine for calculating emission light PSF at the detector.
53
-
54
- This class calculates how light from a point source (like a fluorescent molecule)
55
- spreads due to diffraction through the collection optics to form a pattern at
56
- the detector. For confocal systems, it can include the effect of a pinhole
57
- that spatially filters the light before detection.
50
+ """Engine for generating various microscope Point Spread Functions.
58
51
 
59
- Note: This PSF describes only the diffraction of emitted light through the
60
- collection optics. While a confocal microscope uses focused illumination to
61
- excite molecules, that illumination pattern does not affect how the emitted
62
- light diffracts to form the PSF we calculate here.
52
+ This class implements calculations for both 2D and 3D Point Spread Functions
53
+ using Gaussian approximations.
63
54
  """
64
55
 
65
56
  def __init__(self, params: PSFParameters):
@@ -88,80 +79,34 @@ class PSFEngine:
88
79
  self._norm_sigma_xy = self._sigma_xy / 2.355
89
80
  self._norm_sigma_z = self._sigma_z / 2.355
90
81
 
91
- # Generate pinhole mask if specified
92
- if self.params.pinhole_radius is not None:
93
- if self.params.pinhole_radius < AIRYFACTOR * self._sigma_xy:
94
- raise ValueError(
95
- f"Pinhole size ({self.params.pinhole_radius} um) is smaller than {AIRYFACTOR} times the Airy lobe. This will diffract the emission light in the pinhole; an ideal pinhole size for this setup is {self._sigma_xy} um."
96
- )
97
- self._pinhole_mask = self._generate_pinhole_mask()
98
- else:
99
- self._pinhole_mask = None
100
-
101
- def _generate_pinhole_mask(self) -> NDArray[np.float64]:
102
- """Generate a binary mask representing the pinhole's spatial filtering.
103
- The pinhole is centered on the grid, blocking emission light based on position
104
- in the image plane, affecting what portion of the diffracted light reaches
105
- the detector.
106
- """
107
- x, y = self._grid_xy
108
-
109
- # Calculate the grid center
110
- x_center = (x.max() + x.min()) / 2
111
- y_center = (y.max() + y.min()) / 2
112
-
113
- # Calculate radial distance from grid center
114
- r = np.sqrt((x - x_center) ** 2 + (y - y_center) ** 2)
115
-
116
- return (r <= self.params.pinhole_radius).astype(np.float64)
117
-
118
82
  @lru_cache(maxsize=128)
119
- def psf_z(self, x_val: float, y_val: float, z_val: float) -> NDArray[np.float64]:
120
- """Calculate the PSF at the detector for a point source at z_val.
121
-
122
- This represents how light from a point source at position z_val
123
- diffracts through the collection optics to form a pattern at the
124
- detector. If a pinhole is present, it spatially filters this pattern.
83
+ def psf_z(self, z_val: float) -> NDArray[np.float64]:
84
+ """Generate z=z_val Gaussian approximation of PSF.
125
85
 
126
86
  Args:
127
- x_val: x-position of the point source in micrometers
128
- y_val: y-position of the point source in micrometers
129
- z_val: Z-position of the point source in micrometers
87
+ z_val: Z-position in micrometers
130
88
 
131
89
  Returns:
132
- 2D array containing the light intensity pattern at the detector
90
+ 2D array containing the PSF at given z position
133
91
  """
134
92
  x, y = self._grid_xy
135
93
 
136
- # Calculate how light from the point source diffracts through collection optics
137
- r_squared = (
138
- (x - x_val % self.params.pixel_size) / self._norm_sigma_xy
139
- ) ** 2 + ((y - y_val % self.params.pixel_size) / self._norm_sigma_xy) ** 2
94
+ # Vectorized calculation
95
+ r_squared = (x / self._norm_sigma_xy) ** 2 + (y / self._norm_sigma_xy) ** 2
140
96
  z_term = (z_val / self._norm_sigma_z) ** 2
141
- psf_at_detector = np.exp(-0.5 * (r_squared + z_term))
142
-
143
- if self._pinhole_mask is not None:
144
- # Apply pinhole's spatial filtering
145
- return psf_at_detector * self._pinhole_mask
146
-
147
- return psf_at_detector
97
+ return np.exp(-0.5 * (r_squared + z_term))
148
98
 
149
99
  @lru_cache(maxsize=128)
150
100
  def psf_z_xy0(self, z_val: float) -> float:
151
- """Calculate the PSF intensity at the center of the detector.
152
-
153
- For a point source at z_val, this gives the intensity of light
154
- that reaches the detector center (x=y=0). This point is always
155
- within the pinhole if one is present.
101
+ """Generate z=z_val Gaussian approximation of PSF with x=y=0.
156
102
 
157
103
  Args:
158
- z_val: Z-position of the point source in micrometers
104
+ z_val: Z-position in micrometers
159
105
 
160
106
  Returns:
161
- Light intensity at detector center
107
+ PSF value at x=y=0 and given z position
162
108
  """
163
- z_term = (z_val / self._norm_sigma_z) ** 2
164
- return np.exp(-0.5 * z_term)
109
+ return np.exp(-0.5 * (z_val / self._norm_sigma_z) ** 2)
165
110
 
166
111
  @cache
167
112
  def _3d_normalization_A(
@@ -256,7 +201,7 @@ def calculate_psf_size(
256
201
  Tuple of dimensions (z,y,x) or (y,x) for the PSF calculation
257
202
  """
258
203
  # Calculate radius to capture important features (2x Airy radius)
259
- r_psf = 3 * sigma_xy
204
+ r_psf = 2 * sigma_xy
260
205
 
261
206
  # Convert to pixels and ensure odd number
262
207
  pixels_xy = int(np.ceil(r_psf / pixel_size))
@@ -168,11 +168,11 @@ class incident_photons:
168
168
  photons_n = self.transmission_photon_rate.values[i] * dt
169
169
  photons += photons_n
170
170
  psf_gen = (
171
- self.generator[i].psf_z(
172
- x_val=self.position[0],
173
- y_val=self.position[1],
174
- z_val=self.position[2],
171
+ self.generator[i].normalize_psf(
172
+ self.generator[i].psf_z(z_val=self.position[2]),
173
+ mode="sum",
175
174
  )
175
+ * self.generator[i].psf_z_xy0(z_val=self.position[2])
176
176
  * photons_n
177
177
  )
178
178
 
@@ -27,7 +27,6 @@ class StateTransitionCalculator:
27
27
  self.current_global_time = current_global_time # ms (oversample motion time)
28
28
  self.laser_intensity_generator = laser_intensity_generator
29
29
  self.fluorescent_state_history = {} # {fluorescent.state.name : [delta time (seconds), laser_intensites], ...}
30
- self.current_global_time_s = self.current_global_time * 1e-3
31
30
 
32
31
  def __call__(
33
32
  self,
@@ -49,9 +48,7 @@ class StateTransitionCalculator:
49
48
  time = 0
50
49
  transitions = self.flurophoreobj.state_history[self.current_global_time][2]
51
50
  final_state_name = transitions[0].from_state
52
- laser_intensities = self._initialize_state_hist(
53
- self.current_global_time, time + self.current_global_time_s
54
- )
51
+ laser_intensities = self._initialize_state_hist(self.current_global_time, time)
55
52
 
56
53
  while time < self.time_duration:
57
54
  stateTransitionMatrixR = [
@@ -1,14 +1,14 @@
1
1
  """
2
2
  run_cell_simulation.py
3
3
 
4
- This file contains the command-line interface (CLI) for the AMS_BP package.
4
+ This file contains the command-line interface (CLI) for the SMS_BP package, which is used for simulating single molecule localization microscopy experiments.
5
5
 
6
6
  The CLI is built using Typer and provides two main commands:
7
7
  1. 'config': Generates a sample configuration file.
8
8
  2. 'runsim': Runs the cell simulation using a provided configuration file.
9
9
 
10
10
  Main Components:
11
- - typer_app_asms_bp: The main Typer application object.
11
+ - typer_app_sms_bp: The main Typer application object.
12
12
  - cell_simulation(): Callback function that displays the version information.
13
13
  - generate_config(): Command to generate a sample configuration file.
14
14
  - run_cell_simulation(): Command to run the cell simulation using a configuration file.
@@ -37,7 +37,7 @@ from .configio.saving import save_config_frames
37
37
 
38
38
  cli_help_doc = str(
39
39
  """
40
- CLI tool to run [underline]A[/underline]dvanced [underline]M[/underline]olecule [underline]S[/underline]imulation: [underline]AMS[/underline]-BP. GitHub: [green]https://github.com/joemans3/AMS_BP[/green].
40
+ CLI tool to run [underline]A[/underline]dvanced [underline]M[/underline]olecule [underline]S[/underline]imulation: [underline]ASMS[/underline]-BP. GitHub: [green]https://github.com/joemans3/AMS_BP[/green].
41
41
  [Version: [bold]{0}[/bold]]
42
42
  """.format(__version__)
43
43
  )
AMS_BP/sim_config.toml CHANGED
@@ -23,8 +23,18 @@ diffusion_coefficient = [
23
23
  0.0,
24
24
  ],
25
25
  ] # um^2/s, size of each index (eg. len(...[0]) is the # of diffusion coefficients the system can explore.
26
-
26
+ diffusion_track_amount = [
27
+ [
28
+ 0.5,
29
+ 0.5,
30
+ ],
31
+ [
32
+ 0.5,
33
+ 0.5,
34
+ ],
35
+ ] # only usefull for initial distribution of diffusion coefficients to trajectories.
27
36
  hurst_exponent = [[0.5], [0.5]]
37
+ hurst_track_amount = [[1.0], [1.0]]
28
38
  allow_transition_probability = [true, true] # bool
29
39
  transition_matrix_time_step = [
30
40
  20,
@@ -183,6 +193,12 @@ to_state = "triplet"
183
193
  photon_dependent = false
184
194
  base_rate = 1 # 1/s
185
195
 
196
+ [fluorophores.PAmCherry.transitions.triplet_to_bleached]
197
+ from_state = "triplet"
198
+ to_state = "bleached"
199
+ photon_dependent = false
200
+ base_rate = 1 # 1/s
201
+
186
202
  [fluorophores.PAmCherry.transitions.triplet_to_dark]
187
203
  from_state = "triplet"
188
204
  to_state = "dark"
@@ -259,7 +275,6 @@ custom_path = ""
259
275
  [psf.parameters]
260
276
  numerical_aperture = 1.4 # typical range: 0.1 - 1.5
261
277
  refractive_index = 1.0 # default is air (1.0)
262
- #pinhole_diameter = 1.0 # Do not include for no pinhole else float in um units
263
278
 
264
279
  # Multiple Laser Configuration File
265
280
 
AMS_BP/sim_microscopy.py CHANGED
@@ -73,9 +73,7 @@ class VirtualMicroscope:
73
73
  def _set_laser_powers(self, laser_power: Dict[str, float]) -> None:
74
74
  if laser_power is not None:
75
75
  for laser in laser_power.keys():
76
- if isinstance(self.lasers[laser].params.power, float) and isinstance(
77
- laser_power[laser], float
78
- ):
76
+ if isinstance(self.lasers[laser].params.power, float):
79
77
  if laser_power[laser] > self.lasers[laser].params.max_power:
80
78
  raise ValueError(
81
79
  "Provided laser power for laser: {} nm, is larger than the maximum power: {}".format(
@@ -278,7 +276,7 @@ class VirtualMicroscope:
278
276
  PhysicalSizeXUnit="m",
279
277
  PhysicalSizeY=self.camera.pixel_size * 1e-6,
280
278
  PhysicalSizeYUnit="m",
281
- Channel={"Name": self.channels.names},
279
+ # Channel={"Name": self.channels.names},
282
280
  )
283
281
 
284
282
  # return frames in the format ZCTYX
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: AMS_BP
3
- Version: 0.0.3
3
+ Version: 0.0.21
4
4
  Summary: Advanced Microscopy Simulations developed for the Weber Lab by Baljyot Singh Parmar
5
5
  Project-URL: Documentation, https://joemans3.github.io/AMS_BP/
6
6
  Project-URL: Source code, https://github.com/joemans3/AMS_BP
@@ -10,6 +10,7 @@ License-File: LICENSE
10
10
  Keywords: SMS
11
11
  Requires-Python: >=3.10
12
12
  Requires-Dist: jsonschema>=4.23.0
13
+ Requires-Dist: matplotlib>=3.6.0
13
14
  Requires-Dist: numpy>=1.21.2
14
15
  Requires-Dist: pydantic>=2.9.2
15
16
  Requires-Dist: scikit-image>=0.18.3
@@ -171,5 +172,3 @@ frames, metadata = function_exp(microscope=microscope, config=config_exp)
171
172
  from AMS_BP.configio.saving import save_config_frames
172
173
  save_config_frames(metadata, frames, setup_config["base_config"].OutputParameters)
173
174
  ```
174
-
175
- > A more detailed example is provided in the jupyter notebook in the examples. For starters refer to the [VisualizingIndividualModules](examples/VisualizingIndividualModules/modules_explained.ipynb). Then head over to the [laser modulation module](examples/VisualizingIndividualModules/laser_modulation.ipynb) which will show how to change the laser power over time in the simulations. Then view an example of a complex experiment setup for [FRAP](examples/QuantitativeExperiments/FRAP_methods.ipynb) which is possible by the use of compositions of modules in this simulation library.
@@ -1,40 +1,40 @@
1
- AMS_BP/__init__.py,sha256=XXgng_5FKa65FmYXfkLAQAUD1WX_poIPUnrmCBnIWuI,326
2
- AMS_BP/run_cell_simulation.py,sha256=7InopFikjo0HfaLO2siXskBIbyCIte9avG4YXjjaWCI,7420
3
- AMS_BP/sim_config.toml,sha256=3IqOQIJYmP5g4okk15nqQiNZb3ij7Pt63HbpI-5tySw,11672
4
- AMS_BP/sim_microscopy.py,sha256=u60ApTA6MTUmqSAd7EsAxweKya_Typput8NumDq9fp8,18697
1
+ AMS_BP/__init__.py,sha256=gA3WHujyg_TRO9bQK9orLK8uNHSObJpmsLkv8GHRzLc,327
2
+ AMS_BP/run_cell_simulation.py,sha256=fPU1Tuu7hBupGtMk07j2t8QYo_TjFLMJRU9fwmAgU9c,7502
3
+ AMS_BP/sim_config.toml,sha256=FD-OcSDAgRuNIalFe0pC8sbsaSwM-9DV2DNswds2q54,11976
4
+ AMS_BP/sim_microscopy.py,sha256=7JQ6NQlgNZCvFE-FC1f9Ehh6DoJgn7bLzeqS_Mamq9Y,18619
5
5
  AMS_BP/cells/__init__.py,sha256=yWFScBC1uOGDkeC8i1m1ZBtIREcyt4JHxYa72LxbBZU,177
6
6
  AMS_BP/cells/base_cell.py,sha256=FIPB9J8F40tb53vv7C6qG-SaAFLOI8-MGIk1mmZ-gnI,1503
7
7
  AMS_BP/cells/rectangular_cell.py,sha256=5yGxvTXYvgldLXyWXpE_SD9Zx2NLerC-I2j02reHsJ0,2515
8
8
  AMS_BP/cells/rod_cell.py,sha256=jQ1kLEk74Pv2rcXPRJ6-QJJhux-mYiDSytzqlxCNWfA,3181
9
9
  AMS_BP/cells/spherical_cell.py,sha256=n3ou3tW0nCxXIwv6uLkVKHkYCfgoNn8VI6CVTLBIll0,2140
10
10
  AMS_BP/configio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- AMS_BP/configio/configmodels.py,sha256=Gd2Qdut0u5zS0IpjPwGIB3ur-b4Dfa9e8SbhotBKymc,2894
12
- AMS_BP/configio/convertconfig.py,sha256=Fg9pOCZSxmWuHnrg-5xZRvhPEK6Qc1kXqu6LL9e9QYw,34741
11
+ AMS_BP/configio/configmodels.py,sha256=Isc6THk3RAIVdjEUBW4c_OD0I122dYufgEvAcGJQ5uo,3046
12
+ AMS_BP/configio/convertconfig.py,sha256=lS7FTDheESdbpaZ0K1LcE8rkdJOKLjzIvcmWpjeebSs,34654
13
13
  AMS_BP/configio/experiments.py,sha256=HdfaSi0gPPJ_wLF87XcW5ICja19Uezx7-ygFEwNzi30,3995
14
14
  AMS_BP/configio/saving.py,sha256=596QgAadV32rzsN4B2FngGFcBWCzCDnLFN-qtQsv3bM,857
15
15
  AMS_BP/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- AMS_BP/metadata/metadata.py,sha256=YDumjc5sI3lY_UZx8f0ZhMqbG2qKQkysXwl7CY4ZtnY,2927
16
+ AMS_BP/metadata/metadata.py,sha256=_FwbSRsUhGwigY6YYffMgEx5hlXTT_vu-9AldMFPa6w,2923
17
17
  AMS_BP/motion/__init__.py,sha256=cy3W-wCRjjlN1DrTqYc-JltYwcE8SZCXMVPJ2o6q_BQ,178
18
- AMS_BP/motion/condensate_movement.py,sha256=eig4WtD7o1cvIafWMjOk6pqxyhe_IIucgLcBEoDvasU,11648
19
- AMS_BP/motion/track_gen.py,sha256=2ssg8BXxZUEufycqgziL2BOeKOInTmmjzsthfS80gfI,19540
18
+ AMS_BP/motion/condensate_movement.py,sha256=cGLHIOL7VUJ7U-JrJXetcnUF2v9SepIBznoqu6AQPxU,13252
19
+ AMS_BP/motion/track_gen.py,sha256=Z3QJLVMP1gX4SlgOXFxBg8sJhBG0Xq25ixnBoEHEAZI,19462
20
20
  AMS_BP/motion/movement/__init__.py,sha256=PqovpG4dAuFFIP9M2_kt-6egQJX3P5ig4MMWVzNaswg,278
21
21
  AMS_BP/motion/movement/boundary_conditions.py,sha256=jpfK3AEUY8btrTsu19bpUfx-jri7_HfyxqMFjMoxAVM,2200
22
- AMS_BP/motion/movement/fbm_BP.py,sha256=47d2ph4r8Izso_mBxxgQYH9xjEqj_zXUzIGpEXPEhFM,9292
22
+ AMS_BP/motion/movement/fbm_BP.py,sha256=dH-JZiAInnIaZXH1wAAo8dOIX9zafclqnZ4dOhKtnO0,9327
23
23
  AMS_BP/optics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
24
  AMS_BP/optics/camera/__init__.py,sha256=eCoDUFHcoCWgbgYdLn8EH7AULM53A3XWTXNZnV8QxeY,182
25
- AMS_BP/optics/camera/detectors.py,sha256=_815Ovo7Aj375OZh5Xim8pFuZEEcSVtSdnLRYFqb3_8,10355
25
+ AMS_BP/optics/camera/detectors.py,sha256=UJqi7owESw9nkFiQhoAe7Q1LIi_fYCzuvZLgtM3yAPk,10348
26
26
  AMS_BP/optics/camera/quantum_eff.py,sha256=ZCvJ8dJESOUbjwblsJIBcCg_b-_DNdhDlkzd7HeGMDg,2378
27
27
  AMS_BP/optics/filters/__init__.py,sha256=oYPk2_wuL4KrwbaZy3gktvO5biQUfdQLUColWhkU1lw,337
28
28
  AMS_BP/optics/filters/filters.py,sha256=-iw7eqmDO77SEqlFTv5jJNVwpA8y93TLsjy5hhsAfiI,6406
29
29
  AMS_BP/optics/filters/channels/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
30
  AMS_BP/optics/filters/channels/channelschema.py,sha256=SConyA5yVdfnI_8sgcxVC8SV7S8tGUJYPPC6jn7lglU,906
31
31
  AMS_BP/optics/lasers/__init__.py,sha256=T7dHohhyLf_pBw4TidarYHWmiwxVXGE71-Bf1aeBbuc,564
32
- AMS_BP/optics/lasers/laser_profiles.py,sha256=7mqf5VMpb0VN_veqYEdeiakr0kaOilfGzNq5mzFQuRw,17136
32
+ AMS_BP/optics/lasers/laser_profiles.py,sha256=J9czY646XcW8GzXx9Eb16mG7tQdWw4oVYveOrihZCeY,22745
33
33
  AMS_BP/optics/psf/__init__.py,sha256=ezrKPgpTeR4gTHOvF0mhF6u2zMMTd8Bgp8PGeOf11fA,121
34
- AMS_BP/optics/psf/psf_engine.py,sha256=CDtnZpUvYexIih6ssBZsd5s1RUSa5fjUxgzEVELo6CE,9684
34
+ AMS_BP/optics/psf/psf_engine.py,sha256=ejmTwAKtEpXvKeMuUFcuz6HjJbEjQa_NvkE6a3hkVzk,6769
35
35
  AMS_BP/photophysics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
- AMS_BP/photophysics/photon_physics.py,sha256=9FWBXaxuSRaSxW8bY0x1d5R5buooibZbRdYTuQcMXhQ,6624
37
- AMS_BP/photophysics/state_kinetics.py,sha256=IdZtlHCLs--iSjLwDu2IQA617qXC4la8VpqosrM-vgQ,5401
36
+ AMS_BP/photophysics/photon_physics.py,sha256=QRG_QIZ4csJ3g5qGP9Wtk7kzqm8_MUbVHfFef6cMtHQ,6671
37
+ AMS_BP/photophysics/state_kinetics.py,sha256=0cc7Vc4LtAbEdGDeg22IJmRGLsONOty4c32hXHO-TSU,5281
38
38
  AMS_BP/probabilityfuncs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
39
  AMS_BP/probabilityfuncs/markov_chain.py,sha256=LV6KGr8Lv4NIvBPJqsR0CEynssa_mPH30qLaK85GObA,4339
40
40
  AMS_BP/probabilityfuncs/probability_functions.py,sha256=j_rIxrupGBf_FKkQBh1TvEa34A44jAasaZQRg2u3FuY,11793
@@ -48,8 +48,8 @@ AMS_BP/utils/decorators.py,sha256=4qFdvzPJne0dhkhD1znPxRln1Rfr5NX8rdcCDcbATRU,62
48
48
  AMS_BP/utils/errors.py,sha256=7BOd-L4_YeKmWn3Q4EOdTnNF3Bj_exDa3eg5X0yCZrc,759
49
49
  AMS_BP/utils/maskMaker.py,sha256=2ca3n2nc8rFtUh1LurKXOJJsUmhrOpWbRnVX7fjRVvs,335
50
50
  AMS_BP/utils/util_functions.py,sha256=jI6WBh09_khdABnEoVK7SK1WRvCLHuw40f5ALyflzlc,9478
51
- ams_bp-0.0.3.dist-info/METADATA,sha256=bAzPauaepeW-ZODjT65J91m1-mmwHgJ8-LnpX8-NZ14,5868
52
- ams_bp-0.0.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
53
- ams_bp-0.0.3.dist-info/entry_points.txt,sha256=MFUK9bZWW61djfsavqopMqiVPVn4lJtt6v8qzyEFyNM,76
54
- ams_bp-0.0.3.dist-info/licenses/LICENSE,sha256=k_-JV1DQKvO0FR8WjvOisqdTl0kp6VJ7RFM3YZhao0c,1071
55
- ams_bp-0.0.3.dist-info/RECORD,,
51
+ ams_bp-0.0.21.dist-info/METADATA,sha256=RhM8C7dT2SXt-rbPFdQdo_EaiOFUx-7uC7uvic8IpvU,5316
52
+ ams_bp-0.0.21.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
53
+ ams_bp-0.0.21.dist-info/entry_points.txt,sha256=MFUK9bZWW61djfsavqopMqiVPVn4lJtt6v8qzyEFyNM,76
54
+ ams_bp-0.0.21.dist-info/licenses/LICENSE,sha256=k_-JV1DQKvO0FR8WjvOisqdTl0kp6VJ7RFM3YZhao0c,1071
55
+ ams_bp-0.0.21.dist-info/RECORD,,