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.
- {ams_bp-0.0.3 → ams_bp-0.0.21}/.github/workflows/lint.yml +1 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/PKG-INFO +2 -3
- {ams_bp-0.0.3 → ams_bp-0.0.21}/README.md +0 -2
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/configio/configmodels.md +8 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/optics/psf/psf_engine.md +3 -42
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/sim_config.md +0 -1
- {ams_bp-0.0.3 → ams_bp-0.0.21}/pyproject.toml +1 -2
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/__init__.py +1 -1
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/configio/configmodels.py +4 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/configio/convertconfig.py +1 -2
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/metadata/metadata.py +2 -2
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/motion/condensate_movement.py +45 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/motion/movement/fbm_BP.py +5 -4
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/motion/track_gen.py +6 -6
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/camera/detectors.py +1 -1
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/lasers/laser_profiles.py +177 -15
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/psf/psf_engine.py +38 -93
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/photophysics/photon_physics.py +4 -4
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/photophysics/state_kinetics.py +1 -4
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/run_cell_simulation.py +3 -3
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/sim_config.toml +17 -2
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/sim_microscopy.py +2 -4
- {ams_bp-0.0.3 → ams_bp-0.0.21}/uv.lock +77 -1143
- ams_bp-0.0.3/examples/QuantitativeExperiments/FRAP_base_[[0. 0.]].txt +0 -10
- ams_bp-0.0.3/examples/QuantitativeExperiments/FRAP_base_[[0.04 0.04]].txt +0 -10
- ams_bp-0.0.3/examples/QuantitativeExperiments/FRAP_base_[[0.1 0.1]].txt +0 -10
- ams_bp-0.0.3/examples/QuantitativeExperiments/FRAP_base_[[0.4 0.4]].txt +0 -10
- ams_bp-0.0.3/examples/QuantitativeExperiments/FRAP_data_[[0. 0.]].txt +0 -10
- ams_bp-0.0.3/examples/QuantitativeExperiments/FRAP_data_[[0.04 0.04]].txt +0 -10
- ams_bp-0.0.3/examples/QuantitativeExperiments/FRAP_data_[[0.1 0.1]].txt +0 -10
- ams_bp-0.0.3/examples/QuantitativeExperiments/FRAP_data_[[0.4 0.4]].txt +0 -10
- ams_bp-0.0.3/examples/QuantitativeExperiments/FRAP_methods.ipynb +0 -1025
- ams_bp-0.0.3/examples/VisualizingIndividualModules/laser_modulation.ipynb +0 -1094
- ams_bp-0.0.3/examples/VisualizingIndividualModules/modules_explained.ipynb +0 -1466
- {ams_bp-0.0.3 → ams_bp-0.0.21}/.github/workflows/pages.yml +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/.github/workflows/publish_pypi.yml +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/.gitignore +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/LICENSE +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/cells/base_cell.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/cells/rectangular_cell.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/cells/rod_cell.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/cells/spherical_cell.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/configio/convertconfig.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/configio/experiments.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/configio/saving.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/metadata/metadata.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/motion/condensate_movement.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/motion/movement/boundary_conditions.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/motion/movement/fbm_BP.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/motion/track_gen.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/optics/camera/detectors.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/optics/camera/quantum_eff.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/optics/filters/channels/channelschema.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/optics/filters/filters.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/optics/lasers/laser_profiles.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/photophysics/photon_physics.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/photophysics/state_kinetics.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/probabilityfuncs/markov_chain.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/probabilityfuncs/probability_functions.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/run_cell_simulation.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/sample/flurophore/flurophore_schema.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/sample/sim_sampleplane.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/sim_microscopy.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/utils/constants.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/utils/errors.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/API_Documentation/utils/util_functions.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/assets/icons/Cells-actin-like-a-tree-Jamie-Whitelaw-1.png +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/assets/icons/drawing.pdf +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/assets/icons/drawing.png +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/assets/icons/drawing.svg +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/docs/index.md +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/mkdocs.yml +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/pytest.ini +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/cells/__init__.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/cells/base_cell.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/cells/rectangular_cell.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/cells/rod_cell.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/cells/spherical_cell.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/configio/__init__.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/configio/experiments.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/configio/saving.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/metadata/__init__.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/motion/__init__.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/motion/movement/__init__.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/motion/movement/boundary_conditions.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/__init__.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/camera/__init__.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/camera/quantum_eff.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/filters/__init__.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/filters/channels/__init__.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/filters/channels/channelschema.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/filters/filters.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/lasers/__init__.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/optics/psf/__init__.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/photophysics/__init__.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/probabilityfuncs/__init__.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/probabilityfuncs/markov_chain.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/probabilityfuncs/probability_functions.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/sample/__init__.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/sample/flurophores/__init__.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/sample/flurophores/flurophore_schema.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/sample/sim_sampleplane.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/utils/__init__.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/utils/constants.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/utils/decorators.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/utils/errors.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/utils/maskMaker.py +0 -0
- {ams_bp-0.0.3 → ams_bp-0.0.21}/src/AMS_BP/utils/util_functions.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: AMS_BP
|
3
|
-
Version: 0.0.
|
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
|
-
|
23
|
-
|
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",
|
@@ -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
|
-
|
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
|
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 =
|
166
|
-
|
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
|
-
|
128
|
-
|
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=
|
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
|
-
|
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=
|
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 !=
|
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
|
-
|
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
|
-
#
|
375
|
-
#
|
376
|
-
|
377
|
-
|
378
|
-
#
|
379
|
-
|
380
|
-
|
381
|
-
#
|
382
|
-
|
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.
|
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
|