sopsim 0.2.0__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 (37) hide show
  1. sopsim-0.2.0/MANIFEST.in +2 -0
  2. sopsim-0.2.0/PKG-INFO +130 -0
  3. sopsim-0.2.0/README.md +113 -0
  4. sopsim-0.2.0/pyproject.toml +36 -0
  5. sopsim-0.2.0/setup.cfg +4 -0
  6. sopsim-0.2.0/sopsim/__init__.py +5 -0
  7. sopsim-0.2.0/sopsim/__main__.py +4 -0
  8. sopsim-0.2.0/sopsim/artifacts.py +79 -0
  9. sopsim-0.2.0/sopsim/cli.py +157 -0
  10. sopsim-0.2.0/sopsim/config.py +174 -0
  11. sopsim-0.2.0/sopsim/core.py +69 -0
  12. sopsim-0.2.0/sopsim/delta_in.py +111 -0
  13. sopsim-0.2.0/sopsim/filop_lent.py +69 -0
  14. sopsim-0.2.0/sopsim/filop_vectors.py +61 -0
  15. sopsim-0.2.0/sopsim/mat_files/Ang.mat +0 -0
  16. sopsim-0.2.0/sopsim/mat_files/Delta.mat +0 -0
  17. sopsim-0.2.0/sopsim/mat_files/F2.mat +0 -0
  18. sopsim-0.2.0/sopsim/mat_files/Notch.mat +0 -0
  19. sopsim-0.2.0/sopsim/mat_files/kappa.mat +0 -0
  20. sopsim-0.2.0/sopsim/reference_data.py +46 -0
  21. sopsim-0.2.0/sopsim/run_sopsim.py +284 -0
  22. sopsim-0.2.0/sopsim/server.py +303 -0
  23. sopsim-0.2.0/sopsim/two_d_geom.py +63 -0
  24. sopsim-0.2.0/sopsim/web_dist/__init__.py +1 -0
  25. sopsim-0.2.0/sopsim/web_dist/assets/index-Bg57AWq2.js +32 -0
  26. sopsim-0.2.0/sopsim/web_dist/assets/index-Bop8xgS8.css +1 -0
  27. sopsim-0.2.0/sopsim/web_dist/index.html +13 -0
  28. sopsim-0.2.0/sopsim.egg-info/PKG-INFO +130 -0
  29. sopsim-0.2.0/sopsim.egg-info/SOURCES.txt +35 -0
  30. sopsim-0.2.0/sopsim.egg-info/dependency_links.txt +1 -0
  31. sopsim-0.2.0/sopsim.egg-info/entry_points.txt +2 -0
  32. sopsim-0.2.0/sopsim.egg-info/requires.txt +9 -0
  33. sopsim-0.2.0/sopsim.egg-info/top_level.txt +1 -0
  34. sopsim-0.2.0/tests/test_api_types.py +15 -0
  35. sopsim-0.2.0/tests/test_cli.py +96 -0
  36. sopsim-0.2.0/tests/test_config.py +52 -0
  37. sopsim-0.2.0/tests/test_server.py +199 -0
@@ -0,0 +1,2 @@
1
+ recursive-include sopsim/mat_files *.mat
2
+ recursive-include sopsim/web_dist *
sopsim-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,130 @@
1
+ Metadata-Version: 2.4
2
+ Name: sopsim
3
+ Version: 0.2.0
4
+ Summary: SOPSim simulation library
5
+ Author: Olaolu Olugbenle, Dr. William Annan
6
+ Requires-Python: >=3.9
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: numpy
9
+ Requires-Dist: scipy
10
+ Requires-Dist: tqdm
11
+ Requires-Dist: shapely
12
+ Requires-Dist: matplotlib
13
+ Requires-Dist: fastapi
14
+ Requires-Dist: uvicorn[standard]
15
+ Requires-Dist: pydantic
16
+ Requires-Dist: python-dotenv
17
+
18
+ # SOPSim
19
+
20
+ SOPSim is a Python simulation package for investigating SOP pattern formation. You can choose to use it in one of four ways:
21
+
22
+ 1. The official SOPSim website
23
+ 2. As a Command line tool
24
+ 3. As a website, local to your computer
25
+ 4. As a Python API
26
+
27
+ Each method is explained in detail below.
28
+
29
+ ## 1. The official SOPSim website
30
+
31
+ The official SOPSim website is available at (*link coming soon*).
32
+
33
+ ## 2. As a Command line tool
34
+
35
+ Inside your command line, type:
36
+
37
+ ```bash
38
+ pip install -i https://test.pypi.org/simple/ sopsim==0.1.6
39
+ ```
40
+
41
+ to install the package.
42
+
43
+ Use this command below to run a single simulation:
44
+
45
+ ```bash
46
+ sopsim run --nc 4 --filopodia-type A --filopodia-life-time 10 --out-dir output
47
+ ```
48
+
49
+ In this specific example, this command will also generate plots and metadata to a folder called `output`.
50
+
51
+ For help, run:
52
+
53
+ ```bash
54
+ sopsim run -h
55
+ ```
56
+
57
+ ## 3. As a website, local to your computer
58
+
59
+ After installing SOPSim with `pip install`, you can start the local web app with:
60
+
61
+ ```bash
62
+ sopsim serve
63
+ ```
64
+
65
+ Once you run this, copy the link and paste it into your browser. The link will show up in your terminal and will start with:
66
+ ```bash
67
+ http://...
68
+ ```
69
+
70
+ For help, run:
71
+
72
+ ```bash
73
+ sopsim serve -h
74
+ ```
75
+
76
+ ## 4. As a Python API
77
+
78
+ Assuming you have Python and the `sopsim` library installed, create a new Python script and add the following code:
79
+
80
+ ```python
81
+ from sopsim import sopsim
82
+
83
+ if __name__ == '__main__':
84
+ results = sopsim(Nc=4, filopodia_type="A", filopodia_life_time=10)
85
+ print(results["FData"])
86
+ ```
87
+
88
+ Note: In its current version, using the API does not allow users to view plots.
89
+
90
+ <!-- ## Sanity Checks
91
+
92
+ By default, SOPSim uses NumPy's random number generator, so repeated runs with the same inputs can still produce different results.
93
+
94
+ For a deterministic legacy comparison, use the bundled MATLAB reference matrices in this way:
95
+
96
+
97
+ ### Command Line
98
+ ```bash
99
+ sopsim run --nc 4 --use-mat-files --out-dir output
100
+ ```
101
+
102
+ ### Website Local to your Computer
103
+ Tick the "Use bundled legacy MAT files" checkbox
104
+
105
+ ### Python API (OLAOLU: MAKE SURE TO TEST THIS)
106
+ ```python
107
+ from sopsim import sopsim
108
+
109
+ results = sopsim(Nc=4, use_mat_files=True)
110
+ print(results["FData"])
111
+ ``` -->
112
+
113
+ ### *Input Values*
114
+
115
+ The repo enforces these input rules:
116
+
117
+ | Input | Allowed values |
118
+ | --- | --- |
119
+ | `Nc` (Number of cells per row in final square tissue*) | Integer `>= 1` |
120
+ | `filopodia_type` | One of `A`, `B`, `C`, `D`. Default = `A` |
121
+ | `filopodia_life_time` | Integer `>= 1`. Default = `10` |
122
+ <!-- | `use_mat_files` | `true` / `false`, only valid when `Nc = 4` | -->
123
+
124
+ Important:
125
+
126
+ <!-- - `--use-mat-files` is only supported when `Nc=4`
127
+ - This mode is the best option when you want the same starting RNG state used in the legacy MATLAB workflow
128
+ - For other `Nc` values, the simulation uses fresh random draws each run -->
129
+ - *`Nc = 4` implies a 4x4 tissue
130
+ - `Nc>=10` can take many hours to run, so start smaller when testing
sopsim-0.2.0/README.md ADDED
@@ -0,0 +1,113 @@
1
+ # SOPSim
2
+
3
+ SOPSim is a Python simulation package for investigating SOP pattern formation. You can choose to use it in one of four ways:
4
+
5
+ 1. The official SOPSim website
6
+ 2. As a Command line tool
7
+ 3. As a website, local to your computer
8
+ 4. As a Python API
9
+
10
+ Each method is explained in detail below.
11
+
12
+ ## 1. The official SOPSim website
13
+
14
+ The official SOPSim website is available at (*link coming soon*).
15
+
16
+ ## 2. As a Command line tool
17
+
18
+ Inside your command line, type:
19
+
20
+ ```bash
21
+ pip install -i https://test.pypi.org/simple/ sopsim==0.1.6
22
+ ```
23
+
24
+ to install the package.
25
+
26
+ Use this command below to run a single simulation:
27
+
28
+ ```bash
29
+ sopsim run --nc 4 --filopodia-type A --filopodia-life-time 10 --out-dir output
30
+ ```
31
+
32
+ In this specific example, this command will also generate plots and metadata to a folder called `output`.
33
+
34
+ For help, run:
35
+
36
+ ```bash
37
+ sopsim run -h
38
+ ```
39
+
40
+ ## 3. As a website, local to your computer
41
+
42
+ After installing SOPSim with `pip install`, you can start the local web app with:
43
+
44
+ ```bash
45
+ sopsim serve
46
+ ```
47
+
48
+ Once you run this, copy the link and paste it into your browser. The link will show up in your terminal and will start with:
49
+ ```bash
50
+ http://...
51
+ ```
52
+
53
+ For help, run:
54
+
55
+ ```bash
56
+ sopsim serve -h
57
+ ```
58
+
59
+ ## 4. As a Python API
60
+
61
+ Assuming you have Python and the `sopsim` library installed, create a new Python script and add the following code:
62
+
63
+ ```python
64
+ from sopsim import sopsim
65
+
66
+ if __name__ == '__main__':
67
+ results = sopsim(Nc=4, filopodia_type="A", filopodia_life_time=10)
68
+ print(results["FData"])
69
+ ```
70
+
71
+ Note: In its current version, using the API does not allow users to view plots.
72
+
73
+ <!-- ## Sanity Checks
74
+
75
+ By default, SOPSim uses NumPy's random number generator, so repeated runs with the same inputs can still produce different results.
76
+
77
+ For a deterministic legacy comparison, use the bundled MATLAB reference matrices in this way:
78
+
79
+
80
+ ### Command Line
81
+ ```bash
82
+ sopsim run --nc 4 --use-mat-files --out-dir output
83
+ ```
84
+
85
+ ### Website Local to your Computer
86
+ Tick the "Use bundled legacy MAT files" checkbox
87
+
88
+ ### Python API (OLAOLU: MAKE SURE TO TEST THIS)
89
+ ```python
90
+ from sopsim import sopsim
91
+
92
+ results = sopsim(Nc=4, use_mat_files=True)
93
+ print(results["FData"])
94
+ ``` -->
95
+
96
+ ### *Input Values*
97
+
98
+ The repo enforces these input rules:
99
+
100
+ | Input | Allowed values |
101
+ | --- | --- |
102
+ | `Nc` (Number of cells per row in final square tissue*) | Integer `>= 1` |
103
+ | `filopodia_type` | One of `A`, `B`, `C`, `D`. Default = `A` |
104
+ | `filopodia_life_time` | Integer `>= 1`. Default = `10` |
105
+ <!-- | `use_mat_files` | `true` / `false`, only valid when `Nc = 4` | -->
106
+
107
+ Important:
108
+
109
+ <!-- - `--use-mat-files` is only supported when `Nc=4`
110
+ - This mode is the best option when you want the same starting RNG state used in the legacy MATLAB workflow
111
+ - For other `Nc` values, the simulation uses fresh random draws each run -->
112
+ - *`Nc = 4` implies a 4x4 tissue
113
+ - `Nc>=10` can take many hours to run, so start smaller when testing
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "sopsim"
7
+ version = "0.2.0"
8
+ description = "SOPSim simulation library"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ authors = [
12
+ {name = "Olaolu Olugbenle"},
13
+ {name = "Dr. William Annan"}
14
+ ]
15
+
16
+ dependencies = [
17
+ "numpy",
18
+ "scipy",
19
+ "tqdm",
20
+ "shapely",
21
+ "matplotlib",
22
+ "fastapi",
23
+ "uvicorn[standard]",
24
+ "pydantic",
25
+ "python-dotenv",
26
+ ]
27
+
28
+ [tool.setuptools]
29
+ packages = ["sopsim", "sopsim.web_dist"]
30
+ include-package-data = true
31
+
32
+ [tool.setuptools.package-data]
33
+ sopsim = ["mat_files/*.mat", "web_dist/index.html", "web_dist/assets/*"]
34
+
35
+ [project.scripts]
36
+ sopsim = "sopsim.cli:main"
sopsim-0.2.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,5 @@
1
+ """SOPSim package."""
2
+ from .core import sopsim
3
+
4
+ __all__ = ["sopsim"]
5
+ __version__ = "0.1.0"
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+
4
+ raise SystemExit(main())
@@ -0,0 +1,79 @@
1
+ """Utilities for writing local SOPSim outputs."""
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ import pathlib
6
+ from typing import Any, Dict
7
+
8
+ import numpy as np
9
+
10
+ from .run_sopsim import generate_plots
11
+
12
+
13
+ def _jsonable(value: Any) -> Any:
14
+ if isinstance(value, np.ndarray):
15
+ return value.tolist()
16
+ if isinstance(value, (np.integer, np.floating)):
17
+ return value.item()
18
+ if isinstance(value, dict):
19
+ return {key: _jsonable(item) for key, item in value.items()}
20
+ if isinstance(value, (list, tuple)):
21
+ return [_jsonable(item) for item in value]
22
+ return value
23
+
24
+
25
+ def write_metadata(out_dir: pathlib.Path, inputs: Dict[str, Any], FData, extra: Dict[str, Any] | None = None) -> dict:
26
+ out_dir.mkdir(parents=True, exist_ok=True)
27
+ metadata = {
28
+ "inputs": _jsonable(inputs),
29
+ "FData": _jsonable(FData),
30
+ "summary": {
31
+ "FinalTime": float(FData[0]),
32
+ "RSA": float(FData[1]),
33
+ "mean_LSA": float(FData[2]),
34
+ },
35
+ }
36
+ if extra:
37
+ metadata.update(_jsonable(extra))
38
+
39
+ (out_dir / "metadata.json").write_text(json.dumps(metadata, indent=2))
40
+ return metadata
41
+
42
+
43
+ def save_simulation_outputs(
44
+ out_dir: pathlib.Path,
45
+ inputs: Dict[str, Any],
46
+ FData,
47
+ LSA,
48
+ MeanDin,
49
+ Notch_time_step,
50
+ MeanSOPNotch,
51
+ MeanEPNotch,
52
+ FinalNotch,
53
+ ContP,
54
+ *,
55
+ generate_figures: bool = True,
56
+ ) -> dict:
57
+ """Persist the standard output bundle for a completed simulation."""
58
+ out_dir.mkdir(parents=True, exist_ok=True)
59
+ if generate_figures:
60
+ generate_plots(
61
+ inputs["Nc"],
62
+ inputs["r"],
63
+ ContP,
64
+ MeanDin,
65
+ Notch_time_step,
66
+ MeanSOPNotch,
67
+ MeanEPNotch,
68
+ FinalNotch,
69
+ LSA,
70
+ out_dir,
71
+ )
72
+ return write_metadata(
73
+ out_dir,
74
+ inputs,
75
+ FData,
76
+ extra={
77
+ "result_files": sorted(path.name for path in out_dir.iterdir() if path.is_file()),
78
+ },
79
+ )
@@ -0,0 +1,157 @@
1
+ """Command line entry point for SOPSim."""
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import json
6
+ import pathlib
7
+ import sys
8
+ from typing import Sequence
9
+
10
+ import uvicorn
11
+
12
+ from .artifacts import save_simulation_outputs
13
+ from .config import (
14
+ FILOPODIA_LIFE_TIME_VALIDATION_MESSAGE,
15
+ FILOPODIA_TYPE_VALIDATION_MESSAGE,
16
+ FILOPODIA_TYPES,
17
+ MATLAB_REFERENCE_NC,
18
+ MATLAB_REFERENCE_VALIDATION_MESSAGE,
19
+ MIN_FILOPODIA_LIFE_TIME,
20
+ MIN_NC,
21
+ NC_VALIDATION_MESSAGE,
22
+ SimulationInputs,
23
+ build_simulation_parameters,
24
+ )
25
+ from .core import sopsim
26
+
27
+ DEFAULT_FILOPODIA_TYPE = SimulationInputs().filopodia_type
28
+ DEFAULT_FILOPODIA_LIFE_TIME = SimulationInputs().filopodia_life_time
29
+
30
+
31
+ class SOPSimArgumentParser(argparse.ArgumentParser):
32
+ def error(self, message: str) -> None: # pragma: no cover - exercised through CLI behavior
33
+ self.print_help(sys.stderr)
34
+ self.exit(2, f"\nError: {message}\n")
35
+
36
+
37
+ def positive_int(value: str, *, minimum: int, label: str) -> int:
38
+ try:
39
+ parsed = int(value)
40
+ except ValueError as exc:
41
+ raise argparse.ArgumentTypeError(f"{label} must be an integer >= {minimum}.") from exc
42
+ if parsed < minimum:
43
+ raise argparse.ArgumentTypeError(f"{label} must be an integer >= {minimum}.")
44
+ return parsed
45
+
46
+
47
+ def run_simulation(args: argparse.Namespace) -> int:
48
+ inputs = SimulationInputs(
49
+ Nc=args.nc,
50
+ filopodia_type=args.filopodia_type,
51
+ filopodia_life_time=args.filopodia_life_time,
52
+ use_mat_files=args.use_mat_files,
53
+ )
54
+ params = build_simulation_parameters(inputs)
55
+ result = sopsim(
56
+ Nc=inputs.Nc,
57
+ filopodia_type=inputs.filopodia_type,
58
+ filopodia_life_time=inputs.filopodia_life_time,
59
+ use_mat_files=inputs.use_mat_files,
60
+ )
61
+ out_dir = pathlib.Path(args.out_dir)
62
+ metadata = save_simulation_outputs(
63
+ out_dir,
64
+ params["inputs"],
65
+ result["FData"],
66
+ result["LSA"],
67
+ result["MeanDin"],
68
+ result["Notch_time_step"],
69
+ result["MeanSOPNotch"],
70
+ result["MeanEPNotch"],
71
+ result["FinalNotch"],
72
+ params["ContP"],
73
+ generate_figures=not args.no_plots,
74
+ )
75
+
76
+ print(json.dumps(metadata["summary"], indent=2))
77
+ print(f"Saved outputs to {out_dir}")
78
+ return 0
79
+
80
+
81
+ def serve_app(args: argparse.Namespace) -> int:
82
+ uvicorn.run("sopsim.server:app", host=args.host, port=args.port, reload=args.reload)
83
+ return 0
84
+
85
+
86
+ def build_parser() -> argparse.ArgumentParser:
87
+ parser = SOPSimArgumentParser(
88
+ prog="sopsim",
89
+ description="Run SOPSim locally.",
90
+ formatter_class=argparse.RawDescriptionHelpFormatter,
91
+ epilog=(
92
+ "Input summary:\n"
93
+ f" Nc: integer >= {MIN_NC}. Required input.\n"
94
+ f" filopodia_type: one of {', '.join(FILOPODIA_TYPES)}. Default is {DEFAULT_FILOPODIA_TYPE}.\n"
95
+ f" filopodia_life_time: integer >= {MIN_FILOPODIA_LIFE_TIME}. Default is {DEFAULT_FILOPODIA_LIFE_TIME}.\n"
96
+ f" use_mat_files: only valid when Nc={MATLAB_REFERENCE_NC}\n"
97
+ " r: fixed at 1.0\n\n"
98
+ "Examples:\n"
99
+ " sopsim run --nc 4 --filopodia-type A --filopodia-life-time 10 --out-dir output\n"
100
+ " sopsim run --nc 4 --use-mat-files --out-dir output\n"
101
+ " sopsim serve" #ALT: sopsim serve --host 127.0.0.1 --port 8000
102
+ ),
103
+ )
104
+ subparsers = parser.add_subparsers(dest="command")
105
+
106
+ run_parser = subparsers.add_parser("run", help="Run one simulation and write local outputs.")
107
+ run_parser.add_argument(
108
+ "--nc",
109
+ type=lambda value: positive_int(value, minimum=MIN_NC, label="Nc"),
110
+ required=True,
111
+ help=NC_VALIDATION_MESSAGE,
112
+ )
113
+ run_parser.add_argument(
114
+ "--filopodia-type",
115
+ choices=FILOPODIA_TYPES,
116
+ default=DEFAULT_FILOPODIA_TYPE,
117
+ help=f"{FILOPODIA_TYPE_VALIDATION_MESSAGE} (default: {DEFAULT_FILOPODIA_TYPE})",
118
+ )
119
+ run_parser.add_argument(
120
+ "--filopodia-life-time",
121
+ type=lambda value: positive_int(value, minimum=1, label="filopodia_life_time"),
122
+ default=DEFAULT_FILOPODIA_LIFE_TIME,
123
+ help=f"{FILOPODIA_LIFE_TIME_VALIDATION_MESSAGE} (default: {DEFAULT_FILOPODIA_LIFE_TIME})",
124
+ )
125
+ run_parser.add_argument(
126
+ "--out-dir",
127
+ type=pathlib.Path,
128
+ default=pathlib.Path("output"),
129
+ help="Directory for plots and metadata",
130
+ )
131
+ run_parser.add_argument("--no-plots", action="store_true", help="Skip generating figure files")
132
+ run_parser.add_argument(
133
+ "--use-mat-files",
134
+ action="store_true",
135
+ help=MATLAB_REFERENCE_VALIDATION_MESSAGE,
136
+ )
137
+ run_parser.set_defaults(func=run_simulation)
138
+
139
+ serve_parser = subparsers.add_parser("serve", help="Start SOPSim as a website, local to your computer.")
140
+ serve_parser.add_argument("--host", default="127.0.0.1", help="Host interface to bind")
141
+ serve_parser.add_argument("--port", type=int, default=8000, help="Port to bind")
142
+ serve_parser.add_argument("--reload", action="store_true", help="Enable uvicorn reload mode")
143
+ serve_parser.set_defaults(func=serve_app)
144
+
145
+ return parser
146
+
147
+
148
+ def main(argv: Sequence[str] | None = None) -> int:
149
+ parser = build_parser()
150
+ try:
151
+ args = parser.parse_args(argv)
152
+ if not hasattr(args, "func"):
153
+ parser.print_help()
154
+ return 0
155
+ return int(args.func(args))
156
+ except ValueError as exc:
157
+ parser.error(str(exc))