matprops-sdk 0.1.1__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 (38) hide show
  1. matprops_sdk-0.1.1/.gitignore +60 -0
  2. matprops_sdk-0.1.1/LICENSE +21 -0
  3. matprops_sdk-0.1.1/PKG-INFO +165 -0
  4. matprops_sdk-0.1.1/README.md +141 -0
  5. matprops_sdk-0.1.1/examples/add_numbers/example.input.json +1 -0
  6. matprops_sdk-0.1.1/examples/add_numbers/pyproject.toml +8 -0
  7. matprops_sdk-0.1.1/examples/add_numbers/simulation.py +15 -0
  8. matprops_sdk-0.1.1/examples/composite-thermal-conductivity/example.input.json +8 -0
  9. matprops_sdk-0.1.1/examples/composite-thermal-conductivity/example.input.smoke.json +8 -0
  10. matprops_sdk-0.1.1/examples/composite-thermal-conductivity/pyproject.toml +8 -0
  11. matprops_sdk-0.1.1/examples/composite-thermal-conductivity/requirements.txt +1 -0
  12. matprops_sdk-0.1.1/examples/composite-thermal-conductivity/simulation.py +156 -0
  13. matprops_sdk-0.1.1/examples/composite-thermal-conductivity/solver.py +149 -0
  14. matprops_sdk-0.1.1/examples/gan-thermal-conductivity/example.input.json +4 -0
  15. matprops_sdk-0.1.1/examples/gan-thermal-conductivity/pyproject.toml +12 -0
  16. matprops_sdk-0.1.1/examples/gan-thermal-conductivity/simulation.py +26 -0
  17. matprops_sdk-0.1.1/examples/volume-of-sphere/example.input.json +3 -0
  18. matprops_sdk-0.1.1/examples/volume-of-sphere/my_logic.py +5 -0
  19. matprops_sdk-0.1.1/examples/volume-of-sphere/pyproject.toml +12 -0
  20. matprops_sdk-0.1.1/examples/volume-of-sphere/simulation.py +28 -0
  21. matprops_sdk-0.1.1/pyproject.toml +48 -0
  22. matprops_sdk-0.1.1/src/matprops_sdk/__init__.py +14 -0
  23. matprops_sdk-0.1.1/src/matprops_sdk/auth.py +227 -0
  24. matprops_sdk-0.1.1/src/matprops_sdk/bundle.py +64 -0
  25. matprops_sdk-0.1.1/src/matprops_sdk/cli.py +358 -0
  26. matprops_sdk-0.1.1/src/matprops_sdk/context.py +104 -0
  27. matprops_sdk-0.1.1/src/matprops_sdk/credentials.py +93 -0
  28. matprops_sdk-0.1.1/src/matprops_sdk/manifest.py +70 -0
  29. matprops_sdk-0.1.1/src/matprops_sdk/models.py +38 -0
  30. matprops_sdk-0.1.1/src/matprops_sdk/publish.py +165 -0
  31. matprops_sdk-0.1.1/src/matprops_sdk/remote.py +297 -0
  32. matprops_sdk-0.1.1/src/matprops_sdk/runtime.py +176 -0
  33. matprops_sdk-0.1.1/src/matprops_sdk/simulation.py +163 -0
  34. matprops_sdk-0.1.1/tests/test_bundle.py +92 -0
  35. matprops_sdk-0.1.1/tests/test_cli.py +293 -0
  36. matprops_sdk-0.1.1/tests/test_contract.py +170 -0
  37. matprops_sdk-0.1.1/tests/test_login.py +170 -0
  38. matprops_sdk-0.1.1/tests/test_remote.py +299 -0
@@ -0,0 +1,60 @@
1
+ .DS_Store
2
+ node_modules/
3
+ **/node_modules/
4
+ .build/
5
+ **/.build/
6
+ *.tsbuildinfo
7
+ .next/
8
+ **/.next/
9
+ .env
10
+ .env.*
11
+ !.env.sample*
12
+ # Package-level names are symlinks to the root files (git stores the link, not secrets)
13
+ !/frontend/.env
14
+ !/frontend/.env.local
15
+ !/db/.env
16
+ !/db/.env.local
17
+ *.log
18
+ __pycache__/
19
+ *.pyc
20
+ .venv/
21
+ venv/
22
+ dist/
23
+ build/
24
+ .turbo/
25
+ .serverless/
26
+ .webpack/
27
+ coverage/
28
+ .nyc_output/
29
+ *.egg-info/
30
+ .pytest_cache/
31
+ .ruff_cache/
32
+ .run-results/
33
+ matprops-run/
34
+ results/
35
+ .pnpm-store/
36
+ .pulumi/
37
+ .vercel/
38
+
39
+ .envy.*
40
+
41
+ # lattice-dynamics generated artifacts
42
+ mesh_dicts/
43
+ mesh_dicts*/
44
+ outfiles/
45
+ outfiles*/
46
+ kappa-m*
47
+ *IFCs/
48
+ fc*
49
+ FORCE_SETS
50
+ FORCES_FC2
51
+ FORCES_FC3
52
+ POSCAR*
53
+ BORN
54
+ aux_scripts/
55
+ gruneisen*/
56
+ lattice-dynamics/**/*output/
57
+
58
+ # Local-only reference code — never commit or push
59
+ /example-codebase/
60
+ example-codebase/**
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 MatProps
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,165 @@
1
+ Metadata-Version: 2.5
2
+ Name: matprops-sdk
3
+ Version: 0.1.1
4
+ Summary: Define and run Matprops simulations locally.
5
+ Project-URL: Homepage, https://matprops.com
6
+ Project-URL: Repository, https://github.com/rileyhanus/matprops
7
+ Project-URL: Issues, https://github.com/rileyhanus/matprops/issues
8
+ Author: MatProps
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Scientific/Engineering
18
+ Requires-Python: >=3.11
19
+ Requires-Dist: pydantic<3,>=2
20
+ Provides-Extra: dev
21
+ Requires-Dist: pytest>=8; extra == 'dev'
22
+ Requires-Dist: ruff; extra == 'dev'
23
+ Description-Content-Type: text/markdown
24
+
25
+ # Matprops SDK
26
+
27
+ Local toolkit for typed material simulations: validate the contract, emit JSON Schema, run on your machine, and package or publish a zip to sim-server.
28
+
29
+ Requires Python 3.11+.
30
+
31
+ ```bash
32
+ python -m pip install matprops-sdk
33
+ matprops init my-sim
34
+ cd my-sim
35
+ matprops validate
36
+ matprops run --input example.input.json
37
+ matprops package # dist/<name>.zip, upload it in the web UI
38
+ matprops publish # or package + upload in one step (needs login)
39
+ ```
40
+
41
+ From a clone of this repo, install an editable copy with tests and lint:
42
+
43
+ ```bash
44
+ python -m pip install -e ".[dev]"
45
+ ```
46
+
47
+ `init` writes `simulation.py`, `pyproject.toml`, and `example.input.json` (it will not overwrite existing files). Entrypoint defaults to `[tool.matprops] entrypoint = "simulation:run"`; override with `--entrypoint`.
48
+
49
+ ## CLI login
50
+
51
+ `matprops login` opens the Matprops web app (or prints a URL) so you can sign in and approve the CLI. Temporary credentials are stored in `~/.config/matprops/credentials.json` (`chmod 600`).
52
+
53
+ ```bash
54
+ matprops login
55
+ matprops whoami
56
+ matprops logout
57
+ ```
58
+
59
+ Defaults are production: `https://matprops.com` and `https://api.matprops.com`. Override with `MATPROPS_APP_URL` / `MATPROPS_API_URL` or `--app-url` / `--api-url`. For the local stack use `http://localhost:3000` and `http://localhost:4000`; for the shared dev environment use `https://dev.matprops.com` and `https://api.dev.matprops.com`. Use `--no-browser` on a remote machine and open the printed URL locally.
60
+
61
+ ## Simulation
62
+
63
+ Use Pydantic models and `@simulation`. Sibling modules are importable as long as filenames are valid Python (`my_logic.py`, not `my-logic.py`).
64
+
65
+ ```python
66
+ from matprops_sdk import Field, InputModel, OutputModel, RunContext, simulation
67
+
68
+
69
+ class Inputs(InputModel):
70
+ radius: float = Field(gt=0, units="cm")
71
+
72
+
73
+ class Outputs(OutputModel):
74
+ volume: float = Field(units="cm^3")
75
+
76
+
77
+ @simulation(name="volume-of-sphere", inputs=Inputs, outputs=Outputs)
78
+ def run(inputs: Inputs, context: RunContext) -> Outputs:
79
+ path = context.artifact("trace.txt", "Calculation trace")
80
+ path.write_text("...", encoding="utf-8")
81
+ return Outputs(volume=...)
82
+ ```
83
+
84
+ The kebab-case `name` is the compute identity. Optional decorator metadata (`cpu`, `memory`, `timeout`) is recorded in schema/manifest and not enforced locally.
85
+
86
+ `validate` checks load, decorator, signature, and schema only — not physics and not `example.input.json`.
87
+
88
+ Walkthrough with split logic: [`examples/volume-of-sphere/`](examples/volume-of-sphere/).
89
+
90
+ ## CLI
91
+
92
+ | Command | What it does |
93
+ | --- | --- |
94
+ | `matprops init [dir]` | Scaffold a project |
95
+ | `matprops validate` | Check the entrypoint contract |
96
+ | `matprops schema [--output-dir DIR]` | Print schemas, or write `input.schema.json` / `output.schema.json` |
97
+ | `matprops run --input …` | Run locally |
98
+ | `matprops login` | Sign in via the web app and store credentials |
99
+ | `matprops logout` | Revoke and delete stored credentials |
100
+ | `matprops whoami` | Show the current CLI identity |
101
+ | `matprops package [--output PATH]` | Validate and write an uploadable zip to `dist/<name>.zip` |
102
+ | `matprops publish` | Package the project and POST it to sim-server |
103
+
104
+ `--input` is a file path, or inline JSON if the trimmed value starts with `{` or `[`:
105
+
106
+ ```bash
107
+ matprops run --input '{"var1": 1, "var2": 2}'
108
+ ```
109
+
110
+ Each run writes a timestamped folder under `.run-results/` (UTC, millisecond stamp, e.g. `.run-results/2026-09-01T15-11-22-123Z/`) with `outputs.json`, `manifest.json`, and `artifacts/`. `--output-dir` changes that parent directory.
111
+
112
+ Add `.run-results/` to gitignore.
113
+
114
+ ## Packaging and publishing
115
+
116
+ `package` validates the contract in your environment (where your `requirements.txt` dependencies are installed), then zips the project directory together with a generated `manifest.json` holding the simulation name, entrypoint, input/output JSON Schema and runtime hints. It skips `.git`, virtualenvs, `.run-results`, `dist`, caches, `*.pyc`, `.DS_Store` and root-level `example.input*.json` files. The zip is written to `dist/<name>.zip` (or `--output`) and is byte-for-byte reproducible for identical code.
117
+
118
+ The platform only accepts zips that contain this manifest: it reads the contract from `manifest.json` instead of importing your code, so uploads are validated instantly regardless of which packages the simulation needs. Upload the zip in the web UI, or let `publish` do it for you. Either way the image build installs your `requirements.txt` and re-derives the contract to confirm the manifest.
119
+
120
+ `publish` runs the same packaging step and POSTs the bundle to `{MATPROPS_API_URL}/simulation-function-versions` (default `https://api.matprops.com`). Authenticate with `matprops login`, `MATPROPS_API_KEY`, or `--api-key`. Override the URL with `MATPROPS_API_URL` or `--url`.
121
+
122
+ Add `dist/` to gitignore.
123
+
124
+ ## Releasing
125
+
126
+ PyPI project name is `matprops-sdk` (`matprops` is taken). Versions live in both `pyproject.toml` (`[project].version`) and `src/matprops_sdk/__init__.py` (`__version__`); bump them together.
127
+
128
+ Do **not** tag releases as `v1`, `v13`, or other `v*` integers — those tags are used by the production deploy workflow. SDK tags are `sdk-vX.Y.Z` only.
129
+
130
+ ### One-time setup
131
+
132
+ 1. Create a [pypi.org](https://pypi.org/account/register) account with 2FA (and optionally a separate [test.pypi.org](https://test.pypi.org) account).
133
+ 2. In GitHub: **Settings → Environments** → create `pypi` (URL `https://pypi.org/project/matprops-sdk/`) and optionally `testpypi`. Required reviewers are recommended on `pypi`.
134
+ 3. On PyPI, add a [pending trusted publisher](https://pypi.org/manage/account/publishing/):
135
+ - Project name: `matprops-sdk`
136
+ - Owner: `rileyhanus`
137
+ - Repository: `matprops`
138
+ - Workflow filename: `python-sdk-publish.yml`
139
+ - Environment name: `pypi`
140
+ 4. Repeat on TestPyPI with environment `testpypi` if you want a dry run.
141
+
142
+ A typo in the workflow name or environment is a silent 403 on first upload.
143
+
144
+ ### Publish a version
145
+
146
+ 1. Bump both version fields, merge to `main`.
147
+ 2. From `python/matprops-sdk`: `pip install -e ".[dev]" build twine`, then `ruff check . && pytest`, `python -m build`, and `python -m twine check dist/*`.
148
+ 3. Tag the merged main SHA and push:
149
+
150
+ ```bash
151
+ git tag -a sdk-v0.1.0 -m "matprops-sdk 0.1.0"
152
+ git push origin sdk-v0.1.0
153
+ ```
154
+
155
+ 4. Watch **Actions → Publish Python SDK**. Approve the `pypi` environment if reviewers are required.
156
+
157
+ The first successful trusted-publisher run creates `https://pypi.org/project/matprops-sdk/` and uploads that version. PyPI versions are immutable; a bad upload means yank and ship the next version.
158
+
159
+ Optional TestPyPI dry run: **Actions → Publish Python SDK → Run workflow** with target `testpypi`, then:
160
+
161
+ ```bash
162
+ python -m pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ matprops-sdk
163
+ ```
164
+
165
+ A first upload can also be done from a laptop with an account-scoped API token (`python -m twine upload dist/*`; username `__token__`). Later releases should use the `sdk-v*` tag so CI and Trusted Publishing stay the path of record.
@@ -0,0 +1,141 @@
1
+ # Matprops SDK
2
+
3
+ Local toolkit for typed material simulations: validate the contract, emit JSON Schema, run on your machine, and package or publish a zip to sim-server.
4
+
5
+ Requires Python 3.11+.
6
+
7
+ ```bash
8
+ python -m pip install matprops-sdk
9
+ matprops init my-sim
10
+ cd my-sim
11
+ matprops validate
12
+ matprops run --input example.input.json
13
+ matprops package # dist/<name>.zip, upload it in the web UI
14
+ matprops publish # or package + upload in one step (needs login)
15
+ ```
16
+
17
+ From a clone of this repo, install an editable copy with tests and lint:
18
+
19
+ ```bash
20
+ python -m pip install -e ".[dev]"
21
+ ```
22
+
23
+ `init` writes `simulation.py`, `pyproject.toml`, and `example.input.json` (it will not overwrite existing files). Entrypoint defaults to `[tool.matprops] entrypoint = "simulation:run"`; override with `--entrypoint`.
24
+
25
+ ## CLI login
26
+
27
+ `matprops login` opens the Matprops web app (or prints a URL) so you can sign in and approve the CLI. Temporary credentials are stored in `~/.config/matprops/credentials.json` (`chmod 600`).
28
+
29
+ ```bash
30
+ matprops login
31
+ matprops whoami
32
+ matprops logout
33
+ ```
34
+
35
+ Defaults are production: `https://matprops.com` and `https://api.matprops.com`. Override with `MATPROPS_APP_URL` / `MATPROPS_API_URL` or `--app-url` / `--api-url`. For the local stack use `http://localhost:3000` and `http://localhost:4000`; for the shared dev environment use `https://dev.matprops.com` and `https://api.dev.matprops.com`. Use `--no-browser` on a remote machine and open the printed URL locally.
36
+
37
+ ## Simulation
38
+
39
+ Use Pydantic models and `@simulation`. Sibling modules are importable as long as filenames are valid Python (`my_logic.py`, not `my-logic.py`).
40
+
41
+ ```python
42
+ from matprops_sdk import Field, InputModel, OutputModel, RunContext, simulation
43
+
44
+
45
+ class Inputs(InputModel):
46
+ radius: float = Field(gt=0, units="cm")
47
+
48
+
49
+ class Outputs(OutputModel):
50
+ volume: float = Field(units="cm^3")
51
+
52
+
53
+ @simulation(name="volume-of-sphere", inputs=Inputs, outputs=Outputs)
54
+ def run(inputs: Inputs, context: RunContext) -> Outputs:
55
+ path = context.artifact("trace.txt", "Calculation trace")
56
+ path.write_text("...", encoding="utf-8")
57
+ return Outputs(volume=...)
58
+ ```
59
+
60
+ The kebab-case `name` is the compute identity. Optional decorator metadata (`cpu`, `memory`, `timeout`) is recorded in schema/manifest and not enforced locally.
61
+
62
+ `validate` checks load, decorator, signature, and schema only — not physics and not `example.input.json`.
63
+
64
+ Walkthrough with split logic: [`examples/volume-of-sphere/`](examples/volume-of-sphere/).
65
+
66
+ ## CLI
67
+
68
+ | Command | What it does |
69
+ | --- | --- |
70
+ | `matprops init [dir]` | Scaffold a project |
71
+ | `matprops validate` | Check the entrypoint contract |
72
+ | `matprops schema [--output-dir DIR]` | Print schemas, or write `input.schema.json` / `output.schema.json` |
73
+ | `matprops run --input …` | Run locally |
74
+ | `matprops login` | Sign in via the web app and store credentials |
75
+ | `matprops logout` | Revoke and delete stored credentials |
76
+ | `matprops whoami` | Show the current CLI identity |
77
+ | `matprops package [--output PATH]` | Validate and write an uploadable zip to `dist/<name>.zip` |
78
+ | `matprops publish` | Package the project and POST it to sim-server |
79
+
80
+ `--input` is a file path, or inline JSON if the trimmed value starts with `{` or `[`:
81
+
82
+ ```bash
83
+ matprops run --input '{"var1": 1, "var2": 2}'
84
+ ```
85
+
86
+ Each run writes a timestamped folder under `.run-results/` (UTC, millisecond stamp, e.g. `.run-results/2026-09-01T15-11-22-123Z/`) with `outputs.json`, `manifest.json`, and `artifacts/`. `--output-dir` changes that parent directory.
87
+
88
+ Add `.run-results/` to gitignore.
89
+
90
+ ## Packaging and publishing
91
+
92
+ `package` validates the contract in your environment (where your `requirements.txt` dependencies are installed), then zips the project directory together with a generated `manifest.json` holding the simulation name, entrypoint, input/output JSON Schema and runtime hints. It skips `.git`, virtualenvs, `.run-results`, `dist`, caches, `*.pyc`, `.DS_Store` and root-level `example.input*.json` files. The zip is written to `dist/<name>.zip` (or `--output`) and is byte-for-byte reproducible for identical code.
93
+
94
+ The platform only accepts zips that contain this manifest: it reads the contract from `manifest.json` instead of importing your code, so uploads are validated instantly regardless of which packages the simulation needs. Upload the zip in the web UI, or let `publish` do it for you. Either way the image build installs your `requirements.txt` and re-derives the contract to confirm the manifest.
95
+
96
+ `publish` runs the same packaging step and POSTs the bundle to `{MATPROPS_API_URL}/simulation-function-versions` (default `https://api.matprops.com`). Authenticate with `matprops login`, `MATPROPS_API_KEY`, or `--api-key`. Override the URL with `MATPROPS_API_URL` or `--url`.
97
+
98
+ Add `dist/` to gitignore.
99
+
100
+ ## Releasing
101
+
102
+ PyPI project name is `matprops-sdk` (`matprops` is taken). Versions live in both `pyproject.toml` (`[project].version`) and `src/matprops_sdk/__init__.py` (`__version__`); bump them together.
103
+
104
+ Do **not** tag releases as `v1`, `v13`, or other `v*` integers — those tags are used by the production deploy workflow. SDK tags are `sdk-vX.Y.Z` only.
105
+
106
+ ### One-time setup
107
+
108
+ 1. Create a [pypi.org](https://pypi.org/account/register) account with 2FA (and optionally a separate [test.pypi.org](https://test.pypi.org) account).
109
+ 2. In GitHub: **Settings → Environments** → create `pypi` (URL `https://pypi.org/project/matprops-sdk/`) and optionally `testpypi`. Required reviewers are recommended on `pypi`.
110
+ 3. On PyPI, add a [pending trusted publisher](https://pypi.org/manage/account/publishing/):
111
+ - Project name: `matprops-sdk`
112
+ - Owner: `rileyhanus`
113
+ - Repository: `matprops`
114
+ - Workflow filename: `python-sdk-publish.yml`
115
+ - Environment name: `pypi`
116
+ 4. Repeat on TestPyPI with environment `testpypi` if you want a dry run.
117
+
118
+ A typo in the workflow name or environment is a silent 403 on first upload.
119
+
120
+ ### Publish a version
121
+
122
+ 1. Bump both version fields, merge to `main`.
123
+ 2. From `python/matprops-sdk`: `pip install -e ".[dev]" build twine`, then `ruff check . && pytest`, `python -m build`, and `python -m twine check dist/*`.
124
+ 3. Tag the merged main SHA and push:
125
+
126
+ ```bash
127
+ git tag -a sdk-v0.1.0 -m "matprops-sdk 0.1.0"
128
+ git push origin sdk-v0.1.0
129
+ ```
130
+
131
+ 4. Watch **Actions → Publish Python SDK**. Approve the `pypi` environment if reviewers are required.
132
+
133
+ The first successful trusted-publisher run creates `https://pypi.org/project/matprops-sdk/` and uploads that version. PyPI versions are immutable; a bad upload means yank and ship the next version.
134
+
135
+ Optional TestPyPI dry run: **Actions → Publish Python SDK → Run workflow** with target `testpypi`, then:
136
+
137
+ ```bash
138
+ python -m pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ matprops-sdk
139
+ ```
140
+
141
+ A first upload can also be done from a laptop with an account-scoped API token (`python -m twine upload dist/*`; username `__token__`). Later releases should use the `sdk-v*` tag so CI and Trusted Publishing stay the path of record.
@@ -0,0 +1 @@
1
+ {"num1": 1.5, "num2": 2.5}
@@ -0,0 +1,8 @@
1
+ [project]
2
+ name = "matprops-example-add-numbers"
3
+ version = "0.1.0"
4
+ requires-python = ">=3.11"
5
+ dependencies = ["matprops-sdk"]
6
+
7
+ [tool.matprops]
8
+ entrypoint = "simulation:run"
@@ -0,0 +1,15 @@
1
+ from matprops_sdk import Field, InputModel, OutputModel, simulation
2
+
3
+
4
+ class Inputs(InputModel):
5
+ num1: float = Field(description="First number", units="unitless")
6
+ num2: float = Field(description="Second number", units="unitless")
7
+
8
+
9
+ class Outputs(OutputModel):
10
+ sum: float = Field(description="Sum of the two numbers", units="unitless")
11
+
12
+
13
+ @simulation(name="add-numbers", inputs=Inputs, outputs=Outputs)
14
+ def run(inputs: Inputs) -> Outputs:
15
+ return Outputs(sum=inputs.num1 + inputs.num2)
@@ -0,0 +1,8 @@
1
+ {
2
+ "k_matrix": 0.2,
3
+ "k_inclusion": 30.0,
4
+ "volume_fraction": 0.3,
5
+ "grid_size": 800,
6
+ "max_iterations": 60000,
7
+ "seed": 42
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "k_matrix": 0.2,
3
+ "k_inclusion": 30.0,
4
+ "volume_fraction": 0.3,
5
+ "grid_size": 32,
6
+ "max_iterations": 50,
7
+ "seed": 42
8
+ }
@@ -0,0 +1,8 @@
1
+ [project]
2
+ name = "matprops-example-composite-thermal-conductivity"
3
+ version = "0.1.0"
4
+ requires-python = ">=3.11"
5
+ dependencies = ["matprops-sdk"]
6
+
7
+ [tool.matprops]
8
+ entrypoint = "simulation:run"
@@ -0,0 +1,156 @@
1
+ import numpy as np
2
+ from solver import (
3
+ conductivity_field,
4
+ effective_conductivity,
5
+ hashin_shtrikman_2d,
6
+ random_microstructure,
7
+ solve_temperature,
8
+ )
9
+
10
+ from matprops_sdk import (
11
+ Field,
12
+ InputModel,
13
+ OutputModel,
14
+ RunContext,
15
+ simulation,
16
+ )
17
+
18
+
19
+ class Inputs(InputModel):
20
+ k_matrix: float = Field(
21
+ default=0.2,
22
+ gt=0,
23
+ units="W/m·K",
24
+ description="Thermal conductivity of the continuous matrix",
25
+ )
26
+ k_inclusion: float = Field(
27
+ default=30.0,
28
+ gt=0,
29
+ units="W/m·K",
30
+ description="Thermal conductivity of the dispersed inclusions",
31
+ )
32
+ volume_fraction: float = Field(
33
+ default=0.3,
34
+ ge=0,
35
+ le=1,
36
+ units="unitless",
37
+ description="Target inclusion volume fraction",
38
+ )
39
+ grid_size: int = Field(
40
+ default=800,
41
+ ge=8,
42
+ le=1024,
43
+ units="unitless",
44
+ description="Number of cells along each side of the unit square",
45
+ )
46
+ max_iterations: int = Field(
47
+ default=60_000,
48
+ ge=1,
49
+ le=500_000,
50
+ units="unitless",
51
+ description="Jacobi sweeps; raise this (and grid_size) to spend more compute",
52
+ )
53
+ seed: int = Field(
54
+ default=42,
55
+ ge=0,
56
+ units="unitless",
57
+ description="RNG seed for the random microstructure",
58
+ )
59
+
60
+
61
+ class Outputs(OutputModel):
62
+ k_effective: float = Field(
63
+ units="W/m·K",
64
+ description="Effective in-plane conductivity from the solved heat flux",
65
+ )
66
+ hashin_shtrikman_lower: float = Field(
67
+ units="W/m·K",
68
+ description="2D Hashin–Shtrikman lower bound for the same mixture",
69
+ )
70
+ hashin_shtrikman_upper: float = Field(
71
+ units="W/m·K",
72
+ description="2D Hashin–Shtrikman upper bound for the same mixture",
73
+ )
74
+ volume_fraction_realized: float = Field(
75
+ units="unitless",
76
+ description="Inclusion fraction actually placed on the grid",
77
+ )
78
+ residual: float = Field(
79
+ units="K",
80
+ description="Max temperature change on the last Jacobi sweep",
81
+ )
82
+
83
+
84
+ @simulation(
85
+ name="composite-thermal-conductivity",
86
+ inputs=Inputs,
87
+ outputs=Outputs,
88
+ cpu=1,
89
+ memory="2GiB",
90
+ timeout="10m",
91
+ )
92
+ def run(inputs: Inputs, context: RunContext) -> Outputs:
93
+ context.progress(0, stage="generate microstructure", stage_index=0, stage_count=3)
94
+
95
+ inclusion = random_microstructure(
96
+ inputs.grid_size,
97
+ inputs.volume_fraction,
98
+ inputs.seed,
99
+ )
100
+ conductivity = conductivity_field(
101
+ inclusion,
102
+ inputs.k_matrix,
103
+ inputs.k_inclusion,
104
+ )
105
+ volume_fraction_realized = float(inclusion.mean())
106
+
107
+ context.progress(5, stage="solve heat equation", stage_index=1, stage_count=3)
108
+
109
+ def on_progress(iteration: int, total: int, _residual: float) -> None:
110
+ # 5%–95% is the solver; leave the last 5% for flux and artifacts.
111
+ percent = 5.0 + 90.0 * iteration / total
112
+ context.progress(
113
+ percent, stage="solve heat equation", stage_index=1, stage_count=3
114
+ )
115
+
116
+ temperature, residual = solve_temperature(
117
+ conductivity,
118
+ inputs.max_iterations,
119
+ progress=on_progress,
120
+ )
121
+
122
+ context.progress(
123
+ 95, stage="compute effective conductivity", stage_index=2, stage_count=3
124
+ )
125
+
126
+ k_effective = effective_conductivity(conductivity, temperature)
127
+ hs_lower, hs_upper = hashin_shtrikman_2d(
128
+ inputs.k_matrix,
129
+ inputs.k_inclusion,
130
+ volume_fraction_realized,
131
+ )
132
+
133
+ np.savetxt(
134
+ context.artifact("microstructure.csv", "Inclusion map (1) vs matrix (0)"),
135
+ inclusion.astype("int8"),
136
+ fmt="%d",
137
+ delimiter=",",
138
+ )
139
+ np.savetxt(
140
+ context.artifact("temperature.csv", "Solved temperature field (K, relative)"),
141
+ temperature,
142
+ fmt="%.6e",
143
+ delimiter=",",
144
+ )
145
+
146
+ context.progress(
147
+ 100, stage="compute effective conductivity", stage_index=2, stage_count=3
148
+ )
149
+
150
+ return Outputs(
151
+ k_effective=k_effective,
152
+ hashin_shtrikman_lower=hs_lower,
153
+ hashin_shtrikman_upper=hs_upper,
154
+ volume_fraction_realized=volume_fraction_realized,
155
+ residual=residual,
156
+ )