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.
- sopsim-0.2.0/MANIFEST.in +2 -0
- sopsim-0.2.0/PKG-INFO +130 -0
- sopsim-0.2.0/README.md +113 -0
- sopsim-0.2.0/pyproject.toml +36 -0
- sopsim-0.2.0/setup.cfg +4 -0
- sopsim-0.2.0/sopsim/__init__.py +5 -0
- sopsim-0.2.0/sopsim/__main__.py +4 -0
- sopsim-0.2.0/sopsim/artifacts.py +79 -0
- sopsim-0.2.0/sopsim/cli.py +157 -0
- sopsim-0.2.0/sopsim/config.py +174 -0
- sopsim-0.2.0/sopsim/core.py +69 -0
- sopsim-0.2.0/sopsim/delta_in.py +111 -0
- sopsim-0.2.0/sopsim/filop_lent.py +69 -0
- sopsim-0.2.0/sopsim/filop_vectors.py +61 -0
- sopsim-0.2.0/sopsim/mat_files/Ang.mat +0 -0
- sopsim-0.2.0/sopsim/mat_files/Delta.mat +0 -0
- sopsim-0.2.0/sopsim/mat_files/F2.mat +0 -0
- sopsim-0.2.0/sopsim/mat_files/Notch.mat +0 -0
- sopsim-0.2.0/sopsim/mat_files/kappa.mat +0 -0
- sopsim-0.2.0/sopsim/reference_data.py +46 -0
- sopsim-0.2.0/sopsim/run_sopsim.py +284 -0
- sopsim-0.2.0/sopsim/server.py +303 -0
- sopsim-0.2.0/sopsim/two_d_geom.py +63 -0
- sopsim-0.2.0/sopsim/web_dist/__init__.py +1 -0
- sopsim-0.2.0/sopsim/web_dist/assets/index-Bg57AWq2.js +32 -0
- sopsim-0.2.0/sopsim/web_dist/assets/index-Bop8xgS8.css +1 -0
- sopsim-0.2.0/sopsim/web_dist/index.html +13 -0
- sopsim-0.2.0/sopsim.egg-info/PKG-INFO +130 -0
- sopsim-0.2.0/sopsim.egg-info/SOURCES.txt +35 -0
- sopsim-0.2.0/sopsim.egg-info/dependency_links.txt +1 -0
- sopsim-0.2.0/sopsim.egg-info/entry_points.txt +2 -0
- sopsim-0.2.0/sopsim.egg-info/requires.txt +9 -0
- sopsim-0.2.0/sopsim.egg-info/top_level.txt +1 -0
- sopsim-0.2.0/tests/test_api_types.py +15 -0
- sopsim-0.2.0/tests/test_cli.py +96 -0
- sopsim-0.2.0/tests/test_config.py +52 -0
- sopsim-0.2.0/tests/test_server.py +199 -0
sopsim-0.2.0/MANIFEST.in
ADDED
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,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))
|