Metadata-Version: 2.4
Name: pymats
Version: 0.1.3
Summary: A python module for handling materials
Author-email: Sebastian Mau <klixz09@gmail.com>
License-Expression: MIT
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: numpy<3,>=1.24
Requires-Dist: scipy<2,>=1.10
Requires-Dist: pandas<4,>=2
Requires-Dist: pydantic<3,>=2.7
Requires-Dist: pydantic-settings<3,>=2
Requires-Dist: pymongo<5,>=4.6
Requires-Dist: requests<3,>=2.31
Requires-Dist: PyYAML<7,>=6
Provides-Extra: api
Requires-Dist: fastapi<1,>=0.115; extra == "api"
Requires-Dist: uvicorn[standard]<1,>=0.30; extra == "api"
Requires-Dist: pydantic[email]<3,>=2.7; extra == "api"
Requires-Dist: aiosmtplib<6,>=3; extra == "api"
Requires-Dist: PyJWT<3,>=2.8; extra == "api"
Requires-Dist: pytz>=2024; extra == "api"
Provides-Extra: ml
Requires-Dist: scikit-learn<2,>=1.4; extra == "ml"
Requires-Dist: skops<1,>=0.10; extra == "ml"
Provides-Extra: pma
Requires-Dist: docxtpl<1,>=0.19; extra == "pma"
Requires-Dist: jinja2<4,>=3.1; extra == "pma"
Requires-Dist: fastapi<1,>=0.115; extra == "pma"
Provides-Extra: excel
Requires-Dist: openpyxl<4,>=3.1; extra == "excel"
Provides-Extra: dev
Requires-Dist: pytest<10,>=8; extra == "dev"
Requires-Dist: httpx<1,>=0.27; extra == "dev"
Requires-Dist: build<2,>=1.2; extra == "dev"
Provides-Extra: gcs
Requires-Dist: google-cloud-storage<4,>=2; extra == "gcs"

# PyMats

PyMats provides material records, temperature/thickness-dependent properties, a FastAPI service, and a Next.js browser application. Authentication and personal-user workflows are deferred.

## Python

Install the core package with `pip install pymats`. Repository development uses `pip install -e '.[api,ml,dev]'`.

```python
from pymats import Material, MaterialFactory

# Construction is local; it performs no database lookup.
material = Material(Identifier="LOCAL", EO_overwritten=210_000.0)
assert material.EO == 210_000.0

# Explicitly fetch a complete record through the configured backend.
material = MaterialFactory.from_config({
    "Identifier": "SA-723-2-2",
    "Collection": "asme",
})
```

Optional dependencies are grouped as `api`, `ml`, `pma`, `excel`, `gcs`, and `dev`. Approximation models require `pymats[ml]`; neural models additionally require a compatible `ai-edge-litert` or `tflite-runtime` installation. Legacy pickle/joblib models and scalers are rejected. Convert trusted legacy artifacts to skops in an isolated migration environment and validate their predictions before ingestion.

## Configuration and data

`PYMATS_CONFIG` selects a YAML file containing a `pymats` section. Otherwise an existing `~/.pymats/config.yaml` is read, with API client defaults when absent. Import does not create a configuration file. Calling `pymats.config.create_default_config()` explicitly creates one. `DB_*` variables override database settings.

```yaml
pymats:
  api_url: http://localhost:8001
  database:
    type: api
  logging:
    file: null
```

The server requires a direct `mongodb` or `atlas` backend, and an `api` configuration section. `configs/config.example.yaml` is a nonsecret local container example. File logging is optional. Custom Python plugins execute only when `pymats.register_custom_materials()` is called explicitly; register them before loading custom classes. Unknown material classes are errors.

Property queries reject out-of-domain values by default. Single-axis and single-point tables are supported within their supplied domain; conflicting duplicate points and nonfinite tables fail validation. Explicitly setting a `MechanicalProperty`'s `extrapolation='nearest'` opts into nearest-value extrapolation. Property status, source reference, units, and bounds appear in `material.PropertyStatus`. Reduced previews are for listings; calculations need complete property records. Raw source fields remain available on the model and are not a persistence payload.

Template files are external assets, not bundled wheel data. Configure `pymats.assets.root` for PMA rendering and `api.assets.root` for serving application assets; repository containers copy the tracked `assets/` directory. PMA generation is unavailable. Existing specifications require `pma-manifest.json` under `api.materials.source_pma_dir`:

```json
{
  "en/1.0571/2": {
    "path": "specifications/1.0571-revision2.pdf",
    "sha256": "replace-with-the-file-sha256"
  }
}
```

The key is collection/identifier/revision. Paths must resolve inside that root to a PDF whose contents match the checksum. Fuzzy filename selection is disabled.

## Engineering curves and solver exports

Material modulus and strength inputs are MPa; density is kg/m³. `ElongationBreak.long` is stored in **percent** and converted to a fraction when building stress-strain curves. Plotting curves use dimensionless total strain and MPa.

Solver downloads use **m, kg, s, Pa**, require a positive numeric `Mid`, positive density, valid modulus/strengths, and `-1 < PoissonsRatio < 0.5`. Perfect plasticity keeps the yield stress constant. Linear-hardening plots and exports approximate the curve from Young’s modulus, yield strength, tensile strength, and elongation at break. Solver plastic strain is derived as total strain minus stress divided by Young’s modulus; no additional database field is required. Unsupported allowable-stress rules fail explicitly.

The implementation uses [Ansys plasticity tables](https://ansyshelp.ansys.com/public/Views/Secured/corp/v242/en/ans_cmd/Hlp_C_TB.html), [LS-DYNA MAT24 curve references](https://lsdyna.ansys.com/mat24-table/), and [Abaqus true-stress/plastic-strain conventions](https://3dswym.3dexperience.3ds.com/post/simulia-community/converting-from-engineering-stress-strain-to-true-stress-strain_4070). Numeric/card regression checks do not replace import validation in the intended solver or verification against applicable material standards.

Similarity scores rank candidates at a shared design point. They are deterministic, bounded, and do not establish engineering equivalence. Missing or out-of-domain candidate properties fail explicitly.

## API contracts

- `GET /material?query=SA&limit=10&offset=0`: partial, case-insensitive search; returns `mids`. `limit` is 1–1000; `collections` can be repeated.
- `GET /material/{identifier}?collection=asme`: evaluated material. `equivalents=true` adds ranked candidates.
- `GET /material/{mid}?numeric_mid=true&raw=true`: raw record by numeric MID. Identifier lookup also supports `raw=true`.
- `GET /collections?action=materials`: previews with `Keys` for data fields and `Labels` for headings.
- `GET /collections?action=records&collections=asme&include_property_data=true`: complete raw collection records. Raw responses use MongoDB Extended JSON to retain binary artifacts and ObjectIds. APILoader decodes this representation.
- `GET /material/{identifier}/properties?collection=asme`: bounded property samples.
- `GET /material/{identifier}/cae-model?collection=asme&approach=linearelastic&file=true&application=2`: solver download; applications 1/2/3 are Ansys/Abaqus/LS-DYNA.
- `GET /health/ready`: server database readiness.

Metadata saves accept only `Name`, `Synopsis`, `Applications`, `Notes`, and `PurchaseOrderText`. They require the last observed `expected_revision` (zero for a legacy record) and return the saved material with incremented `Revision`. A stale edit returns 409; absent records return 404. Identity, source properties, and engineering inputs require a separate ingestion workflow. The existing authenticated write entry point remains deferred along with user management.

## Running and checking

```sh
python -m pytest -q
cd pymats-app
npm ci
npm run typecheck
npm run build
```

The Python suite uses temporary settings and mocked repositories/HTTP; it does not read home credentials or contact live services.

```sh
# Built images, no source mounts. Starts an empty local MongoDB volume.
docker compose up --build --wait
# Development reload with source mounts:
docker compose -f docker-compose.yaml -f docker-compose.dev.yaml up --build
```

The browser is at `http://localhost:3001`, API at `http://localhost:8001`. Ingest material data separately. `NEXT_PUBLIC_API_URL` is a frontend **build-time** setting and must be reachable by the browser. The checked-in container configuration is for local development; use deployment-specific configuration, database storage, and networking for a hosted installation.

CI runs offline regressions, wheel installation, frontend typecheck/build, and a container readiness smoke check. Publication and deployment depend on those checks. VPS scripts check out the triggering revision; external VPS stack files, rollback, production material data, and solver imports still require separate validation. See [the audit backlog](jupyter/AUDIT_BACKLOG.md).
