diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..e1417d704 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,92 @@ +# AGENTS.md + +Guidance for AI coding agents (and humans) working on the Kratos ↔ GiD interface. +For installation and user-facing docs see [README.md](./README.md). + +## What this repo is + +A GiD *problemtype* (`kratos.gid/`) that lets users build Kratos Multiphysics models in GiD. It writes the Kratos input files (`.mdpa`, `ProjectParameters.json`, materials `.json`) and launches Kratos. + +- **Language:** Tcl/Tk on top of GiD's *customlib* framework. Data trees are XML (`.xml`, `.spd`). +- **Python** is used only in `kratos.gid/exec/MainKratos.py`, `scripts/Custom/python_writer.py` and the release tools. +- There is **no standalone build or test command**: the code runs inside GiD. + +## Layout + +| Path | Purpose | +|---|---| +| `kratos.gid/kratos.tcl` | Entry point: registers GiD events (`GiD_RegisterEvent`, e.g. `GiD_Event_LoadModelSPD`), version checks, model upgrade. | +| `kratos.gid/kratos.xml` | Problemtype metadata: version, `MinimumGiDVersion`, required pip packages. | +| `kratos.gid/kratos.spd` | Root data tree; `` and one `appLink` per application. | +| `kratos.gid/kratos.transform` | Rules applied when opening a model saved with a different `.spd` version. | +| `kratos.gid/apps//` | One folder per application (see below). | +| `kratos.gid/apps/Common/xml/` | Shared definitions (processes, solvers, results, intervals…) reused by apps. | +| `kratos.gid/scripts/Model/` | In-memory model: Element, Condition, Material, Process, Solver… | +| `kratos.gid/scripts/Writing/` | Generic writers for mdpa, submodelparts, materials, ProjectParameters, stages. | +| `kratos.gid/scripts/Controllers/` | Windows: preferences, application market, examples, tree injections. | +| `kratos.gid/scripts/Launch.tcl` | Execution modes (GiD python, pip, local compiled, docker) and dependency checks. | +| `kratos.gid/exec/` | Per-mode, per-OS launch scripts (`*.win.bat`, `*.unix.bat`) and `MainKratos.py`. | +| `kratos.gid/libs/` | Third-party Tcl libs — do not modify. | +| `tools/`, `dockers/` | Release packaging. | +| `dist/` | Release output (git-ignored) — never edit. | + +## Anatomy of an application (`apps//`) + +``` +app.json id, prefix, kratos_name, python_packages, script_files, start_script, + requirements (apps, minimum_gid_version), permissions, unique_names, write +start.tcl namespace ::; Init stores the app object and calls xml::Init / write::Init +xml/Main.spd Tree for this app (plus Parts.spd, Materials.spd, … included from it) +xml/*.xml Catalogues: Elements, Conditions, Materials, ConstitutiveLaws, Processes, Solvers, Strategies +xml/XmlController.tcl ::::xml — loads catalogues via Model::get*, CustomTree tweaks +write/write.tcl ::::write — mdpa writing (Init sets attributes from app.json) +write/writeProjectParameters.tcl ProjectParameters.json +examples/examples.xml Example list; each points to a proc in examples/*.tcl +images/ Icons and example thumbnails +``` + +Conventions: +- Every namespace registers itself with `Kratos::AddNamespace [namespace current]`. +- Sub-namespaces use `namespace path ::` to reach the app's helpers (`GetAttribute`, `GetUniqueName`, `GetWriteProperty`). +- Tree node names are prefixed with the app `prefix` (e.g. `STParts`, `FLBC`); use `unique_names` from `app.json` instead of hard-coding them. +- Any new `.tcl` file must be listed in `script_files` of `app.json`, otherwise it is not sourced. +- Reuse `apps/Common/xml/*` and the generic writers in `scripts/Writing/` before adding app-specific code. +- Launcher apps (`FluidLauncher`, `PfemLauncher`, `DEMLauncher`, `ThermicLauncher`) only route to other apps. + +### Adding a new application +1. Copy the structure of a similar app (e.g. `Fluid` or `Structural`) to `apps//`. +2. Choose a unique `prefix` and update `id`, `kratos_name`, `python_packages`, `unique_names`, `start_script`. +3. Add an `appLink` to `kratos.spd` (`public="1"` to show it in the market, `production="1"` to ship it in releases). +4. Add tests in the tester repo (see below). + +## Versioning — read before touching versions + +The Kratos version (currently `10.4.3`) is hard-coded in several places that must stay in sync: + +- `kratos.gid/kratos.xml` — `` and `` +- `kratos.gid/kratos.spd` — `` +- `kratos.gid/kratos.tcl` — `pip_packages_required` +- `README.md` — pip install commands +- `tools/create-release.bat`, `dockers/deploy.bat`, `dockers/create-release.sh` + +Search for the old version string across the repo when bumping it. + +**Model compatibility:** when a saved model's `.spd` version differs from `kratos.spd`, GiD runs the upgrade defined by `kratos.transform`. If you rename or remove tree nodes, values or conditions, add the corresponding rule to `kratos.transform`. Otherwise existing user models lose data. + +The minimum GiD version is `MinimumGiDVersion` in `kratos.xml`. Some `app.json` files declare older values; the global one is the effective minimum. + +## Testing + +- No unit tests in this repo. Integration tests live in [kratos-gid-tester](https://github.com/jginternational/kratos-gid-tester): it runs GiD batch files (`batchs//*.bch`) that build each example, write the Kratos input and, for `*_calculate` cases, run the simulation. +- CI: `.github/workflows/tester.yml`, image `fjgarate/kratos-tester`, self-hosted runner. It runs on push to `master` and on PRs labelled `safe-to-test`. +- Manual check: link `kratos.gid` into GiD's `problemtypes`, load the problemtype, open the relevant example, *Calculate*, and inspect the generated files in the model folder. +- Without GiD you can only review syntax and logic. Say so when reporting results instead of claiming the change was tested. + +## Rules + +- Do not edit `dist/`, `libs/`, or generated/ignored files (`exec/Kratos*`, `__pycache__`). +- `*.unix.bat` and `*.sh` must keep **LF** line endings; `*.win.bat` CRLF. +- Keep XML files UTF-8 and preserve each file's existing indentation (some use tabs, others spaces). +- Do not rename tree nodes, `n=` attributes or unique names without a `kratos.transform` rule. +- Use `Kratos::Log` for debug output rather than `W` in committed code. +- Release scripts (`tools/create-release.bat`) create and force-push tags: do not run them unless asked. diff --git a/README.md b/README.md index c650494ae..1b4b45278 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,106 @@ # KratosMultiphysics <-> GiD Interface -[![Codacy Badge](https://app.codacy.com/project/badge/Grade/36d3d305c87e4bb398bc87ea2e3b890e)](https://www.codacy.com/gh/KratosMultiphysics/GiDInterface/dashboard?utm_source=github.com&utm_medium=referral&utm_content=KratosMultiphysics/GiDInterface&utm_campaign=Badge_Grade) +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/36d3d305c87e4bb398bc87ea2e3b890e)](https://app.codacy.com/gh/KratosMultiphysics/GiDInterface/dashboard) [![Tester](https://github.com/KratosMultiphysics/GiDInterface/actions/workflows/tester.yml/badge.svg)](https://github.com/KratosMultiphysics/GiDInterface/actions/workflows/tester.yml) -The user interface of Kratos with [GiD](http://www.gidsimulation.com). - -If you need the latest stable release, launch your GiD, navigate to Data > Problemtype > Internet retrieve and download Kratos there. -Available for Linux. Windows, and macOS. - -If you need the developer version, you are on the right place. - -## First steps -* 1- Clone this repository, or install a stable [release](https://github.com/KratosMultiphysics/GiDInterface/releases) -* 2- Install the latest GiD developer version **(minimum 16.1.4d)** -> [Developer version](https://www.gidsimulation.com/gid-for-science/downloads/) -* 3- Navigate to GiD's problemtype folder and delete any previous kratos.gid - * Create there a link to our [kratos.gid](./kratos.gid/) downloaded in step 1 - * Windows: Simple shortcut to kratos.gid folder -* 4- Choose your execution mode: - * 4.1- **Default execution mode.** Use GiD's python: - * You don't need to install python. The program will detect if you have any pending package to install. - * If there's any missing package, use the GiD command line and execute: - - `-np- W [GiD_Python_PipInstall { $::Kratos::pip_packages_required } 1 ]` - * 4.1- To execute Kratos using the standard pip packages: - * Python version recommended: 3.8, 3.9, 3.10, 3.11, 3.12 - * Open a terminal and run - - Linux: `python3 -m pip install --upgrade --force-reinstall --no-cache-dir KratosMultiphysics[all]==10.4.3` - - Windows: `python -m pip install --upgrade --force-reinstall --no-cache-dir KratosMultiphysics[all]==10.4.3` - * 4.2- To execute Kratos using your compiled binaries: - * Fill the Kratos preferences windows with - - Path to the python folder - - Path to the kratos build folder - * Step by step video: https://www.youtube.com/watch?v=zZq7ypDdudo - * 4.3- To execute Kratos using docker, just install docker. - * Note: This is the ONLY option if you are a **macOS** user at this moment - -### Launch modes -In Kratos preferences, select the execution mode: -* GiD's python: Use the GiD internal python to run. It will help you install the pip packages -* Pip packages: Kratos will be installed via `pip install` -* local compiled: If you are a developer and build your applications, use this one -* docker: If you do not want to install any dependency, just run via docker! - * The default image is [fjgarate/kratos-run](https://hub.docker.com/repository/docker/fjgarate/kratos-run) - -### Usage -* Run GiD -* Go to top menu: Data / Problem type / kratos -* Go to top menu: kratos / Preferences / Developer mode (recommended) +The graphical user interface of [Kratos Multiphysics](https://github.com/KratosMultiphysics/Kratos) for [GiD](https://www.gidsimulation.com), distributed as a GiD *problemtype* (`kratos.gid`). + +- **Stable release:** open GiD, go to *Data > Problem type > Internet retrieve* and download Kratos. Available for Linux, Windows and macOS. +- **Developer version:** you are in the right place. + +Current version: **Kratos 10.4.3** — requires **GiD 16.1.10d or newer** (developer version recommended). + +## Installation (developer version) + +1. Clone this repository, or download a [release](https://github.com/KratosMultiphysics/GiDInterface/releases). +2. Install the latest [GiD developer version](https://www.gidsimulation.com/gid-for-science/downloads/) (minimum **16.1.10d**). +3. Go to GiD's `problemtypes` folder and delete any previous `kratos.gid`. +4. Create there a link to the [`kratos.gid`](./kratos.gid/) folder of this repository: + - Windows: a shortcut to the `kratos.gid` folder. + - Linux / macOS: `ln -s /path/to/GiDInterface/kratos.gid /path/to/GiD/problemtypes/kratos.gid` +5. Choose an execution mode (see below). + +## Execution modes + +Select the mode in *Kratos > Preferences*. + +| Mode | What you need | Notes | +|---|---|---| +| **GiD's python** (default) | Nothing | Uses the Python bundled with GiD. Missing packages are detected and can be installed from the interface. | +| **Pip packages** | Python + `KratosMultiphysics[all]` | Use a Python version supported by the [KratosMultiphysics 10.4.3 wheels](https://pypi.org/project/KratosMultiphysics/10.4.3/#files). | +| **Local compiled** | Your own Kratos build | For Kratos developers. | +| **Docker** | Docker | No other dependency. Currently the **only option on macOS**. Default image: [`fjgarate/kratos-run`](https://hub.docker.com/r/fjgarate/kratos-run). | + +### GiD's python +If some package is missing, run this in the GiD command line: + +``` +-np- W [GiD_Python_PipInstall { $::Kratos::pip_packages_required } 1 ] +``` + +### Pip packages +```bash +# Linux +python3 -m pip install --upgrade --force-reinstall --no-cache-dir KratosMultiphysics[all]==10.4.3 +# Windows +python -m pip install --upgrade --force-reinstall --no-cache-dir KratosMultiphysics[all]==10.4.3 +``` + +### Local compiled +In *Kratos > Preferences* fill in: +- the path to the Python folder +- the path to the Kratos build folder + +Step-by-step video: https://www.youtube.com/watch?v=zZq7ypDdudo + +## Usage +1. Run GiD. +2. *Data > Problem type > kratos*. +3. *Kratos > Preferences > Developer mode* (recommended for developers). +4. Pick an application in the application market window. ### Examples -* [Fluid dynamics example](https://github.com/KratosMultiphysics/Kratos/wiki/Running-an-example-from-GiD#3-set-a-fluid-dynamics-problem) -* [Structural mechanics example](https://github.com/KratosMultiphysics/Kratos/wiki/Running-an-example-from-GiD#4-set-a-structural-mechanics-problem) -* [Fluid-Structure interaction example](https://github.com/KratosMultiphysics/Kratos/wiki/Running-an-example-from-GiD#5-set-a-fluid-structure-interaction-problem) +- [Fluid dynamics](https://github.com/KratosMultiphysics/Kratos/wiki/Running-an-example-from-GiD#3-set-a-fluid-dynamics-problem) +- [Structural mechanics](https://github.com/KratosMultiphysics/Kratos/wiki/Running-an-example-from-GiD#4-set-a-structural-mechanics-problem) +- [Fluid-structure interaction](https://github.com/KratosMultiphysics/Kratos/wiki/Running-an-example-from-GiD#5-set-a-fluid-structure-interaction-problem) + +Many applications also ship ready-to-run examples (*Examples* tool inside the interface). + +## Applications + +Public applications (shown in the application market): Structural, Fluid, FSI, Dam, Thermic, Pfem, DEM, MPM, Shallow water, GeoMechanics, and the tools Stenosis Wizard, Stent, Mdpa Generator and Examples. + +Others (CompressibleFluid, EmbeddedFluid, Buoyancy, ConjugateHeatTransfer, PfemFluid, CDEM, …) are reachable through the launchers or in developer mode. The full list lives in the `appLink` entries of [`kratos.gid/kratos.spd`](./kratos.gid/kratos.spd). + +## Repository layout + +``` +kratos.gid/ The GiD problemtype + kratos.tcl Entry point (GiD events, init, version checks) + kratos.xml Problemtype metadata (version, min GiD version, pip packages) + kratos.spd Root of the data tree; lists the applications (appLink) + kratos.transform Rules to upgrade models saved with older versions + apps// One folder per application: app.json, start.tcl, xml/, write/, examples/ + apps/Common/ Shared XML/SPD definitions + scripts/ Core: Model/ (entities), Writing/ (mdpa + json), Controllers/ (windows) + exec/ Launch scripts per mode and OS, MainKratos.py + libs/ Third-party Tcl libraries +tools/ Release scripts +dockers/ Release / runner docker images +``` + +## Testing + +CI runs the [kratos-gid-tester](https://github.com/jginternational/kratos-gid-tester) suite in the `fjgarate/kratos-tester` image on a self-hosted runner, on every push to `master`. Pull requests are tested only after a maintainer adds the `safe-to-test` label. + +## Contributing + +1. Fork the repository and create a branch from `master`. +2. Make your changes and test them in GiD (see [AGENTS.md](./AGENTS.md) for the code structure and conventions). +3. Open a pull request against `master`. -## Warnings -* This repository is in Beta version. This means that everything can change. +Questions: open an [issue](https://github.com/KratosMultiphysics/GiDInterface/issues). -## Want to develop? -* Ask for access -> contact fjgarate@cimne.upc.edu +## License +See [LICENSE.md](./LICENSE.md). diff --git a/TODO.md b/TODO.md new file mode 100644 index 000000000..f11e85b47 --- /dev/null +++ b/TODO.md @@ -0,0 +1,151 @@ +# TODO — Auditoría de código (2026-11-12) + +Resultado de una revisión de solo lectura de `kratos.gid/` (Tcl, XML/SPD, `exec/`, `tools/`, `dockers/`). +Nada de esto se ha probado en GiD. Rutas relativas a `kratos.gid/` salvo que se indique. + +Leyenda: **[V]** = comprobado leyendo el código · **[A]** = reportado por la auditoría, pendiente de confirmar al corregir. +Severidad: 🔴 alta · 🟠 media · 🟢 baja. + +Antes de cada corrección: identificar el test de kratos-gid-tester que la cubre (o añadir uno). + +--- + +## Fase 1 — Bugs confirmados (arreglos pequeños, un commit por bug) + +### Lanzamiento / ejecución +- [ ] 🔴 [V] `scripts/Launch.tcl:103` — `GetMissingPipPackages` compara `KratosMultiphysics[all]` con `pip list --format=freeze`, que nunca incluye `[all]` → el modo *External python* siempre da `MISSING_PIP_PACKAGES` y `kratos.tcl:548` cancela el cálculo. Fix: `regsub {\[.*\]} $name ""` antes de comparar (como en la variante GiD's python). +- [ ] 🔴 [V] `exec/pip.unix.bat:12-16` — `export PYTHONPATH=%python_home%` (sintaxis Windows en bash) → Python no arranca; además ejecuta `$python_home/python3` en vez de `$python_path`. Fix: no exportar PYTHONHOME/PYTHONPATH y ejecutar `"$python_path" MainKratos.py`. +- [ ] 🔴 [V] `exec/compiled.unix.bat:34-35` — `export PATH=$kratos_bin_path\libs;$PATH` rompe PATH; `PYTHONHOME=$python_home` usa `dirname(python)` (p.ej. `/usr/bin`). Fix: `export PATH="$kratos_bin_path/libs:$PATH"`, no fijar PYTHONHOME en Unix. +- [ ] 🔴 [A] `exec/pip_gids_python.win.bat:18-19` — `set PYTHONPATH=""` deja el literal `""`. Fix: `set "PYTHONPATH="` / `set "PYTHONHOME="`. +- [ ] 🟠 [V] `exec/*.unix.bat:5-7` (compiled, pip, pip_gids_python, docker) — `rm -f "$2/$1*.post.bin"`: el `*` entrecomillado no expande. Fix: `rm -f "$2/$1"*.post.bin`. +- [ ] 🟠 [A] Rutas con espacios sin comillas: `compiled.unix.bat:41`, `pip_gids_python.unix.bat:16`, `compiled.win.bat:28`, `pip_gids_python.win.bat:20`, `pip.win.bat:21`. +- [ ] 🟠 [A] `exec/compiled.win.bat:18-19` — `DEL "%2\gid_output"` sobre un directorio pide confirmación. Fix: `rmdir /s /q`. +- [ ] 🟠 [A] `exec/docker.*.bat` — `--name "$1"` falla con nombres de modelo con espacios; sin `--user` en Linux los resultados quedan como root. `Launch.tcl:351` depende del nombre. +- [ ] 🟠 [A] `scripts/Launch.tcl:305-310` + `kratos.tcl:557` — modo inexistente → `dict get` falla, `catch` lo silencia y GiD recibe un bat vacío sin aviso. Fix: comprobar `$mode ne ""` y mostrar `$error_msg`. +- [ ] 🟠 [A] `scripts/Launch.tcl:98,115` — `exec ... pip list` sin `catch`. `Launch.tcl:232` llama a `pipVersion` sin el `python_path` configurado. + +### Núcleo (`scripts/`, `kratos.tcl`) +- [ ] 🔴 [V] `scripts/Writing/Writing.tcl:724-725` — `CopyMainScriptFile`: rama de error usa `$errName`/`$wevent` inexistentes y `return errcode 1` inválido. +- [ ] 🟠 [V] `scripts/Writing/Writing.tcl:379` — prisma cuadrático escrito con 1 nodo (debe ser 15). +- [ ] 🟠 [V] `scripts/Controllers/TreeInjections.tcl:376` — `v='$vfX'` dentro del bucle X/Y/Z → Y y Z reciben la función de X. Fix: `[set vf$i]`. +- [ ] 🟠 [V] `scripts/Controllers/CommonProcs.tcl:292` — `if {...} {return hidden} {return normal}` hace inalcanzables las líneas 293-294. Fix: `if {$conditionId ni $ncslist} {return hidden}`. +- [ ] 🟠 [V] `scripts/spdAuxiliar.tcl:278-280` — `GetAppIdFromNode` asigna `prevDomNode` pero compara `prevDomNodeName` (nunca cambia) → puede subir hasta el documento y fallar. >30 usos. +- [ ] 🟠 [V] `kratos.tcl:448` — se pasa el literal `n_elems` en vez de `$n_elems` a `MeshProgress`. +- [ ] 🟠 [A] `kratos.tcl:598` — usa `$inittime`; la variable es `ini_time` (latente: solo con `time_monitor`). +- [ ] 🟠 [A] `scripts/Writing/WriteProjectParameters.tcl:700-707` — `GetMatchSubModelPart`: comprueba `$pair_join` pero añade `$pair` (no deduplica); L700 pasa literal `stage`; L701 sobrescribe `model_part_basename`. +- [ ] 🟠 [V] `scripts/Logs.tcl:54` — `return ""` al inicio de `FlushLog` → `kratos_private(Log)` crece sin límite. `Logs.tcl:98` condición invertida (desactiva logs cuando `SaveGidDefaults`=1). +- [ ] 🟠 [A] `scripts/Writing/Writing.tcl:514-519` — MPI genera `MPILauncher.sh` que apunta a `exec/Kratos/runkratos` y `python35.zip` (ya no existen). +- [ ] 🟠 [A] `scripts/Controllers/TreeInjections.tcl:700` vs `:737` — `is_historical`: una usa `isBooleanFalse`, otra `ne "False"` (latente). +- [ ] 🟢 [A] `scripts/spdAuxiliar.tcl:479-480` — `RenameIntervalGroup`: `join [list $newname $child] //` con `$child` lista. Fix: `{*}$child`. +- [ ] 🟢 [A] `scripts/Controllers/ApplicationMarketWindow.tcl:310` — `set must_open_init_window 0` sin `variable` (sin efecto); L138 usa `$root` posiblemente indefinido. Mismo patrón con `initwind` en `CreateLauncherWindow`/`CreateDimensionWindow`. +- [ ] 🟢 [A] `scripts/Writing/WriteConditions.tcl:38` — `ne $groups` en vez de `ni` (no deduplica; lo usa MPM). +- [ ] 🟢 [A] `scripts/Controllers/MdpaImportMesh.tcl:127` — `if {$id in [dict exists ...]} {next}` → `if {[dict exists ...]} {continue}`; cerrar `$fp` y `EndWaitState` con `try/finally`. +- [ ] 🟢 [A] Errores de una línea: `ConstitutiveLaw.tcl:398` (`set $cl`), `ConstitutiveLaw.tcl:351`, `Writing.tcl:61` (`configutation`), `Writing.tcl:90` (`]` suelto), `WriteProjectParameters.tcl:142` (ignora `cut_planes_UN`), `TreeInjections.tcl:988`, `TreeInjections.tcl:962` (`get_materials_list_simple` vs `ProcGet_materials_list_simple`). +- [ ] 🟢 [A] `scripts/Model/Entity.tcl:61-74` — `addInput/addOutput` pasan argumentos desplazados al constructor de `Parameter` (latente). + +### Apps +- [ ] 🔴 [V] `apps/PfemThermic/xml/NodalConditions.xml:72` — `INLET` usa `AssignInletProcess` (renombrado a `AssignLagrangianInletProcess` solo en PfemFluid, commit `48f4290ef`) → `TreeInjections.tcl:231` lanza error. +- [ ] 🔴 [V] `apps/GeoMechanics/app.json:37-45` — `unique_names` (`GEOMParts`, `GEOMNodalConditions`, `GEOMBC`, `GEOMResults`, `GEOMTimeParameters`) no existen; el árbol usa `STParts`, `STNodalConditions`, `STLoads,GEOMLoads`, `STResults`. +- [ ] 🔴 [V] `apps/GeoMechanics/write/write.tcl:64` — llama a `write::writeModelPartFileOld`; el proc es `::GeoMechanics::write::writeModelPartFileOld` (L125). +- [ ] 🔴 [V] `apps/DEMPFEM/xml/XmlController.tcl:16` y `apps/FluidDEM/xml/XmlController.tcl:43` — leen `${::DEMPFEM::prefix}` / `${::FluidDEM::prefix}`, que no existen. Fix: `[::X::GetAttribute prefix]$name`. +- [ ] 🔴 [V] `apps/DEMPFEM/start.tcl:14-22` — `Init` no hace `set _app $app`. +- [ ] 🟠 [A] `apps/ConjugateHeatTransfer/write/writeProjectParameters.tcl:192` — `lappend` en vez de `concat`; L225-232 `new_condition` sin rama por defecto. +- [ ] 🟠 [V] `apps/StenosisWizard/app.json:14` — lista `wizard/wizard_steps.tcl`, el archivo es `Wizard_Steps.tcl` (falla en Linux/macOS). +- [ ] 🟠 [V] `apps/StenosisWizard/start.tcl:33` — `after 600 [::StenosisWizard::StartWizardWindow]` ejecuta al instante. Fix: sin corchetes. L22 variable local sin uso. +- [ ] 🟠 [A] `apps/ShallowWater/examples/examples.xml:9` — "Waves" llama a `DamBreak::Init`; `examples/Waves.tcl` no está en `script_files`. +- [ ] 🟠 [A] `apps/Structural/xml/XmlController.tcl:56` y `:109` — `ProcCheckGeometryStructural` definido dos veces; `Stent/xml/XmlController.tcl:26` lo redefine globalmente. +- [ ] 🟠 [A] `apps/FreeSurface/write/write.tcl:2` y `apps/Buoyancy/write/write.tcl:2` — `namespace path` a sí mismos; `AddValidApps` llama a `AddAttribute` inexistente. +- [ ] 🟠 [A] `apps/CompressibleFluid/xml/XmlController.tcl:77` — llama a `CompressibleFluid::write::GetUsedElements` (no existe; usar `::Fluid::write::GetUsedElements`). +- [ ] 🟠 [A] `apps/PotentialFluid/xml/XmlController.tcl:49` — redefine globalmente `spdAux::injectConditions` sin `processDynamicNodes`; afecta a apps cargadas después. +- [ ] 🟠 [A] IDs duplicados en el mismo catálogo (getElement/GetProcess devuelven el primero): `PfemFluid/xml/Elements.xml:504/673` y `:587/714`, `Dam/xml/Processes.xml:166/175` y `:184/194`, `MPM/xml/Elements.xml:157/176`. +- [ ] 🟢 [A] `AddAttribute` con `dict append ... ]` en `Structural/write/write.tcl:495`, `DEM/write/write.tcl:125`, `GeoMechanics/write/write.tcl:252`, `PotentialFluid/write/write.tcl:48`. `validApps` no lo lee nadie → eliminar `AddValidApps`. +- [ ] 🟢 [A] `apps/FluidDEM/start.tcl:30` — `::DEM::AfterMeshGeneration fail` (literal en vez de `$fail`). +- [ ] 🟢 [A] `apps/Stent/start.tcl:52` — `catch {::Structural::BeforeMeshGeneration ...}` proc inexistente; L6 `variable app_id` en vez de `_app`. +- [ ] 🟢 [A] `apps/CompressibleFluid/app.json` — `unique_names` `materials`/`time_parameters` no coinciden con el árbol; falta `drag`. +- [ ] 🟢 [A] IDs de ejemplo duplicados en el mismo grupo: `FluidDEM/examples/examples.xml:7,15`; `FSI/examples/examples.xml:27,41`. + +--- + +## Fase 2 — Procesos, compatibilidad y decisiones + +- [ ] 🔴 [A] `tools/create-release.bat:18-23` + `tools/prepare-release-files.py:38-55` — borra apps no `production` del working tree y hace `git commit -am` en la rama actual, luego `tag -f` + `push --force` (ya pasó: `bfde2884`, revertido en `153ec864`). Fix: generar `dist/` desde `git archive`/`git worktree`, sin commit, abortar en error. +- [ ] 🟠 [A] Finales de línea: no hay `.gitattributes`; con `core.autocrlf=true` los `*.unix.bat` y `*.sh` quedan en CRLF en el working tree; `dockers/create-release.sh:5` solo hace `dos2unix` a `*.unix.bat`. Fix: `.gitattributes` (`*.unix.bat`/`*.sh` `eol=lf`, `*.win.bat` `eol=crlf`) y `dos2unix` también para `*.sh`. Revisar la regla de AGENTS.md. +- [ ] 🟠 [A] `apps/Structural/xml/ConstitutiveLaws.xml:177` — `BeamConstitutiveLaw2D` → `TimoshenkoBeamConstitutiveLaw2D` (commit `38b8bb93`) sin regla en `kratos.transform`; `kratos.spd` sigue en 10.4.3 así que el transform no se dispara. Fix: subir versión del `.spd` y añadir regla. +- [ ] 🟠 [A] `kratos.transform` — solo reglas 6.0 → 9.3.2. Añadir sección por versión y documentar el procedimiento en AGENTS.md. +- [ ] 🟠 [A] `exec/launch.json:5,11` — contiene `10.4.3` (no está en la lista de AGENTS.md); `pip_packages` no se usa. `Launch.tcl:273` / `LoadLaunchModes` — revisar si se copia/sobrescribe `~/.kratos_multiphysics/launch_configuration.json` (los dos informes discrepan). +- [ ] 🔴 [A] **Decidir:** `scripts/Writing/WriteProjectParameters.tcl:21` — `tcl2json` elige número/string según la representación interna de Tcl → salida no determinista. Cambia el JSON de todas las apps. +- [ ] 🔴 [V] **Decidir:** `expr` sin llaves sobre valores de usuario: `Writing.tcl:571` (`getFormattedValue`), `WriteProjectParameters.tcl:391-392`, `WriteMaterials.tcl:99`. Riesgo de inyección y conversiones no deseadas (`2*3`, `sin(1)`). +- [ ] 🟠 [A] `scripts/Controllers/TreeInjections.tcl` (L64, 93, 118, 243, 268, 331…) — XML generado con `help='$help'` sin escapar; un apóstrofo rompe `appendXML`. Añadir helper `xml_escape`. +- [ ] 🟢 [A] `minimum_gid_version` en los `app.json` (`15.1.3d`, `15.1.4d`, `16.1.4d`) por debajo del efectivo `16.1.10d`. Quitar el campo o alinearlo. +- [ ] 🟢 [A] `exec/install_python_and_dependencies.unix.sh:2` — `2>1` (debe ser `2>&1`); `python3-distutils` no existe en Ubuntu 24.04. +- [ ] 🟢 [A] `tools/prepare-release-files.py:24` — `ET.SubElement(root, 'Program', 'Production')` pasa str como attrib; `tree.write` sin declaración/encoding. + +--- + +## Fase 3 — Limpieza de bajo riesgo + +### Código y archivos muertos +- [ ] `.tcl` no listados en `script_files` (borrar o registrar): `CompressibleFluid/examples/examples.tcl`, `Fluid/write/writeByGiDId.tcl`, `GeoMechanics/controllers/Fase.tcl`, `GeoMechanics/controllers/SplashWindow.tcl`, `GeoMechanics/examples/FirstExample.tcl`. +- [ ] Procs sin uso (verificar de nuevo con grep, incluido kratos-gid-tester, antes de borrar): + - Launch: `InstallAllPythonDependencies` (y `exec/install_python.win.bat`, `exec/global_pip.win.bat`), `InstallPip`, `GetMissingPipPackagesGiDsPython_old`, `CreateModeCombo`, `CheckDependenciesLocalPipMode`. + - Utils: `SetMeshCriteria`/`ResetMeshCriteria`, `GetExecVersion`, `proc ?`. + - Model: `GetAllCLInputs`, `GetAllCondInputs`, `GetAllCondOutputs`, `GetAllElemInputs`, `GetAllSchemeParams`, `GetAllSolStratParams`, `GetAvailableConditions`, `CheckCondOutputState`, `DeleteRepeatedConditions`, `getAllProcs`, `Element::getNodalCondition`. + - apps/spdAux: `apps::ClearActiveApp`, `spdAux::ExploreAllRoutes`, `ForceExtremeLoad`, `insertDependenciesSoft`, `InsertMaterialsSimple`; `Proc*` sin referencia: `ProcRefreshTree`, `ProcgetStateFromXPathValue2`, `ProcCambioMat`, `ProcEdit_database_list`, `ProcGetIntervals`, `ProcGet_materials_list_simple`, `ProcPartParamValue`, `ProcShowInMode` (ojo: `.spd` de usuario antiguos). + - write: `AddConfigurationAttribute`, `GetDataType`, `GetNodesFromElementFace`, `GetRestartProcess`, `json2dict_former`. Examples: `getExampleById`. + - **No borrar:** `Kratos::Quicktest` (lo usa kratos-gid-tester), eventos legacy `EndGIDProject`/`AfterWriteCalcFileGIDProject`. +- [ ] GeoMechanics `xml/XmlController.tcl`: `ProcCheckGeometryGeoMechanics` (x2), `ProcGetSolutionStrategiesGeoMechanics`, `ProcCheckNodalConditionStateGeoMechanics`, `ProcGetElementsGeoMechanics` (~120 líneas sin uso). +- [ ] `apps/Buoyancy/write/write.tcl:71` `writeSubModelParts` sin uso. +- [ ] `scripts/Custom/python_writer.py` — no lo referencia nadie y está a medias. +- [ ] Catálogos rotos/no cargados: `FluidDEM/xml/NodalConditions.xml:11` (XML inválido), `DEM/xml/NodalConditions.xml:3`, `MPM/xml/NodalConditions.xml:5`. +- [ ] Includes a `apps/Structural/xml/Processes.spd` (inexistente, `active="0"`) en Structural, MPM y GeoMechanics `Main.spd`. +- [ ] Ramas para GiD < 16: `kratos.tcl:24-28` (`DeprecatedEvents.tcl`, `ModifyPreferencesWindowOld`), `Deprecated.tcl:84-105`, comprobaciones 14.x en `kratos.tcl:297,374`, `Menus.tcl:167`, `ApplicationMarketWindow.tcl:105`. +- [ ] Código tras `return`: `CommonProcs.tcl:390`, `:586`; `Launch.tcl:47` (`if {true}`); `SolutionStrategy.tcl:377,399`. + +### Coherencia +- [ ] `prefix` de los `appLink` en `kratos.spd` no coincide con `app.json` (no se usa: `App::getPrefix` sin llamadas). Eliminar o alinear. +- [ ] `id`/`kratos_name` de `app.json` inconsistentes (`DAM`, `* Launcher`, `Buoyancyapplication`…). +- [ ] Nombres únicos escritos a mano (usar `GetUniqueName`): `MPM/xml/XmlController.tcl:66`, `GeoMechanics/xml/XmlController.tcl:126`, `FSI/write/writeProjectParameters.tcl:80,81,90,168,169`, `FluidDEM/xml/XmlController.tcl:68-69`, `FluidDEM/write/writeProjectParameters.tcl:272`, `ConjugateHeatTransfer/xml/XmlController.tcl:36-44`, `ConjugateHeatTransfer/write/writeProjectParameters.tcl:64-65,150-162`, `PfemFluid/xml/XmlController.tcl:415`; prefijos a mano en `xml::getUniqueName` de Dam, MPM, PfemFluid. +- [ ] `Launch.tcl:179-180` recomienda Python 3.9; el resto exige ≥ 3.10.8. +- [ ] Plataforma: `PreferencesWindow.tcl:45` (ruta por defecto solo Windows), `ImportFiles.tcl:104` (`start` solo Windows), `ApplicationMarketWindow.tcl:182` (`string trimleft` como prefijo). + +### Depuración +- [ ] 82 `W` activas y 104 comentadas en `kratos.tcl` + `scripts/`; pasar las de depuración a `Kratos::Log`: `spdAuxiliar.tcl:177,267,270,369`, `Element.tcl:439`, `Mesh.tcl:32`, `CommonProcs.tcl:309,505,878`, `Writing.tcl:210`, `kratos.tcl:374`. En apps: `PfemFluid/xml/XmlController.tcl:422`, `GeoMechanics/controllers/Python.tcl:5,15`, `FluidDEM/examples/CylinderInFlow.tcl:262`. +- [ ] `scripts/Controllers/ExamplesWindow.tcl:244-252` — canal abierto si falla el parse de un enlace. + +--- + +## Fase 4 — Refactors de duplicación (requieren kratos-gid-tester) + +| # | Clúster | Líneas aprox. | Destino propuesto | +|---|---|---|---| +| 1 | Plantilla de `Init` en 49 `examples/*.tcl` (`IsModelEmpty`, `ResetModel`, redraw/zoom) | ~700 | `Examples::RunExample {ns}` en `scripts/Controllers/ExamplesWindow.tcl` (comprobar si el tester llama a los `Init` directamente) | +| 2 | Ejemplos 2D/3D casi iguales (Dam ThermoMechaDam, FreeSurface Box, MPM CantileverBeam, PfemThermic Sloshing, PotentialFluid NACA) | ~650 | Un archivo parametrizado por dimensión | +| 3 | Ejemplos copiados entre apps (CylinderInFlow, HeatedSquare, SpheresDrop/CirclesDrop, DamBreakFSI) | ~650 | Llamar al proc de la app padre (como `FSI/examples/HighRiseBuilding.tcl:26-29`) | +| 4 | Accesores de atributos del writer en 19 apps (116 procs) | ~550 | Almacén común en `scripts/Writing/Writing.tcl` | +| 5 | Cabecera de `start.tcl` en 24 apps | ~450 | Generada en `apps::LoadAppProperties` | +| 6 | GeoMechanics copia de Structural (`XmlController.tcl`, `write.tcl`) | ~225 | Usar `Structural::xml::*` | +| 7 | `Procs.spd` copiados (Fluid = EmbeddedFluid = PotentialFluid; PfemThermic ≈ PfemFluid) | ~160 | `include` del de la app padre | +| 8 | Tres escritores de SubModelPart (`WriteSubModelPart.tcl:3`, `WriteConditionsByGiDId.tcl:74`, `WriteConditionsByUniqueId.tcl:159`) | ~120 | `write::_writeSMPBlock` con callback de condiciones | +| 9 | `inject*Inputs` (`TreeInjections.tcl:542,565,588`) + `injectNodalConditionsOutputs_do`/`_Nonhistorical_do` | ~120 | Un proc parametrizado | +| 10 | `ErasePreviousIntervals` en 12 `examples.tcl` | ~80 | `spdAux::` junto a `CreateInterval` | +| 11 | `PlaceMDPAImports`/`ModelersPrefix` (FSI, CHT) | ~50 | Helper junto a `write::GetModelersDict` | +| 12 | `writeParametersEvent` idéntico en 7 apps | — | `write::DefaultWriteParametersEvent ns` | +| 13 | Lista de booleanos copiada 5 veces (`Writing.tcl:578-596`, `TreeInjections.tcl:765`) | — | Una sola variable `write::true_values` | +| 14 | Envoltorios `Proc*State` en `CommonProcs.tcl:257-486` | — | `spdAux::BoolToState` | +| 15 | Parseo de `pip list` x3 en `Launch.tcl` | — | `Kratos::_pipFreezeDict` | + +### XML +- [ ] Elementos de `apps/Stent/xml/Elements.xml:3-171` copiados de Structural (Stent ya depende de Structural). +- [ ] Cargas `SelfWeight`/`PointLoad`/`LineLoad`/`SurfaceLoad`/`PointMoment` en Dam, MPM y Structural → `Common/xml/Conditions.xml`. +- [ ] `Dam/xml/Solvers.xml` repite 6 de los 9 solvers de `Common/xml/Solvers.xml`. +- [ ] Materiales `Water`, `Air` (5 apps) y `Steel` (3 apps). + +### Diseño +- [ ] Apps hijas que redefinen procs de la padre o del core (`EmbeddedFluid` → `Fluid::write::writeCustomBlocks`, `Stent` → `ProcCheckGeometryStructural`, `MdpaGenerator` → `write::GetWriteMode`, `PotentialFluid` → `spdAux::injectConditions`) → hooks explícitos. +- [ ] Herencia del writer de Fluid distinta en cada app hija → un único mecanismo (`write::InheritAttributes`). +- [ ] CHT y Buoyancy mutan atributos de `ConvectionDiffusion::write` y los restauran a mano → pasar `un` como parámetros. +- [ ] Capas mezcladas: `apps::setActiveApp` → ventanas; `Model::*State` depende del DOM; `Model::GetSolutionStrategy` devuelve `""` con `W`. +- [ ] `Kratos::ManagePreferences` escribe en disco y refresca el árbol incluso en `GetValue`. +- [ ] `spdAux::TryRefreshTree` con `update` en temporizador y `catch` (reentrada). +- [ ] Procs grandes: `spdAux::GetParameterValueString`, `Kratos::ReadPre`, `write::processMaterials`, `write::writeEvent`, `ProcGetMaterialsList` (define procs globales en cada llamada). +- [ ] Fugas: `Model::DestroyEverything` no destruye objetos TclOO; documentos tDOM sin borrar (`Model.tcl:55-95`, `kratos.tcl:247`, `TreeInjections.tcl:793`, `ExamplesWindow.tcl:97`).