in-silico-cancer-cell 0.2.4__cp311-cp311-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,30 @@
1
+ # Welcome!
2
+ from in_silico_cancer_cell import _in_rusty_silico # type: ignore reportAttributeAccessIssue
3
+ from ._in_rusty_silico import (
4
+ A549CancerCell,
5
+ CellPhase,
6
+ ChannelCountsProblem,
7
+ InSilicoMethod,
8
+ PatchClampProtocol,
9
+ PatchClampData,
10
+ find_best_fit_for,
11
+ setup_logging,
12
+ )
13
+
14
+
15
+ def useless_python_function():
16
+ print("hello")
17
+
18
+
19
+ __doc__ = _in_rusty_silico.__doc__
20
+ __all__ = [
21
+ "A549CancerCell",
22
+ "CellPhase",
23
+ "ChannelCountsProblem",
24
+ "InSilicoMethod",
25
+ "PatchClampProtocol",
26
+ "PatchClampData",
27
+ "find_best_fit_for",
28
+ "setup_logging",
29
+ "useless_python_function",
30
+ ]
@@ -0,0 +1,46 @@
1
+ import enum
2
+
3
+ class A549CancerCell:
4
+ @staticmethod
5
+ def new() -> A549CancerCell:
6
+ pass
7
+
8
+ def evaluate(self, protocol: PatchClampProtocol, phase: CellPhase) -> float:
9
+ pass
10
+
11
+ class PatchClampProtocol(enum.Enum):
12
+ Activation = enum.auto()
13
+ Deactivation = enum.auto()
14
+ Ramp = enum.auto()
15
+
16
+ class CellPhase(enum.Enum):
17
+ G0 = enum.auto()
18
+ G1 = enum.auto()
19
+
20
+ class ChannelCountsProblem:
21
+ @staticmethod
22
+ def new(data: PatchClampData) -> ChannelCountsProblem:
23
+ pass
24
+ def precompute_single_channel_currents(self):
25
+ pass
26
+ def get_current_basis(self) -> list[list[float]]:
27
+ pass
28
+
29
+ class InSilicoMethod(enum.Enum):
30
+ Projection = enum.auto()
31
+ ParticleSwarm = enum.auto()
32
+ SteepestDescent = enum.auto()
33
+ LBFGS = enum.auto()
34
+
35
+ class PatchClampData:
36
+ @staticmethod
37
+ def pyload(protocol: PatchClampProtocol, phase: CellPhase) -> PatchClampData:
38
+ pass
39
+ def to_list(self) -> list[float]:
40
+ pass
41
+
42
+ def find_best_fit_for(data: PatchClampData, using: InSilicoMethod) -> list[float]:
43
+ pass
44
+
45
+ def setup_logging():
46
+ pass
@@ -0,0 +1,52 @@
1
+ import clarabel
2
+ import numpy as np
3
+ from scipy import sparse
4
+ import scipy
5
+
6
+ from . import CellPhase, ChannelCountsProblem, PatchClampData, PatchClampProtocol
7
+ from .utils import moving_average
8
+
9
+
10
+ def load_problem(n):
11
+ measurements = PatchClampData.pyload(PatchClampProtocol.Activation, CellPhase.G0)
12
+ data = moving_average(np.array(measurements.to_list()), n)
13
+ # data = np.array(measurements.to_list())[::12]
14
+ problem = ChannelCountsProblem.new(measurements)
15
+ problem.precompute_single_channel_currents()
16
+ single_channels = moving_average(np.array(problem.get_current_basis()), n)
17
+ # single_channels = np.array(problem.get_current_basis())[:, (3,)]
18
+ # single_channels = np.concatenate([single_channels, np.ones((single_channels.shape[0], 1))], axis=1)
19
+ return single_channels[: data.shape[0]], data
20
+
21
+
22
+ def solve_as_quadratic_problem(single_channels, data):
23
+ # LSQ formulation min 1/2 ||Rx - d||^2
24
+ R = single_channels
25
+ d = data
26
+
27
+ # converted into QP formulation
28
+ P = sparse.csc_matrix(R.T @ R)
29
+ q = -R.T @ d
30
+ A = -sparse.identity(11).tocsc()
31
+ b = np.zeros(11)
32
+ cones = [clarabel.NonnegativeConeT(11)]
33
+
34
+ # solve
35
+ settings = clarabel.DefaultSettings()
36
+ solver = clarabel.DefaultSolver(P, q, A, b, cones, settings)
37
+ solution = solver.solve()
38
+ return np.array(solution.x)
39
+
40
+
41
+ def solve_with(single_channels, data, method):
42
+ if method == "lstsq":
43
+ channel_counts, res, rank, s = np.linalg.lstsq(single_channels[: len(data), :], data, rcond=None)
44
+ elif method == "nnls":
45
+ channel_counts, rnorm = scipy.optimize.nnls(single_channels[: len(data), :], data)
46
+ elif method == "qp":
47
+ channel_counts = solve_as_quadratic_problem(single_channels, data)
48
+ elif method == "langthaler":
49
+ channel_counts = np.array([22, 78, 5, 1350, 40, 77, 19, 200, 17, 12, 13])
50
+ channel_counts = channel_counts.round().astype(int)
51
+ print(f"Best fit: {channel_counts}")
52
+ return channel_counts
@@ -0,0 +1,42 @@
1
+ import pathlib
2
+
3
+ import matplotlib.axes
4
+ import matplotlib.pyplot as plt
5
+ import numpy as np
6
+
7
+ from . import setup_logging
8
+ from .fit import load_problem, solve_with
9
+
10
+ RESULTS = pathlib.Path.cwd()
11
+ setup_logging()
12
+
13
+
14
+ def plot_measurement():
15
+ fig = plt.figure()
16
+ axes: matplotlib.axes.Axes = fig.add_subplot(1, 1, 1)
17
+ axes.plot()
18
+ axes.set_xlabel("")
19
+ axes.set_ylabel("")
20
+ axes.legend()
21
+ fig.savefig(str(RESULTS / "plot.pdf"))
22
+
23
+
24
+ def plot_full_comparison(method="nnls", n=800):
25
+ single_channels, data = load_problem(n)
26
+ channel_counts = solve_with(single_channels, data, method)
27
+ diff = (single_channels * channel_counts).sum(axis=1) - data
28
+ print(f"Error: {np.sqrt((diff ** 2).sum() / len(diff)):.2f}")
29
+ time = np.linspace(0, 9.901, single_channels.shape[0])
30
+ fig = plt.figure(figsize=(8, 4))
31
+ axes: matplotlib.axes.Axes = fig.add_subplot(1, 1, 1)
32
+ axes.plot(time[: len(data)], data, label="Measurements")
33
+ axes.plot(time, (single_channels * channel_counts).sum(axis=1), label="Simulation")
34
+ axes.set_xlabel("Time $t$ / s")
35
+ axes.set_ylabel("Current $I$ / pA")
36
+ axes.legend()
37
+ fig.savefig(str(RESULTS / "data-vs-simulation.pdf"))
38
+
39
+
40
+ def set_results_folder(path: pathlib.Path):
41
+ global RESULTS
42
+ RESULTS = path
File without changes
@@ -0,0 +1,16 @@
1
+ import numpy as np
2
+
3
+
4
+ def moving_average(a: np.ndarray, n=3) -> np.ndarray:
5
+ """Generate a moving average
6
+
7
+ Args:
8
+ a (np.array): original datum
9
+ n (int, optional): Average stencil order. Defaults to 3.
10
+
11
+ Returns:
12
+ np.ndarray: averaged array
13
+ """
14
+ ret = np.cumsum(a, dtype=float, axis=0)
15
+ ret[n:] = ret[n:] - ret[:-n]
16
+ return ret[n - 1 :] / n
@@ -0,0 +1,40 @@
1
+ Metadata-Version: 2.4
2
+ Name: in_silico_cancer_cell
3
+ Version: 0.2.4
4
+ Classifier: Programming Language :: Rust
5
+ Classifier: Programming Language :: Python :: Implementation :: CPython
6
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
7
+ Requires-Dist: matplotlib>=3.10.8
8
+ Requires-Dist: numpy>=2.4.2
9
+ Requires-Dist: clarabel>=0.11.1
10
+ Summary: Simulation of an electrophysiological A549 cancer cell model using individual ion channels across the membrane
11
+ Author-email: MrP01 <peter@waldert.at>
12
+ License-Expression: MIT
13
+ Requires-Python: >=3.11
14
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
15
+ Project-URL: homepage, https://in-silico-cancer-cell.waldert.at/
16
+ Project-URL: repository, https://github.com/MrP01/InSilicoCancerCell
17
+
18
+ # Electrophysiological Cancer Cell Model
19
+
20
+ ![PyPI - Version](https://img.shields.io/pypi/v/in-silico-cancer-cell)
21
+
22
+ Attempt to model an A549 cancer cell's ion channels using an HMM (Hidden Markov Model) and simulation of voltage + current development accross the membrane of the cell.
23
+
24
+ This software comes in three flavours:
25
+
26
+ - to run the `main.rs` simulation, do `cargo run`,
27
+ - to compile the Python module, do `maturin develop --features pyo3`,
28
+ - to precompile for the Astro dashboard, do `bun run wasm-pack build frontend`.
29
+
30
+ ## A visual to capture your interest:
31
+
32
+ ![Ion Channels](https://journals.plos.org/ploscompbiol/article/figure/image?size=large&download=&id=10.1371/journal.pcbi.1009091.g002)
33
+ (Image source: [here](https://doi.org/10.1371/journal.pcbi.1009091.g002)).
34
+
35
+ This computational model is based on [Langthaler et al., 2021](https://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1009091): **A549 in-silico 1.0: A first computational model to simulate cell cycle dependent ion current modulation in the human lung adenocarcinoma**.
36
+
37
+ ## The Simulation Dashboard
38
+
39
+ ![Screenshot of the User Interface](./figures/full-length-screenshot.png)
40
+
@@ -0,0 +1,10 @@
1
+ in_silico_cancer_cell\__init__.py,sha256=KSGw1PIDDXcTpX3HizMCXy0AuWcsCM1BeOZ3oEIr_J8,653
2
+ in_silico_cancer_cell\_in_rusty_silico.cp311-win_amd64.pyd,sha256=3gvzW6qhf6QQkjH299Zhn0uFgF9QacBV0fDf0_XLo2Q,2389504
3
+ in_silico_cancer_cell\_in_rusty_silico.pyi,sha256=FkZk0u5D_4o_fMAA5j7pKou7KAReXhWsyOtBMw1cH6Q,1145
4
+ in_silico_cancer_cell\fit.py,sha256=I1mXIBxkUbS8kmwgEmhHGDC-fvH2kPuuvinb-CcLJWU,2021
5
+ in_silico_cancer_cell\plot.py,sha256=zy11eGa_OBBqr8SXFsLLdgUt2HJIa9rQOIa-vmlzNfI,1307
6
+ in_silico_cancer_cell\py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ in_silico_cancer_cell\utils.py,sha256=HE2irwwNnF0LoSOSCcOk1bT5a1VfJ8JL6oM6CugnyP0,399
8
+ in_silico_cancer_cell-0.2.4.dist-info\METADATA,sha256=DfOLCmnaeW_eKxUI9o1I5sroyHDf9B2kzfJiMh_-uFA,1940
9
+ in_silico_cancer_cell-0.2.4.dist-info\WHEEL,sha256=X79LywvMB9iCuFHu88xBAFTJDhRqJi6Yh9hhoCI9jao,97
10
+ in_silico_cancer_cell-0.2.4.dist-info\RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.11.5)
3
+ Root-Is-Purelib: false
4
+ Tag: cp311-cp311-win_amd64