Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/type hinting #96

Merged
merged 12 commits into from
Nov 29, 2023
5 changes: 5 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 1.8
* Implemented type hinting
* Removed warning for geometry factors above 4
* Refactored material functions in `erosion.py`

## 1.7.9
* Add name to material properties dictionary

Expand Down
8 changes: 4 additions & 4 deletions pysand/asd.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

logger = logging.getLogger(__name__)

def validate_asd(**kwargs):
def validate_asd(**kwargs: float) -> bool:
"""
Validation of all input parameters that go into std_step_clampon, std_step_emerson and sand_rate functions;
"""
Expand All @@ -19,7 +19,7 @@ def validate_asd(**kwargs):
logger.warning('The model has got negative value(s) of {} and returned nan.'.format(i))
return True

def std_step_clampon(v_m, GLR):
def std_step_clampon(v_m: float, GLR: float) -> float:
'''
Standard step calculation for Clampon ASD's
:param v_m: fluid mix velocity at ASD [m/s]
Expand Down Expand Up @@ -47,7 +47,7 @@ def std_step_clampon(v_m, GLR):
return step


def std_step_emerson(v_m, GOR):
def std_step_emerson(v_m: float, GOR: float) -> float:
'''
Standard step calculation for Emerson ASD's
:param v_m: fluid mix velocity at ASD [m/s]
Expand All @@ -70,7 +70,7 @@ def std_step_emerson(v_m, GOR):
return step


def sand_rate(raw, zero, step, exp=1):
def sand_rate(raw: float, zero: float, step: float, exp: float=1) -> float:
'''
ASD sand rate calculation
:param raw: raw value from ASD
Expand Down
4 changes: 2 additions & 2 deletions pysand/choke.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
def critical_velocity(p1, p2, rho_1, rho_2):
def critical_velocity(p1: float, p2: float, rho_1: float, rho_2: float) -> float:
"""
Throttling velocity in the choke
DNVGL RP-O501, August 2015 - chapter 4.12.3
Expand All @@ -12,7 +12,7 @@ def critical_velocity(p1, p2, rho_1, rho_2):
return v_c


def min_choke(Qs, v_c):
def min_choke(Qs: float, v_c: float) -> float:
"""
Recommended minimum choke opening for plug/cage and cage/sleeve types of chokes
DNVGL RP-O501, August 2015 - chapter 4.12.3
Expand Down
162 changes: 89 additions & 73 deletions pysand/erosion.py

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions pysand/fluidproperties.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def validate_fluid_props(**kwargs):
logger.warning('The model has got negative value(s) of {} and returned nan.'.format(i))
return True

def mix_velocity(P, T, Qo, Qw, Qg, Z, D):
def mix_velocity(P: float, T: float, Qo: float, Qw: float, Qg: float, Z: float, D: float) -> float:
'''
Blackoil mixture velocity model, based on DNVGL RP-O501, August 2015 edition
:param P: Pressure [bar]
Expand All @@ -46,7 +46,8 @@ def mix_velocity(P, T, Qo, Qw, Qg, Z, D):
return np.round(v_m, 2)


def mix_density(P, T, Qo, Qw, Qg, rho_o, rho_w, MW, Z):
def mix_density(P: float, T: float, Qo: float, Qw: float, Qg: float,
rho_o: float, rho_w: float, MW: float, Z: float) -> float:
'''
Blackoil mixture density calculator, based on DNVGL RP-O501, August 2015 edition
:param P: Pressure [bar]
Expand Down Expand Up @@ -76,7 +77,7 @@ def mix_density(P, T, Qo, Qw, Qg, rho_o, rho_w, MW, Z):
return np.round(rho_m, 2)


def mix_viscosity(P, T, Qo, Qw, Qg, mu_o, mu_w, mu_g, Z):
def mix_viscosity(P: float, T: float, Qo: float, Qw: float, Qg: float, mu_o: float, mu_w: float, mu_g: float, Z: float) -> float:
'''
Blackoil mixture viscosity calculator, based on DNVGL RP-O501, August 2015 edition
Output viscosity units equals input units
Expand Down Expand Up @@ -106,7 +107,7 @@ def mix_viscosity(P, T, Qo, Qw, Qg, mu_o, mu_w, mu_g, Z):
return np.round(mu_m, 6)


def liq_density(Qo, Qw, rho_o, rho_w):
def liq_density(Qo: float, Qw: float, rho_o: float, rho_w: float) -> float:
"""
Weighted average of oil and water densities
:param Qo: Oil rate [Sm3/d]
Expand All @@ -125,7 +126,7 @@ def liq_density(Qo, Qw, rho_o, rho_w):
return rho_l


def liq_viscosity(Qo, Qw, mu_o, mu_w):
def liq_viscosity(Qo: float, Qw: float, mu_o: float, mu_w: float) -> float:
"""
Weighted average of oil and water viscosities
:param Qo: Oil rate [Sm3/d]
Expand Down
2 changes: 1 addition & 1 deletion pysand/probe.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def validate_inputs(**kwargs):
'to trust the quantification model.'.format(kwargs[i]))


def er_sand_rate(E_meas, v_m, rho_m, D, d_p, alpha=60):
def er_sand_rate(E_meas: float, v_m: float, rho_m: float, D: float, d_p: float, alpha: float=60) -> float:
"""
ER probe sand rate calculation, model reference to DNVGL RP-O501, August 2015.
This approach involve uncertainty, particularly at low bulk flow velocities; Should not be used when v_m < 5 m/s.
Expand Down
6 changes: 3 additions & 3 deletions pysand/transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
g = 9.80665 # Standard gravity [m/s^2]


def hydro(D, rho_l, mu_l, d_p, e=5e-5, rho_p=2650):
def hydro(D: float, rho_l: float, mu_l: float, d_p: float, e: float=5e-5, rho_p: float=2650) -> list[float, float]:
"""
Equinor sand transport model for horizontal pipelines
Based on T. Søntvedt (1995) and R. Schulkes (2002) work in Hydro
Derivative work based off of T. Søntvedt (1995) and R. Schulkes (2002) work in Hydro.
:param D: Pipe diameter [m]
:param rho_l: Liquid density [kg/m3]
:param mu_l: Dynamic liquid viscosity [Pa.s]
Expand Down Expand Up @@ -90,7 +90,7 @@ def critical_u(u, m):
return result


def stokes(rho_m, mu_m, d_p, angle, rho_p=2650):
def stokes(rho_m: float, mu_m: float, d_p: float, angle: float, rho_p: float=2650) -> float:
"""
Sand lifting rate calculation model for vertical or deviated (up to ~80 deg) inclination
Based on Stokes law for settling velocities, but corrected for turbulent flow around sand grains
Expand Down
2 changes: 1 addition & 1 deletion pysand/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.7.9'
__version__ = '1.8'
42 changes: 26 additions & 16 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
import pathlib
from setuptools import setup

exec(open('pysand/version.py').read())

HERE = pathlib.Path(__file__).parent
README = (HERE / "README.md").read_text()
def get_version():
with open('pysand/version.py') as version_file:
namespace = {}
exec(version_file.read(), namespace)
return namespace['__version__']

setup(name='pysand',
version=__version__,
description='Sand management related calculations',
long_description=README,
long_description_content_type="text/markdown",
author='Equinor ASA',
author_email='[email protected]',
license='GNU GPL',
url='https://github.com/equinor/pysand',
classifiers=["Programming Language :: Python :: 3"],
packages=['pysand'],
install_requires=['pandas', 'numpy>=1.17', 'scipy']
)
VERSION = get_version()

# Read the README.md file
home_dir = pathlib.Path(__file__).parent
README = (home_dir / "README.md").read_text()

if __name__ == "__main__":
setup(
name='pysand',
version=VERSION,
description='Sand management related calculations',
long_description=README,
long_description_content_type="text/markdown",
author='Equinor ASA',
author_email='[email protected]',
license='GNU GPL',
url='https://github.com/equinor/pysand',
classifiers=["Programming Language :: Python :: 3"],
packages=['pysand'],
install_requires=['pandas', 'numpy>=1.17', 'scipy']
)
36 changes: 19 additions & 17 deletions tests/test_erosion.py
sogunneroed marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import pysand.exceptions as exc
import logging
from pysand.erosion import validate_inputs, bend, tee, straight_pipe, \
welded_joint, manifold, reducer, probes, flexible, choke_gallery, F, material_properties, erosion_rate, nozzlevalve_wall
welded_joint, manifold, reducer, probes, flexible, choke_gallery, F, \
get_material_properties, get_materials, erosion_rate, nozzlevalve_wall

def test_validate_inputs(caplog):

Expand All @@ -14,14 +15,14 @@ def test_validate_inputs(caplog):
for inp in ['v_m', 'rho_m', 'mu_m', 'Q_s']:
for non_number in [None, 'string', np.nan]:
kwargs[inp] = non_number
with pytest.raises(exc.FunctionInputFail) as excinfo:
with pytest.raises(exc.FunctionInputFail):
validate_inputs(**kwargs)
kwargs[inp] = num

kwargs = {'crushed': False}
for non_bool in [None, 'string', np.nan]:
kwargs['crushed'] = non_bool
with pytest.raises(exc.FunctionInputFail) as excinfo:
with pytest.raises(exc.FunctionInputFail):
validate_inputs(**kwargs)

# Test v_m boundaries
Expand Down Expand Up @@ -68,7 +69,7 @@ def test_validate_inputs(caplog):
for inp in ['R', 'GF', 'D', 'd_p', 'h', 'Dm', 'D1', 'D2', 'alpha']:
for non_number in [None, 'string', np.nan, pd.Series(dtype='float64').any()]:
kwargs[inp] = non_number
with pytest.raises(exc.FunctionInputFail) as excinfo:
with pytest.raises(exc.FunctionInputFail):
validate_inputs(**kwargs)
kwargs[inp] = num

Expand Down Expand Up @@ -99,10 +100,10 @@ def test_validate_inputs(caplog):
"Particle diameter, d_p, is outside RP-O501 model boundaries (0.02 - 5 mm)." in s.message for s in info)

# Test geometry factor limitations
kwargs = {'GF': 6}
kwargs = {'GF': 0.5}
with caplog.at_level(logging.WARNING):
validate_inputs(**kwargs)
assert "Geometry factor, GF, can only be 1, 2, 3 or 4" in str(caplog.records)
assert "Geometry factor, GF, can only be 1 or higher" in str(caplog.records)

# Test bend radius boundaries
kwargs = {'R': 1}
Expand Down Expand Up @@ -145,7 +146,7 @@ def test_validate_inputs(caplog):
kwargs = {'R_c': R_c, 'gap': gap, 'H': H}
for i in kwargs.keys():
kwargs[i] = -1
with pytest.raises(exc.FunctionInputFail) as excinfo:
with pytest.raises(exc.FunctionInputFail):
validate_inputs(**kwargs)

kwargs['R_c'] = R_c
Expand Down Expand Up @@ -320,30 +321,31 @@ def test_F(a_rad, angle_dependency, E):
assert F(a_rad, angle_dependency) == E

angle_dependency = 'something_else'
with pytest.raises(exc.FunctionInputFail) as excinfo:
with pytest.raises(exc.FunctionInputFail):
F(a_rad, angle_dependency)


# Material properties function #
# Material properties function
material_validation = [('carbon_steel', (7800, 2e-9, 2.6, 'ductile')),
('grp_epoxy', (1800, 3e-10, 3.6, 'ductile')),
('psz_ceramic_zirconia', (5700, 4.1e-9, 2.5, 'brittle'))]
@pytest.mark.parametrize('material, E', material_validation)
def test_material_properties(material, E):
assert material_properties(material) == E
def test_get_material_properties(material, E):
assert get_material_properties(material) == E


def test_get_material_properties_invalid_material():
with pytest.raises(exc.FunctionInputFail):
get_material_properties(material='invalid material')

# Test material list and error raising
def test_material():
def test_get_materials():
material_list = ['carbon_steel', 'duplex', 'ss316', 'inconel', 'grp_epoxy', 'grp_vinyl_ester', 'hdpe', 'aluminium',
'dc_05_tungsten', 'cs_10_tungsten', 'cr_37_tungsten', '95_alu_oxide', '99_alu_oxide',
'psz_ceramic_zirconia', 'ZrO2-Y3_ceramic_zirconia', 'SiC_silicon_carbide', 'Si3N4_silicon_nitride',
'TiB2_titanium_diboride', 'B4C_boron_carbide', 'SiSiC_ceramic_carbide']
material = 'list'
assert material_properties(material) == material_list
assert get_materials() == material_list

material = 'something_else'
with pytest.raises(exc.FunctionInputFail) as excinfo:
material_properties(material)

def test_return_nan():
v_m = 29.3
Expand Down
Loading