Metadata-Version: 2.4
Name: thermohl
Version: 1.8.0
Summary: Calculations relative to temperature and ampacity in overhead conductors.
License-Expression: MPL-2.0
Project-URL: Homepage, https://github.com/phlowers/thermohl
Project-URL: Documentation, https://phlowers.readthedocs.io/projects/thermohl
Project-URL: Issues, https://github.com/phlowers/thermohl/issues
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: Developers
Classifier: Natural Language :: English
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Operating System :: OS Independent
Requires-Python: <3.15,>=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.26.0
Requires-Dist: pandas>=2.1.2
Requires-Dist: pyyaml>=6.0.1
Provides-Extra: scientific
Requires-Dist: scipy>=1.13.1; extra == "scientific"
Dynamic: license-file

<!--
SPDX-FileCopyrightText: 2025 RTE (https://www.rte-france.com)

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
SPDX-License-Identifier: MPL-2.0
-->

# ThermOHL

[![MPL-2.0 License](https://img.shields.io/badge/license-MPL_2.0-blue.svg)](https://www.mozilla.org/en-US/MPL/2.0/)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=phlowers_thermohl&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=phlowers_thermohl)
[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=phlowers_thermohl&metric=ncloc)](https://sonarcloud.io/summary/new_code?id=phlowers_thermohl)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=phlowers_thermohl&metric=coverage)](https://sonarcloud.io/summary/new_code?id=phlowers_thermohl)

[![pyodide](https://img.shields.io/badge/works_on-pyodide-%237303fc)](https://pyodide.org/en/stable/index.html)


Temperature estimation of overhead line conductors is an important topic for 
TSOs for technical, economic, and safety-related reasons (DLR/ampacity, sag 
management ...). It depends on several factors, mainly transit, weather and the
conductor properties. ThermOHL is a python package to compute temperature and/or 
ampacity in overhead line conductors.

## Features

The temperature of a conductor is estimated by solving a heat equation
which describes how temperature evolves over time, taking into account
different power terms that either heat or cold the conductor (see next picture 
from CIGRE[1]).

![image](thermohl-docs/docs/assets/images/cigre_balance.png "Overhead conductor heating and cooling. From [CIGRE].")

Two heat equations (a more complete, third one is under development)
are available:

* one with a single temperature for the cable;
* another with three temperatures (core, average and surface
  temperature) for more precise computations.

Each of these equations can be used with a set of pre-coded power
terms from the literature :

* one using CIGRE recommendations [1];  
* one using the IEEE standard [2];  
* two others from RTE departments.

Solvers derivated from heat equations can compute steady-state
temperature or ampacity, and transient temperature. The set of
[parameter](thermohl-docs/docs/api-reference/parameters.md) required depends on 
the power terms used, and default values are provided.

## References

* [1] Stephen et al., **Thermal behaviour of overhead conductors**. 
  *CIGRE, Study committee 22, working group 12*, 2002.
  https://e-cigre.org/publications/detail/207-thermal-behaviour-of-overhead-conductors.html.
* [2] IEEE, **Standard for Calculating the Current-Temperature Relationship of Bare Overhead Conductors**.
  *IEEE Std 738–2012 (Revision of IEEE Std 738–2006, Incorporates IEEE Std 738–2012 Cor 1–2013)*, 2013.
  https://doi.org/10.1109/IEEESTD.2013.6692858.


## Users

---

### Environment
ThermOHL is using pip for project and dependencies management.
You need a compatible version of python (3.8 or higher). You may have to install it manually (e.g. with pyenv). Then you may create a virtualenv and activate it.

### Set up thermohl

To install the package using uv, execute the following command:

```shell
    uv pip install "thermohl @ git+https://github.com/phlowers/thermohl"
```
Use it ! You can report to the user guide section.
```shell
    import thermohl
    print(thermohl.__version__)
```

## Developers

---

Install the development dependencies and program scripts via

```shell
  uv sync --group dev
```

Then install the pre-commit hooks:

```shell
  uv run pre-commit install
```

Build a new wheel via

```shell
  uv build --wheel
```

This build a wheel in newly-created dist/ directory

## Pre-commit

This project uses `pre-commit` to ensure code quality through `ruff`.
Hooks are automatically run on `git commit`.

You can also run them manually on all files:

```shell
  uv run pre-commit run --all-files
```

## Building the documentation with mkdocs

First, make sure you have mkdocs and the Readthedocs theme installed.

If you use uv, open a terminal and enter the following commands:

```shell 
  uv sync --group docs
```

Then, in the same terminal, in the `thermohl-docs` folder, build the doc with:

* `mkdocs serve` (or `uv run mkdocs serve`) - Start the live-reloading docs server.
* `mkdocs build` (or `uv run mkdocs build`) - Build the documentation site.
* `mkdocs -h` (or `uv run mkdocs -h`) - Print help message and exit.

The documentation can then be accessed locally from http://127.0.0.1:8000.

### Logging

By default, the `thermohl` logger is silent (it uses a `logging.NullHandler`).

To enable log messages in the console, you can use the provided utility function:

```python
import thermohl.utils
import logging

thermohl.utils.add_stderr_logger(level=logging.INFO)
```

Alternatively, you can manually configure the `thermohl` logger using Python's standard `logging` module:

```python
import logging

logger = logging.getLogger("thermohl")
logger.setLevel(logging.INFO)
handler = logging.StreamHandler()
logger.addHandler(handler)
```

## Simple usage

Solvers in thermOHL take a dictionary as an argument, where all keys are strings and all values are either integers,
floats or 1D `numpy.ndarray` of integers or floats. It is important to note that all arrays should have the same size.
Missing or `None` values in the input dictionary are replaced with a default value, available using
`solver.default_values()`, which are read from `thermohl/default_values.yaml`.

### Example 1

This example uses the single-temperature heat equation (`1t`) with IEEE power terms and default values to compute the
surface temperature (°C) of a conductor in steady-state regime along with the corresponding power terms (W.m<sup>-1</sup>).

```python
from thermohl import solver
from thermohl.solver.entities import HeatEquationType

slvr = solver.ieee(dic=None, heat_equation=HeatEquationType.ONE_TEMPERATURE)
temp = slvr.steady_temperature() 
```

Results from the solver are returned in a dict where values are numpy arrays:

``` python
>>> temp
{'temperature': array([27.3325034]),
 'joule_power': array([0.27314919]),
 'solar_power': array([9.73237776]),
 'convection_power': array([6.65130481]),
 'radiation_power': array([3.35422215]),
 'precipitation_power': array([0.]),
 'input_latitude': 45.0,
  ...
 }
```

Input data can be accessed with the `input_` prefix (e.g. `temp["input_latitude"]`).

### Example 2

This example uses the same heat equation and power terms, but to compute the line ampacity (A), ie the maximum power 
intensity that can be used in a conductor without exceeding a specified maximal temperature (°C), along with the 
corresponding power terms (W.m<sup>-1</sup>). We can see that, for three different ambient temperature, we have three
distinct ampacities (and the lower the ambient temperature, the higher the ampacity).

```python
import numpy as np
from thermohl import solver
from thermohl.solver.entities import HeatEquationType

slvr = solver.ieee(dict(ambient_temperature=np.array([0., 15., 30.])), heat_equation=HeatEquationType.ONE_TEMPERATURE)
Tmax = 80.
imax = slvr.steady_intensity(Tmax)
```

```
>>> imax
{'transit': array([1605.51693463, 1407.02006847, 1183.54643897]),
 'joule_power': array([83.64586616, 64.2414426 , 45.45538152]),
 'solar_power': array([9.73237776, 9.73237776, 9.73237776]),
 'convection_power': array([66.75078505, 50.88447273, 36.23473652]),
 'radiation_power': array([26.62745888, 23.08934764, 18.95302277]),
 'precipitation_power': 0.0,
 'input_latitude': array([45., 45., 45.]),
  ...
 }
```

Input data can be accessed with the `input_` prefix (e.g. `imax["input_latitude"]`).
