Metadata-Version: 2.4
Name: YggSimLib
Version: 1.0
Summary: A library for interfacing with the kspice API for the Yggdrasil project
Author: Håkon Enerstvedt
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: tk==0.1.0
Requires-Dist: networkx==3.4.2
Dynamic: author
Dynamic: description
Dynamic: description-content-type
Dynamic: license-file
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# YggSimLib

YggSimLib is a Python framework for orchestrating and automating simulation workflows in the Yggdrasil Engineering Simulator. It provides a lightweight abstraction on top of the k-Spice API, including simulator initialization, sequence execution, dependency management, and simplified tag/property access. 【1-81dc1e】

## Features

- Simple simulator initialization through the `YggLCS` class
- Programmatic or GUI-based selection of timelines and model files
- Generic tag/property access through `get()` and `set()`
- Flexible step-based sequencing using `Step` and `Sequence`
- Dependency-managed orchestration using `Admin`
- Parallel sequence execution support
- Inhibit logic and transition conditions
- Direct access to the underlying k-Spice Timeline object
- Minimal abstraction layer with native k-Spice compatibility

---

## Installation

```bash
pip install YggSimLib
```

---

## Requirements

- Python 3.12+
- Yggdrasil Engineering Simulator
- k-Spice Python bindings
- networkx

---

## Quick Start

### GUI Mode

When no arguments are supplied, YggSimLib opens dialogs that let you select:

- Model directory
- Timeline
- Model file
- Parameter file
- Initial condition file

```python
from YggSimLib import YggLCS

sim = YggLCS()
```

---

### Scripted Mode

The simulator can also be initialized directly from code without any dialogs.

```python
from YggSimLib import YggLCS

sim = YggLCS(
    model=r"C:\K-Spice-Projects\Hugin A",
    tl="S24 and S38 steady state",
    mpc=[
        "S24 and S38 steady state",
        "S24 and S38 steady state",
        "S24 and S38 shut down, warm TEG"
    ]
)
```

#### Constructor Arguments

| Argument | Description |
|-----------|-------------|
| `model` | Model directory path |
| `tl` | Timeline name |
| `mpc` | List containing model, parameter, and initial condition names |
| `run` | Automatically start simulation after initialization |

Example:

```python
sim = YggLCS(
    model=r"C:\K-Spice-Projects\Hugin A",
    tl="S24 and S38 steady state",
    mpc=[
        "S24 and S38 steady state",
        "S24 and S38 steady state",
        "S24 and S38 shut down, warm TEG"
    ],
    run=True
)
```

---

## Reading and Writing Values

### Read a Property

```python
pressure = sim.get(
    "D-38PT4225",
    "MeasuredValue",
    unit="barg"
)

print(pressure)
```

### Write a Property

```python
sim.set(
    "D-38PA002A_m",
    "LocalInput",
    True
)
```

### Direct Timeline Access

The active k-Spice Timeline object is available through:

```python
timeline = sim.get_timeline()
```

or

```python
timeline = sim.timeline
```

This gives access to the full k-Spice API:

```python
value = sim.timeline.get_value(
    "ProcessModel",
    "D-38PT4225:MeasuredValue"
)

sim.timeline.set_value(
    "ProcessModel",
    "D-38PA002A_m:LocalInput",
    True
)
```

---

## Creating a Step

A step consists of:

- Actions
- Transition conditions
- Timeout limit
- Next step logic

```python
step = Step({
    "number": 10,
    "actions": [
        lambda: sim.set(
            "D-38PA002A_m",
            "LocalInput",
            True
        )
    ],
    "transitions": [
        lambda: sim.get(
            "D-38PA002A_m",
            "MachineState"
        ) == 1
    ],
    "tmax": 30,
    "next": lambda: "S020"
})
```

---

## Creating a Sequence

```python
steps = {
    "S010": step1,
    "S020": step2
}

sequence = Sequence(
    "Pump Startup",
    steps,
    sim
)

sequence.add_steps(steps.values())

sequence.start(verbose=True)
```

### Sequence Features

- Ordered execution
- Conditional transitions
- Timeouts
- Inhibit conditions
- Verbose execution logging

---

## Example: Multi-Step Sequence

```python
S010 = Step({
    "number": 10,
    "actions": [
        lambda: sim.set(
            "D-38PA002A_m",
            "LocalInput",
            True
        )
    ],
    "transitions": [
        lambda: sim.get(
            "D-38PA002A_m",
            "MachineState"
        ) == 1
    ],
    "tmax": 30,
    "next": lambda: "S020"
})

S020 = Step({
    "number": 20,
    "actions": [],
    "transitions": [
        lambda: sim.get(
            "D-38PT4225",
            "MeasuredValue"
        ) > 10
    ],
    "tmax": 60,
    "next": None
})

steps = {
    "S010": S010,
    "S020": S020
}

seq = Sequence(
    "Pump Startup",
    steps,
    sim
)

seq.add_steps(steps.values())
seq.start()
```

---

## Parallel Sequence Execution

Multiple sequences can be coordinated through the `Admin` class.

```python
admin = Admin(
    "Startup Controller",
    [seq1, seq2, seq3],
    edges,
    sim
)

admin.start()
```

### Dependency Graph

Dependencies are defined as directed edges:

```python
edges = [
    ("START", "WaterWash"),
    ("WaterWash", "TEGStartup"),
    ("TEGStartup", "END")
]
```

Sequences whose dependencies are satisfied can execute in parallel.

---

## Working with Simulator Time

Sequences evaluate transitions against simulator time.

For fully automated execution it may be useful to advance timeline time in a separate thread:

```python
import threading
import time

stop_event = threading.Event()

def advance_time():
    while not stop_event.is_set():
        sim.timeline.run_steps(1)
        time.sleep(0.1)

clock = threading.Thread(target=advance_time)
clock.start()

try:
    sequence.start(verbose=True)
finally:
    stop_event.set()
    clock.join()
```

---

## Main Classes

### YggLCS

Simulator wrapper responsible for:

- Project loading
- Timeline activation
- Model loading
- Property access

Methods:

```python
get_timeline()
get(tag, prop, unit=False)
set(tag, prop, value, unit=False)
run()
pause()
close_project()
```

### Step

Represents an individual sequence step.

### Sequence

Executes a collection of steps.

### Admin

Coordinates multiple sequences using dependency graphs.

---

## Design Philosophy

YggSimLib intentionally stays close to the underlying k-Spice API.

The library focuses on:

- Simplified simulator initialization
- Readable sequence definitions
- Reusable startup and shutdown procedures
- Dependency management
- Minimal abstraction overhead


---

## Author

Built by Håkon Enerstvedt.

YggSimLib is designed to simplify automation, testing, startup procedures, and workflow orchestration within the Yggdrasil Engineering Simulator ecosystem.
