AMS-BP 0.0.3__tar.gz → 0.0.21__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 (108) hide show
  1. {ams_bp-0.0.3 → ams_bp-0.0.21}/.github/workflows/lint.yml +1 -0
  2. {ams_bp-0.0.3 → ams_bp-0.0.21}/PKG-INFO +2 -3
  3. {ams_bp-0.0.3 → ams_bp-0.0.21}/README.md +0 -2
  4. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/configio/configmodels.md +8 -0
  5. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/optics/psf/psf_engine.md +3 -42
  6. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/sim_config.md +0 -1
  7. {ams_bp-0.0.3 → ams_bp-0.0.21}/pyproject.toml +1 -2
  8. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/__init__.py +1 -1
  9. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/configio/configmodels.py +4 -0
  10. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/configio/convertconfig.py +1 -2
  11. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/metadata/metadata.py +2 -2
  12. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/motion/condensate_movement.py +45 -0
  13. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/motion/movement/fbm_BP.py +5 -4
  14. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/motion/track_gen.py +6 -6
  15. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/camera/detectors.py +1 -1
  16. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/lasers/laser_profiles.py +177 -15
  17. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/psf/psf_engine.py +38 -93
  18. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/photophysics/photon_physics.py +4 -4
  19. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/photophysics/state_kinetics.py +1 -4
  20. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/run_cell_simulation.py +3 -3
  21. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/sim_config.toml +17 -2
  22. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/sim_microscopy.py +2 -4
  23. {ams_bp-0.0.3 → ams_bp-0.0.21}/uv.lock +77 -1143
  24. ams_bp-0.0.3/examples/QuantitativeExperiments/FRAP_base_[[0. 0.]].txt +0 -10
  25. ams_bp-0.0.3/examples/QuantitativeExperiments/FRAP_base_[[0.04 0.04]].txt +0 -10
  26. ams_bp-0.0.3/examples/QuantitativeExperiments/FRAP_base_[[0.1 0.1]].txt +0 -10
  27. ams_bp-0.0.3/examples/QuantitativeExperiments/FRAP_base_[[0.4 0.4]].txt +0 -10
  28. ams_bp-0.0.3/examples/QuantitativeExperiments/FRAP_data_[[0. 0.]].txt +0 -10
  29. ams_bp-0.0.3/examples/QuantitativeExperiments/FRAP_data_[[0.04 0.04]].txt +0 -10
  30. ams_bp-0.0.3/examples/QuantitativeExperiments/FRAP_data_[[0.1 0.1]].txt +0 -10
  31. ams_bp-0.0.3/examples/QuantitativeExperiments/FRAP_data_[[0.4 0.4]].txt +0 -10
  32. ams_bp-0.0.3/examples/QuantitativeExperiments/FRAP_methods.ipynb +0 -1025
  33. ams_bp-0.0.3/examples/VisualizingIndividualModules/laser_modulation.ipynb +0 -1094
  34. ams_bp-0.0.3/examples/VisualizingIndividualModules/modules_explained.ipynb +0 -1466
  35. {ams_bp-0.0.3 → ams_bp-0.0.21}/.github/workflows/pages.yml +0 -0
  36. {ams_bp-0.0.3 → ams_bp-0.0.21}/.github/workflows/publish_pypi.yml +0 -0
  37. {ams_bp-0.0.3 → ams_bp-0.0.21}/.gitignore +0 -0
  38. {ams_bp-0.0.3 → ams_bp-0.0.21}/LICENSE +0 -0
  39. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/cells/base_cell.md +0 -0
  40. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/cells/rectangular_cell.md +0 -0
  41. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/cells/rod_cell.md +0 -0
  42. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/cells/spherical_cell.md +0 -0
  43. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/configio/convertconfig.md +0 -0
  44. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/configio/experiments.md +0 -0
  45. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/configio/saving.md +0 -0
  46. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/metadata/metadata.md +0 -0
  47. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/motion/condensate_movement.md +0 -0
  48. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/motion/movement/boundary_conditions.md +0 -0
  49. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/motion/movement/fbm_BP.md +0 -0
  50. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/motion/track_gen.md +0 -0
  51. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/optics/camera/detectors.md +0 -0
  52. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/optics/camera/quantum_eff.md +0 -0
  53. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/optics/filters/channels/channelschema.md +0 -0
  54. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/optics/filters/filters.md +0 -0
  55. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/optics/lasers/laser_profiles.md +0 -0
  56. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/photophysics/photon_physics.md +0 -0
  57. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/photophysics/state_kinetics.md +0 -0
  58. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/probabilityfuncs/markov_chain.md +0 -0
  59. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/probabilityfuncs/probability_functions.md +0 -0
  60. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/run_cell_simulation.md +0 -0
  61. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/sample/flurophore/flurophore_schema.md +0 -0
  62. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/sample/sim_sampleplane.md +0 -0
  63. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/sim_microscopy.md +0 -0
  64. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/utils/constants.md +0 -0
  65. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/utils/errors.md +0 -0
  66. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/utils/util_functions.md +0 -0
  67. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/assets/icons/Cells-actin-like-a-tree-Jamie-Whitelaw-1.png +0 -0
  68. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/assets/icons/drawing.pdf +0 -0
  69. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/assets/icons/drawing.png +0 -0
  70. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/assets/icons/drawing.svg +0 -0
  71. {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/index.md +0 -0
  72. {ams_bp-0.0.3 → ams_bp-0.0.21}/mkdocs.yml +0 -0
  73. {ams_bp-0.0.3 → ams_bp-0.0.21}/pytest.ini +0 -0
  74. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/cells/__init__.py +0 -0
  75. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/cells/base_cell.py +0 -0
  76. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/cells/rectangular_cell.py +0 -0
  77. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/cells/rod_cell.py +0 -0
  78. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/cells/spherical_cell.py +0 -0
  79. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/configio/__init__.py +0 -0
  80. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/configio/experiments.py +0 -0
  81. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/configio/saving.py +0 -0
  82. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/metadata/__init__.py +0 -0
  83. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/motion/__init__.py +0 -0
  84. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/motion/movement/__init__.py +0 -0
  85. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/motion/movement/boundary_conditions.py +0 -0
  86. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/__init__.py +0 -0
  87. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/camera/__init__.py +0 -0
  88. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/camera/quantum_eff.py +0 -0
  89. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/filters/__init__.py +0 -0
  90. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/filters/channels/__init__.py +0 -0
  91. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/filters/channels/channelschema.py +0 -0
  92. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/filters/filters.py +0 -0
  93. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/lasers/__init__.py +0 -0
  94. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/psf/__init__.py +0 -0
  95. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/photophysics/__init__.py +0 -0
  96. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/probabilityfuncs/__init__.py +0 -0
  97. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/probabilityfuncs/markov_chain.py +0 -0
  98. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/probabilityfuncs/probability_functions.py +0 -0
  99. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/sample/__init__.py +0 -0
  100. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/sample/flurophores/__init__.py +0 -0
  101. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/sample/flurophores/flurophore_schema.py +0 -0
  102. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/sample/sim_sampleplane.py +0 -0
  103. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/utils/__init__.py +0 -0
  104. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/utils/constants.py +0 -0
  105. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/utils/decorators.py +0 -0
  106. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/utils/errors.py +0 -0
  107. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/utils/maskMaker.py +0 -0
  108. {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/utils/util_functions.py +0 -0
@@ -21,5 +21,6 @@ jobs:
21
21
  # Update output format to enable automatic inline annotations.
22
22
  - name: Run Ruff
23
23
  run: |
24
+ ruff check --fix
24
25
  ruff format
25
26
  ruff format --check --diff
@@ -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.
@@ -151,5 +151,3 @@ frames, metadata = function_exp(microscope=microscope, config=config_exp)
151
151
  from AMS_BP.configio.saving import save_config_frames
152
152
  save_config_frames(metadata, frames, setup_config["base_config"].OutputParameters)
153
153
  ```
154
-
155
- > 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.
@@ -41,10 +41,18 @@ class MoleculeParameters(BaseModel)
41
41
  - Description: Diffusion coefficients in μm²/s
42
42
  - 2D array automatically converted to numpy array
43
43
 
44
+ - `diffusion_track_amount: List[List[float]]`
45
+ - Description: Amount of diffusive tracking for each state
46
+ - 2D array automatically converted to numpy array
47
+
44
48
  - `hurst_exponent: List[List[float]]`
45
49
  - Description: Hurst exponents for fractional Brownian motion
46
50
  - 2D array automatically converted to numpy array
47
51
 
52
+ - `hurst_track_amount: List[List[float]]`
53
+ - Description: Amount of Hurst tracking for each state
54
+ - 2D array automatically converted to numpy array
55
+
48
56
  - `allow_transition_probability: List[bool]`
49
57
  - Description: Whether to allow state transitions
50
58
 
@@ -12,35 +12,14 @@ This module provides functionality for generating Point Spread Functions (PSFs)
12
12
  - [_calculate_sigma_z](#_calculate_sigma_z)
13
13
  - [_generate_grid](#_generate_grid)
14
14
  - [calculate_psf_size](#calculate_psf_size)
15
- - [_generate_pinhole_mask](#_generate_pinhole_mask)
16
15
 
17
16
  ---
18
17
 
19
18
  ## Classes
20
19
 
21
20
  ### `PSFParameters`
22
- #### Description
23
- This is a frozen dataclass (enum-ish?) with the following parameters / cached properties
24
- ```python
25
- emission_wavelength: float
26
- numerical_aperture: float
27
- pixel_size: float
28
- z_step: float
29
- refractive_index: float = 1.0
30
- pinhole_diameter: Optional[float] = None # um
31
-
32
- @cached_property
33
- def wavelength_um(self) -> float:
34
- """Emission wavelength in micrometers."""
35
- return self.emission_wavelength / 1000.0
36
- @cached_property
37
- def pinhole_radius(self) -> Optional[float]:
38
- """Pinhole radius in micrometers."""
39
- return (
40
- self.pinhole_diameter / 2.0 if self.pinhole_diameter is not None else None
41
- )
42
- ```
43
- ### `PSFEngine`
21
+
22
+
44
23
  #### Methods
45
24
 
46
25
  - **`__init__`**: Initializes the PSF engine with the given parameters.
@@ -50,7 +29,6 @@ def pinhole_radius(self) -> Optional[float]:
50
29
  - **`_3d_normalization_A`**: Computes the normalization factor for a 3D Gaussian PSF.
51
30
  - **`_2d_normalization_A`**: Computes the normalization factor for a 2D Gaussian PSF.
52
31
  - **`normalize_psf`**: Normalizes the PSF using different schemes.
53
- - **`_generate_pinhole_mask`**: Generate a binary mask representing the pinhole's spatial filtering.
54
32
 
55
33
  ---
56
34
 
@@ -127,21 +105,4 @@ Calculates the appropriate PSF size based on physical parameters.
127
105
 
128
106
  #### Returns
129
107
 
130
- - **`Tuple[int, ...]`**: Tuple of dimensions (z, y, x) or (y, x) for the PSF calculation.
131
-
132
- ---
133
-
134
- ### `_generate_pinhole_mask`
135
-
136
-
137
- #### Description
138
-
139
- Generate a binary mask representing the pinhole's spatial filtering.
140
-
141
- The pinhole blocks emission light based on position in the image plane,
142
- affecting what portion of the diffracted light reaches the detector.
143
-
144
- #### Parameters
145
- #### Returns
146
-
147
- - **`NDArray[np.float64]`**: Same dimensions as the psf generated but with binary values (0,1) indicating the transmittance of the psf due to the pinhole. Note, if the pinhole size is smaller than 1*airy disk diameter, then diffraction due to the pinhole is NOT non negligiable and diffraction effects will be introduced. A ValueError is thrown if this is the case.
108
+ - **`Tuple[int, ...]`**: Tuple of dimensions (z, y, x) or (y, x) for the PSF calculation.
@@ -224,7 +224,6 @@ Each fluorophore has transitions defined with the following parameters:
224
224
  - **Properties**:
225
225
  - **`numerical_aperture`**: The numerical aperture (typical range: 0.1 - 1.5).
226
226
  - **`refractive_index`**: The refractive index (default is air: 1.0).
227
- - **`pinhole_diameter`**: None or float. In units of um. None = no pinhole before the detector.
228
227
 
229
228
  ---
230
229
 
@@ -22,6 +22,7 @@ maintainers = [
22
22
 
23
23
  dependencies = [
24
24
  "numpy>=1.21.2",
25
+ "matplotlib>=3.6.0",
25
26
  "scipy>=1.7.1",
26
27
  "scikit-image>=0.18.3",
27
28
  "typer>=0.12.5",
@@ -40,10 +41,8 @@ venv = ".venv"
40
41
 
41
42
  [tool.uv]
42
43
  dev-dependencies = [
43
- "matplotlib>=3.10.0",
44
44
  "mkdocs-material==9.5.40",
45
45
  "mkdocstrings-python>=1.12.2",
46
- "notebook>=7.3.2",
47
46
  "pymdown-extensions>=10.11",
48
47
  "pyright>=1.1.384",
49
48
  "pytest>=8.3.3",
@@ -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