Metadata-Version: 2.5
Name: yld.run
Version: 0.1.0
Summary: yld: programmatic problem authoring, solve requests and canonical `.yld` results.
License: MIT License
        
        Copyright (c) 2026 Sam Stanier
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.10
Provides-Extra: view
Requires-Dist: pyvista>=0.43; extra == 'view'
Description-Content-Type: text/markdown

# yld

`yld` is pronounced “yield”.

This is a private research project for a programmatic computational mechanics toolkit. The name
reflects both mechanical yielding and the idea that the toolkit yields results.

## Two packages

`yld` is delivered as two independently installable Python packages, and the split is a licence and
distribution boundary, not a convenience (`architecture/PLATFORM.md` §9):

| package | licence | distributed | contents |
|---|---|---|---|
| **`yld`** | MIT | yes | problem authoring, materials and spatial fields as declarations, the solve-request document, the execution client, the archive reader and the PyVista viewer. Pure Python: no native module, no mandatory dependency. |
| **`yld_core`** | proprietary | **no** | constitutive binding, meshing, assembly, the conic solve, adaptation, independent verification, field evaluation and archive writing, through one compiled extension (`yld_core._native`). |

A problem is authored and a solve is requested with `yld` alone; a numerical installation is
configured explicitly and is the only part that executes anything:

```python
import yld, yld_core
yld.use_executor(yld_core.NativeExecutor())          # explicit; no discovery, no environment variables

result = yld.solve(problem, yld.FELA_LB_Solver(order=3),
                   target=yld.Target.strength(), adapt=[yld.adapt.p(order=3)])
result.multiplier, result.verified                   # from the canonical `.yld` archive
result.save("analysis.yld"); result.show("cohesion")
```

`solve()` always submits a canonical `yld.solve-request/1` document to the configured executor and
always returns the same archive-backed result, so a local run and a service run are indistinguishable
to the caller.  With nothing configured it raises `yld.NoExecutorError` rather than choosing a
backend.

Build both artefacts (the private one only for a local numerical installation):

```bash
tools/yld-package public   --out-dir build/dist   # yld-<version>-py3-none-any.whl + sdist
tools/yld-package private  --out-dir build/dist   # yld_core-<version>-<platform>.whl
```

`tests/python/distribution_content_tests.py` builds and inspects the public artefacts (a positive
allowlist: no C++ sources, no native binaries, no experiments, no private modules), and
`tests/python/distribution_install_tests.py` installs each into a clean environment and checks what
it can and cannot do.

## Default production build

Use the CMake preset so build artefacts stay under `build/dev`. The `dev` preset is intentionally the default production-solver build: `Release`, Python enabled, experiments disabled. CMake obtains Eigen 3.4.0 and Catch2 v3.8.1 through pinned `FetchContent`; no system Eigen/Catch2 path is required for the normal development build.

System prerequisites: a C++20 compiler, CMake ≥ 3.20, Ninja or Make, **clang-format 21.1.8** (the pinned
version CI installs, because `code_format` is a test and its verdict must not depend on the image), Python 3 with development headers and `uv` (the test suite runs Python oracles
through `uv`), a Rust toolchain (Clarabel.cpp builds its Rust backend), and **header-only Boost**
(`libboost-dev`) for the exact geometric predicates in `yld_mesh`.

Canonical verification goes through the shared build/test wrappers, which bound memory on the
workstation (see `AGENTS.md`, "Build discipline"):

```bash
tools/yld-build --preset dev
tools/yld-test  --preset dev
```

For a stale or missing configure, refresh the cache first — `cmake --fresh --preset dev` — then
build and test through the wrappers again.

If dependency discovery or cache state gets stale, refresh the cache with `cmake --fresh --preset dev` rather than manually deleting the build tree.

Debug builds are opt-in only:

```bash
cmake --fresh --preset debug
tools/yld-build --preset debug
tools/yld-test  --preset debug
```

The compiled extension is written **inside the private package** (`yld_core/_native*.so`) rather than
into a build directory, because that is where an extension module has to be to be importable: a
package's `__path__` is its own directory.  One checkout therefore has one native extension — rebuild
for the preset you are testing.  No `PYTHONPATH` entry is needed to import it.

Do not use the debug preset for solver performance, FELA regression timing, or ordinary commit validation.

## Examples

`examples/ben_cutting_slope.ipynb` is an executable introduction to slope limit analysis through
the public Python API: gravity and strength-reduction targets, Bernstein lower and upper bounds
with independent verification, adaptation recipes, and deterministic and random spatial strength
fields. See `examples/README.md` for launch instructions.

## Testing

Routine development tests only the area a change touches. Catch2 tags and `ctest -R` are the
normal entry points:

```bash
# one whole test binary
./build/dev/tests/yld_mechanics_tests

# a Catch2 tag, e.g. the model just changed
./build/dev/tests/yld_mechanics_tests "[mohr_coulomb]"

# ctest tests selected by name
tools/yld-test --preset dev -R "mohr_coulomb|code_format"

# the Python suite only
tools/yld-test --preset dev -R "^python_|^bezier_member_vtk$|^parameter_archive_visualisation$"
```

The complete `tools/yld-test --preset dev` suite includes MFEM/Python integration tests and takes
about four minutes. It is **not** the commit gate: it runs in CI (`.github/workflows/ci.yml`) on every
push to `main` and on pull requests, against the production Release solver path.

The local commit hook is deliberately fast, because a slow hook teaches people to use
`--no-verify`:

```bash
git config core.hooksPath .githooks   # one-time setup
```

`.githooks/pre-commit` checks only what needs the working tree or is commit-specific —
`clang-format` on staged C++ files, a 5 MB per-file size guard against bulk artefacts, validation of
any staged experiment record, and a private-key scan. Bypass for work-in-progress commits with
`YLD_SKIP_HOOKS=1 git commit ...`.

Run the full suite locally before a substantial push, or when CI is unavailable:

```bash
tools/yld-test --preset dev
```
