# Components Wear Examples

# Components Wear Examples

Файлы: `examples/components_wear/example.py`, `example_objects_simulate.py`, `example_objects_simulate_ray.py`. Данные: `examples/components_wear/data/graph.json` (граф из двух узлов A/B, по 4 компонента в каждом, с одной зависимостью B→A) и `data/object.json` (конкретный объект: компонент `A2` с износом 22000 и `B1` с износом 63000).

`example_objects_simulate_ray.py` — **единственный пример во всём репозитории, явно включённый в `run.sh`** (все остальные строки там закомментированы).

> ✅ **Проверено на локальном Docker-стеке**: все три скрипта отрабатывают до конца — включая `example.py`, который раньше падал (см. ниже).

## `example.py`

```python
graph = ComponentsGraph(graph_test)
component_object = ComponentsObject(component_object_test)

print(component_object())
print(component_object.get_probabilities(graph))
print(graph.simulate_objects_bn())

component_object.update_wear(graph, 10000)
print(component_object())
print(component_object.get_probabilities(graph))

result = component_object.predict_fix(graph, target_wear=20_000, step=1_000)
for row in result[1]:
    print(row)
```

### Исправлено: два независимых бага

1. **Неверный импорт.** Скрипт импортировал `from src.mlumina.components_wear import ...` — такого пакета `src` в установленном окружении нет (`mlumina` ставится как обычный пакет, без префикса `src`), скрипт падал сразу на старте с `ModuleNotFoundError: No module named 'src'`. Исправлено на `from mlumina.components_wear import ...`, как во всех остальных примерах.
2. **Опечатка в самом фреймворке.** После фикса импорта скрипт всё равно падал на строке `component_object.update_wear(graph, 10000)`: `ComponentsObject.update_wear()` и `.predict_fix()` вызывали несуществующий метод `self._get_wear_dict()`, тогда как в классе был определён `_get__dict()` (опечатка, двойное подчёркивание). Метод переименован в `_get_wear_dict` — сейчас `update_wear`/`predict_fix` работают как задокументировано.

Теперь весь скрипт, включая `update_wear`/`predict_fix`, отрабатывает от начала до конца.

## `example_objects_simulate.py` — рабочий пример, без Ray

```python
graph = ComponentsGraph(graph_test)
brakes = graph.simulate_objects(n_objects=10000, total_wearout=10000000, step=1000, seed=42, fix_coeff=1.0)

print(f"Broken parts: {len(brakes)}")
print(brakes.head())
```

Симулирует 10 000 независимых объектов на графе из `graph.json`, каждый "проезжает" 10 000 000 условных единиц износа с шагом 1000. Возвращает `pandas.DataFrame` со всеми зафиксированными отказами (колонки `failed_node`, `wear`, `all_parts`). Объект, загруженный из `object.json` (`component_object_test`), в этом скрипте создаётся, но не используется — вся работа идёт через `graph.simulate_objects(...)`, который сам генерирует случайные объекты внутри себя (см. страницу Components Wear в «Документация MLumina»: `simulate_objects` не принимает готовый `ComponentsObject`, а строит собственные случайные объекты на каждой итерации).

При таком объёме (10 000 объектов × 10 000 шагов) выполнение занимает заметное время на одном процессе — на локальном тесте (1 CPU в контейнере) это было около 6.5 минут, результат — 11 944 зафиксированных отказа. Отсюда мотивация для следующего примера.

## `example_objects_simulate_ray.py` — тот же сценарий через Ray

```python
ray.init("ray://localhost:10001")
...
brakes = graph.simulate_objects_ray(n_objects=10000, total_wearout=10000000, step=1000, seed=42, fix_coeff=1.0)
```

Идентичные параметры симуляции, но каждый из 10 000 объектов считается в отдельной Ray-задаче (`@ray.remote`) — распараллеливается на все воркеры кластера. Подключается напрямую к Ray Client Server (`ray://localhost:10001` — порт `HEADNODEPORT` из `.env`, при запуске не из Docker-сети нужно, чтобы этот порт был проброшен на хост, что и происходит в `docker-compose.yml`). На локальном тесте отработал за ~5 минут, 12 030 отказов; в середине прогона несколько Ray-воркеров были убиты out-of-memory killer'ом (конкурировал за память с параллельно запущенным тяжёлым тестом на том же урезанном локальном стенде) — Ray автоматически повторил упавшие задачи, и скрипт всё равно успешно завершился без вмешательства.

## Как запустить

```shell
# без Ray (медленнее, но не требует кластера)
python examples/components_wear/example_objects_simulate.py

# с Ray (нужен поднятый кластер, порт HEADNODEPORT=10001 должен быть доступен)
python examples/components_wear/example_objects_simulate_ray.py

# example.py — теперь тоже полностью рабочий, включая update_wear/predict_fix
python examples/components_wear/example.py
```