Skip to content

Commit

Permalink
add python binding
Browse files Browse the repository at this point in the history
  • Loading branch information
thermalogic committed Aug 9, 2023
1 parent eb5ba03 commit 677b355
Show file tree
Hide file tree
Showing 10 changed files with 319 additions and 1 deletion.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
/target
/Cargo.lock
/python/seuif97.egg-info
/dist
/build
*.exe
*.pdb
*.jar
Expand Down
10 changes: 9 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "if97"
version = "1.3.9"
version = "1.4.0"
edition = "2021"
authors = ["Cheng Maohua <cmh@seu.edu.cn>"]
description = "The high-speed IAPWS-IF97 package with C binding"
Expand All @@ -13,11 +13,19 @@ categories = ["science"]
exclude=["/dynamic_lib"]

[lib]
name = "if97"
crate-type = ["rlib","cdylib"]

[features]
cdecl=[]
stdcall=[]
python = ["pyo3"]

[dependencies.pyo3]
version = "0.15.1"
features = ["extension-module"]
optional = true


[dev-dependencies]
assert_approx_eq = "1.1.0"
Expand Down
3 changes: 3 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include Cargo.toml
recursive-include src *
recursive-include python *
109 changes: 109 additions & 0 deletions README_Python.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# seuif97

The **seuif97** is the Python API of the high-speed IAPWS-IF97 package in Rust

It is suitable for computation-intensive calculations, such as heat cycle calculations, simulations of non-stationary processes, real-time process monitoring and optimizations.

In seuif97, [36 thermodynamic, transport and further properties](#properties) can be calculated.

The following 12 input pairs are implemented:

```txt
(p,t) (p,h) (p,s) (p,v)
(p,x) (t,x) (h,x) (s,x)
(t,h) (t,s) (t,v)
(h,s)
```

## The functions

The type of functions are provided in the seuif97 package:

```python
??(in1,in2,o_id)
```
* the first,second input parameters : the input propertry pairs
* the third input parametes: the property ID of the calculated property - [o_id](#properties)
* the return: the calculated property value of o_id

```python
pt(p,t,o_id)
ph(p,h,o_id)
ps(p,s,o_id)
pv(p,v,o_id)

th(t,h,o_id)
ts(t,s,o_id)
tv(t,v,o_id)

hs(h,s,o_id)

px(p,x,o_id)
tx(p,x,o_id)
hx(h,x,o_id)
sx(s,x,o_id)
```

## Examples

```python
import seuif97

p,t=16.10,535.10
t = seuif97.ph(p, h, 1)
s = seuif97.ph(p, h, 5)
v = seuif97.ph(p, h, 3)
print("(p,h),t,s,v:",
"{:>.2f}\t {:>.2f}\t {:>.2f}\t {:>.3f}\t {:>.4f}".format(p, h, t, s, v))
```

## Properties

| Propertry | Unit | Symbol | o_id | o_id(i32)|
| ------------------------------------- | :---------: |:------:|------:|:--------:|
| Pressure | MPa | p | OP | 0 |
| Temperature | °C | t | OT | 1 |
| Density | kg/m³ | ρ | OD | 2 |
| Specific Volume | m³/kg | v | OV | 3 |
| Specific enthalpy | kJ/kg | h | OH | 4 |
| Specific entropy | kJ/(kg·K) | s | OS | 5 |
| Specific exergy | kJ/kg | e | OE | 6 |
| Specific internal energy | kJ/kg | u | OU | 7 |
| Specific isobaric heat capacity | kJ/(kg·K) | cp | OCP | 8 |
| Specific isochoric heat capacity | kJ/(kg·K) | cv | OCV | 9 |
| Speed of sound | m/s | w | OW | 10 |
| Isentropic exponent | | k | OKS | 11 |
| Specific Helmholtz free energy | kJ/kg | f | OF | 12 |
| Specific Gibbs free energy | kJ/kg | g | OG | 13 |
| Compressibility factor | | z | OZ | 14 |
| Steam quality | | x | OX | 15 |
| Region | | r | OR | 16 |
| Isobari cubic expansion coefficient | 1/K | ɑv | OEC | 17 |
| Isothermal compressibility | 1/MPa | kT | OKT | 18 |
| Partial derivative (∂V/∂T)p | m³/(kg·K) |(∂V/∂T)p| ODVDT | 19 |
| Partial derivative (∂V/∂p)T | m³/(kg·MPa) |(∂v/∂p)t| ODVDP | 20 |
| Partial derivative (∂P/∂T)v | MPa/K |(∂p/∂t)v| ODPDT | 21 |
| Isothermal throttling coefficient | kJ/(kg·MPa) | δt | OIJTC | 22 |
| Joule-Thomson coefficient | K/MPa | μ | OJTC | 23 |
| Dynamic viscosity | Pa·s | η | ODV | 24 |
| Kinematic viscosity | m²/s | ν | OKV | 25 |
| Thermal conductivity | W/(m.K) | λ | OTC | 26 |
| Thermal diffusivity | m²/s | a | OTD | 27 |
| Prandtl number | | Pr | OPR | 28 |
| Surface tension | N/m | σ | OST | 29 |
| Static Dielectric Constant | | ε | OSDC | 30 |
| Isochoric pressure coefficient | 1/K | β | OPC | 31 |
| Isothermal stress coefficient | kg/m³ | βp | OBETAP| 32 |
| Fugacity coefficient | | fi | OFI | 33 |
| Fugacity | MPa | f* | OFU | 34 |
| Relative pressure coefficient | 1/K | αp | OAFLAP| 35|







4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[build-system]
requires = ["setuptools", "wheel", "setuptools-rust"]
build-backend = "setuptools.build_meta"

1 change: 1 addition & 0 deletions python/seuif97/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .seuif97 import *
16 changes: 16 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[metadata]
name = seuif97
version = 2.0.1
author=Cheng Maohua
author_email=cmh@seu.edu.cn
keywords = IAPWS-IF97, IF97
license = MIT
url = https://github.com/thermalogic/IF97
long_description = file: README_Python.md
long_description_content_type = text/markdown
[options]
packages = seuif97
zip_safe = False
setup_requires = setuptools-rust >= 0.12.1;
python_requires = >=3.0
include_package_data = True
13 changes: 13 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

from setuptools import find_packages, setup
from setuptools_rust import RustExtension

setup(
packages=find_packages(where="python"),
package_dir={"": "python"},
rust_extensions=[RustExtension("seuif97.seuif97")],
classifiers=[
"Programming Language :: Python :: 3",
"Topic :: Scientific/Engineering",
]
)
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ pub mod cdecl_c_if97;

#[cfg(feature = "stdcall")]
pub mod stdcall_c_if97;

#[cfg(feature = "python")]
pub mod python_if97;
158 changes: 158 additions & 0 deletions src/python_if97.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
//! The Python API:

use pyo3::prelude::*;

use crate::algo::*;
use crate::common::*;
use crate::r1::*;
use crate::r2::*;
use crate::r3::*;
use crate::r4::*;
use crate::r5::*;

#[pyfunction]
fn pt(p: f64, t: f64, o_id: i32) -> f64 {
let T: f64 = t + 273.15;
let reg: i32 = REGION_NONE;
match o_id {
OP => return p,
OT => return t,
_ => pair_properties(p, T, o_id, pT_sub_region, pT_reg1, pT_reg2, pT_reg3, pT_reg4, pT_reg5, reg),
}
}

#[pyfunction]
fn ph(p: f64, h: f64, o_id: i32) -> f64 {
let reg: i32 = REGION_NONE;
match o_id {
OP => return p,
OH => return h,
_ => pair_properties(p, h, o_id, ph_sub_region, ph_reg1, ph_reg2, ph_reg3, ph_reg4, ph_reg5, reg),
}
}

#[pyfunction]
fn ps(p: f64, s: f64, o_id: i32) -> f64 {
let reg: i32 = REGION_NONE;
match o_id {
OP => return p,
OS => return s,
_ => pair_properties(p, s, o_id, ps_sub_region, ps_reg1, ps_reg2, ps_reg3, ps_reg4, ps_reg5, reg),
}
}

#[pyfunction]
fn hs(h: f64, s: f64, o_id: i32) -> f64 {
let reg: i32 = REGION_NONE;
match o_id {
OH => return h,
OS => return s,
_ => pair_properties(h, s, o_id, hs_sub_region, hs_reg1, hs_reg2, hs_reg3, hs_reg4, hs_reg5, reg),
}
}

#[pyfunction]
fn px(p: f64, x: f64, o_id: i32) -> f64 {
if p > P_MAX4 || p < P_MIN4 || x > 1.0 || x < 0.0 {
return INVALID_VALUE as f64;
}
match o_id {
OP => return p,
OX => return x,
OT => return px_reg4(p, x, o_id) - 273.15,
_ => return px_reg4(p, x, o_id),
}
}

#[pyfunction]
fn tx(t: f64, x: f64, o_id: i32) -> f64 {
let T: f64 = t + 273.15;
if T > T_MAX4 || T < T_MIN4 || x > 1.0 || x < 0.0 {
return INVALID_VALUE as f64;
}
Tx_reg4(T, x, o_id)
}

#[pyfunction]
fn pv(p: f64, v: f64, o_id: i32) -> f64 {
let reg: i32 = REGION_NONE;
match o_id {
OP => return p,
OV => return v,
_ => pair_properties(p, v, o_id, pv_sub_region, pv_reg1, pv_reg2, pv_reg3, pv_reg4, pv_reg5, reg),
}
}

#[pyfunction]
fn tv(t: f64, v: f64, o_id: i32) -> f64 {
let reg: i32 = REGION_NONE;
match o_id {
OT => return t,
OV => return v,
_ => pair_properties(t, v, o_id, tv_sub_region, tv_reg1, tv_reg2, tv_reg3, tv_reg4, tv_reg5, reg),
}
}

#[pyfunction]
fn th(t: f64, h: f64, o_id: i32) -> f64 {
let reg: i32 = REGION_NONE;
match o_id {
OT => return t,
OH => return h,
_ => pair_properties(t, h, o_id, th_sub_region, th_reg1, th_reg2, th_reg3, th_reg4, th_reg5, reg),
}
}

#[pyfunction]
fn ts(t: f64, s: f64, o_id: i32) -> f64 {
let reg: i32 = REGION_NONE;
match o_id {
OT => return t,
OS => return s,
_ => pair_properties(t, s, o_id, ts_sub_region, ts_reg1, ts_reg2, ts_reg3, ts_reg4, ts_reg5, reg),
}
}

#[pyfunction]
fn hx(h: f64, x: f64, o_id: i32) -> f64 {
if h > H_MAX4 || h < H_MIN4 || x > 1.0 || x < 0.0 {
return INVALID_VALUE as f64;
}
match o_id {
OH => return h,
OX => return x,
_ => hx_reg4(h, x, o_id),
}
}

#[pyfunction]
fn sx(s: f64, x: f64, o_id: i32) -> f64 {
if s > S_MAX4 || s < S_MIN4 || x > 1.0 || x < 0.0 {
return INVALID_VALUE as f64;
}
match o_id {
OS => return s,
OX => return x,
_ => sx_reg4(s, x, o_id),
}
}

#[pymodule]
fn seuif97(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(pt, m)?)?;
m.add_function(wrap_pyfunction!(ph, m)?)?;
m.add_function(wrap_pyfunction!(ps, m)?)?;
m.add_function(wrap_pyfunction!(pv, m)?)?;

m.add_function(wrap_pyfunction!(tv, m)?)?;
m.add_function(wrap_pyfunction!(th, m)?)?;
m.add_function(wrap_pyfunction!(ts, m)?)?;

m.add_function(wrap_pyfunction!(hs, m)?)?;

m.add_function(wrap_pyfunction!(px, m)?)?;
m.add_function(wrap_pyfunction!(tx, m)?)?;
m.add_function(wrap_pyfunction!(hx, m)?)?;
m.add_function(wrap_pyfunction!(sx, m)?)?;
Ok(())
}

0 comments on commit 677b355

Please sign in to comment.