Metadata-Version: 2.4
Name: med2limit
Version: 0.0.3
Summary: Convert Code_Aster MED/RMED simulation files to LIMIT .linp / .lui input format
Author-email: Dorian Nezzar <dorian.nezzar@simvia.tech>
License-Expression: MIT
Keywords: med,rmed,code_aster,limit,fea,fatigue
Requires-Python: <3.14,>=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: medcoupling>=9.15
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Dynamic: license-file

<p align="center"><img src="https://raw.githubusercontent.com/simvia-tech/med2limit/refs/heads/main/logo/logo_med_coupling.png" alt="logo" width="50%"></p>

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
![PyPI - Version](https://img.shields.io/pypi/v/med2limit)
[![CI](https://github.com/simvia-tech/med2limit/actions/workflows/ci.yml/badge.svg)](https://github.com/simvia-tech/med2limit/actions/workflows/ci.yml)

# med2limit
Convert Code_Aster MED/RMED simulation results into LIMIT `.linp` / `.lui` input files for fatigue analysis.

## Features

- Shell workflows (DKT elements: S3, S4) with orientation (REPLO/CARCOQUE) handling
- Linear solid workflows (C3D8 / HEXA8, C3D6 / PENTA6) with validated LIMIT node ordering
- Multi-step / multi-increment displacement and stress transfer
- Optional shell orientation file, or read directly from `IMPR_CONCEPT` embedded result file

## Requirement
- Python 3.9 - 3.13
- [Git LFS](https://git-lfs.com) (only needed if you clone the repository to access the example files)

## Installation
Install med2limit with pip into a virtual python environnement (venv):

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install med2limit
```
## Code_aster Requirement
- Identify weld groups as Group_NO (not Group_MA), 1 node set per weld and duplicated node set and to have right and left weld node set.
- For shell element, extract top/bottom stresses as:
```bash
#Ensure to name the concept "SIEF_SUP" and "SIEF_INF"
SIEF_SUP=POST_CHAMP(RESULTAT=RESU,
                    EXTR_COQUE=_F(NOM_CHAM='SIEF_ELNO',
                                  NUME_COUCHE=1,
                                  NIVE_COUCHE='SUP',),);

SIEF_INF=POST_CHAMP(RESULTAT=RESU,
                    EXTR_COQUE=_F(NOM_CHAM='SIEF_ELNO',
                                  NUME_COUCHE=1,
                                  NIVE_COUCHE='INF',),);
```
- For shell element, extract orientation/tichkness as:
```bash
IMPR_CONCEPT(FORMAT='MED',
             UNITE=80, --> Same unit as your results or in a dedicated file
             CONCEPT=(_F(CARA_ELEM=Elem,
                         REPERE_LOCAL='ELEM',
                         MODELE=Modell,),),)                                  
```
## Usage

### Command line
From 01_exemple in folder:
```bash
med2limit/exemples/01_exemple
```

```bash
med2limit 01_exemple.rmed output.linp output.lui --groups "Shell1,Shell2" --nsets "WeldNO"
```

With separate orientation file:

```bash
med2limit 01_exemple.rmed output.linp output.lui 01_carcoc.rmed --groups "Shell1,Shell2" --nsets "WeldNO"
```

### Set classification in LIMIT

LIMIT decides how to file an imported set from its name and from whether it
carries a section:

| Group name | LIMIT classification |
|---|---|
| starts with `PROF_` | Profile Set |
| starts with `SW_` | Solid Weld Generation Elset |
| starts with `solset` / `surfset` | Property Set (gets a `*Section`) |
| anything else | Other Elset / Other Nset |

`PROF_` and `SW_` are matched literally, underscore included, so those
underscores are preserved while the rest of the name is normalized
(`PROF_POA_COR_1a` becomes `PROF_POACOR1a`).

Only the property groups get a `*Section`: they are the ones with a material
and a thickness. Every other `GROUP_MA` (construction groups, boundary
conditions, weld lines) stays a plain elset. The converter prints the list of
elsets it left without a section — check it, because an elset that needed a
property but does not follow the naming convention reaches LIMIT without one.

Both conventions are overridable when a study uses different names:

```bash
med2limit model.rmed out.linp out.lui \
  --limit-prefixes "PROF_,SW_" --property-prefixes "solset,surfset"
```

Property prefixes are matched case-insensitively; the LIMIT prefixes are not.
Omitting an option keeps the built-in convention shown in the table above.
# 01_exemple
<img src="https://raw.githubusercontent.com/simvia-tech/med2limit/main/examples/images/01_exemple_LIMIT.png" width="50%">
Code_aster Shell-Shell geometry successfully imported in LIMIT Software


# 02_exemple
```bash
med2limit/exemples/02_exemple
```
<img src="https://raw.githubusercontent.com/simvia-tech/med2limit/main/examples/images/02_exemple_LIMIT.png" width="50%">
Code_aster Solid-Shell geometry successfully imported in LIMIT Software

### Python API

```python
from med2limit import MEDToLimitConverter

conv = MEDToLimitConverter(
    med_filename="LIMIT1.rmed",
    linp_filename="out.linp",
    lui_filename="out.lui",
    active_groups=["Shell1", "Shell2"],
    active_nsets=["WeldNO"],
)
conv.convert()
```

## Package layout

```
med2limit/
├── element_types.py   # MED↔LIMIT type mapping + helpers (pure)
├── reader.py          # MED file open + field lookup
├── mesh.py            # nodes, elements, GROUP_MA, GROUP_NO
├── fields.py          # DEPL + SIEF over all timesteps
├── orientation.py     # REPLO + CARCOQUE (embedded or separate)
├── filter.py          # active group selection + shell metadata 
├── result_mapper.py   # per-timestep stress/displacement mapping
├── writer.py          # .linp + .lui output
├── converter.py       # orchestrator (step_1 .. step_6 + convert)
└── cli.py             # CLI + in-script config
```

## Testing

```bash
pytest                              # all tests
pytest tests/test_element_types.py  # one module
```

## Publishing a new version

Releases are fully automated via GitHub Actions and PyPI Trusted Publishing. To publish a new version:

1. Update the `version` field in `pyproject.toml` (e.g. `1.2.0`).
2. Add a `## [1.2.0]` section to `CHANGELOG.md` describing the changes. This section is mandatory: it is extracted automatically and used as the GitHub release notes.
3. Merge these changes into `main`.
4. Create and push a tag matching the version, from the merged commit on `main`:

```bash
git checkout main && git pull
git tag 1.2.0
git push origin 1.2.0
```

The `Release` workflow then runs the full CI suite (tests + build), and if everything passes, builds the distributions, publishes them to PyPI and creates the GitHub release with the changelog notes attached.

The workflow will abort if the tag does not point to a commit on `main`, if the tag does not match the version in `pyproject.toml`, or if no matching section exists in `CHANGELOG.md`. No PyPI token is needed: publication uses OIDC Trusted Publishing.

## Known limitations

- Quadratic solids (C3D10, C3D15, C3D20) — node ordering not yet validated in LIMIT
- Shell elsets with mixed thicknesses use the most-frequent value (with warning)

## Acknowledgments

Special thanks to Tobias and Nikolaus for their feedback as early adopters
and their patience during the iterative development of the converter.
