Source code for dipplanner.tools
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2011-2012 Thomas Chiroux
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.
# If not, see <http://www.gnu.org/licenses/gpl.html>
#
# This module is part of dipplanner, a Dive planning Tool written in python
"""tools modules
This modules contains some utility functions like unit conversions, etc...
"""
__authors__ = [
# alphabetical order by last name
'Thomas Chiroux', ]
import math
import re
# local imports
from dipplanner import settings
[docs]def safe_eval_calculator(text_to_eval):
"""Small an safe eval function usable only for simple calculation
(only the basic operators)
*Keyword Arguments:*
:text_to_eval: (float) -- the text (formula) that should be evaluated
*Returns:*
float -- the result of the calculation.
*Raise:*
ValueError: when given expression is not constitued of only
numbers and operators
SyntaxError: when the given expression is incorrect
"""
expr = "^([0-9]|\+|\*|\/|\-|\.|\ )+$"
re_result = re.match(expr, text_to_eval)
if re_result is None:
raise ValueError("Only numbers and simple operators (*+-/) "
"are allowed")
else:
return eval(re_result.group(0), {'__builtins__': None}, {})
[docs]def seconds_to_mmss(seconds):
"""Convert a value in seconds into a string representing the time in
minutes and seconds
(like 2:06)
It does returns only minutes and seconds, not hours, minutes and seconds
*Keyword Arguments:*
:seconds: (float) -- the duration in seconds
*Returns:*
str -- the time in minutes and seconds
ex:
" 23:45"
"112:33"
...
*Raise:*
ValueError: when bad time values
"""
if seconds < 0:
raise ValueError("time can not be negative")
text = "%3d:%02d" % (int(seconds / 60), int(seconds % 60))
return text
[docs]def seconds_to_hhmmss(seconds):
"""Convert a value in seconds into a string representing the time
in hour:minutes and seconds
like 22:34:44
*Keyword Arguments:*
:seconds: (float) -- the duration in seconds
*Returns:*
str -- the time in hour - minutes and seconds
ex:
"00:23:45"
"01:52:33"
*Raise:*
ValueError: when bad time values is given
"""
if seconds < 0:
raise ValueError("time can not be negative")
hours = seconds // (60 * 60)
seconds %= (60 * 60)
minutes = seconds // 60
seconds %= 60
return "%02i:%02i:%02i" % (hours, minutes, seconds)
[docs]def altitude_or_depth_to_absolute_pressure(altitude_or_depth):
"""output absolute pressure for give "depth" in meter.
* If depth is positive it's considered altitude depth
* If depth is negative it's considered depth in water
*Keyword Arguments:*
:altitude_or_depth: (float (signed)) -- in meter
*Returns:*
float -- resulting absolute pressure in bar
*Raise:*
ValueError if altitude > 10000m
"""
if altitude_or_depth < 0:
return depth_to_pressure(-altitude_or_depth) + \
settings.AMBIANT_PRESSURE_SURFACE
else:
return altitude_to_pressure(altitude_or_depth)
[docs]def altitude_to_pressure(altitude):
"""Convert a given altitude in pressure in bar
uses the formula:
p = 101325.(1-2.25577.10^-5.h)^5.25588
*Keyword Arguments:*
:altitude: (float) -- current altitude in meter
*Returns:*
float -- resulting pressure in bar
*Raise:*
ValueError: when bad altitude is given (bad or <0 or > 10000 m)
"""
if altitude < 0:
raise ValueError("altitude can not be negative")
if altitude > 10000:
raise ValueError("altitude can not higher than 10000m")
return math.pow(1 - 2.25577 * math.pow(10, -5) * altitude, 5.25588) * \
settings.AMBIANT_PRESSURE_SEA_LEVEL
[docs]def depth_to_pressure(depth, method=settings.METHOD_FOR_DEPTH_CALCULATION):
"""Calculates depth pressure based on depth using a more complex
method than only /10
*Keyword Arguments:*
:depth: (float) -- in meter
*Returns:*
float -- depth pressure in bar
*Raise:*
<nothing>
"""
if method == 'complex':
g = 9.81
return settings.WATER_DENSITY * 1E3 * g * float(depth) * 1E-5
else:
return float(depth) / 10
[docs]def pressure_to_depth(pressure, method=settings.METHOD_FOR_DEPTH_CALCULATION):
"""Calculates depth based on give pressure using a more complex
method than only *10
*Keyword Arguments:*
:pressure: (float) -- pressure in bar
*Returns:*
float -- depth in meter
*Raise:*
<nothing>
"""
if method == 'complex':
g = 9.81
return float(pressure) / (settings.WATER_DENSITY * 1E3 * g * 1E-5)
else:
return float(pressure) * 10
[docs]def calculate_pp_h2o_surf(temperature=20):
"""Calculates and return vapor pressure of water at surface
using Antoine equation
(http://en.wikipedia.org/wiki/Vapour_pressure_of_water)
*Keyword Arguments:*
:temperature: (float) [OPTIONNAL] -- in ° Celcius
*Returns:*
float -- ppH2O in bar
*Raise:*
ValueError -- when temperature exceed maximum value for calculation
(>=374 °C)
"""
mm_hg_to_bar = 1.0 / 750.0615
if temperature < 1:
temperature = 1
if temperature >= 1 and temperature <= 100:
const_a = 8.07131
const_b = 1730.63
const_c = 233.426
elif temperature > 100 and temperature < 374:
const_a = 8.14019
const_b = 1810.94
const_c = 244.485
else:
raise ValueError("Temperature is too High")
pressure_mm_hg = 10 ** (const_a - (const_b / (const_c +
float(temperature))))
return pressure_mm_hg * mm_hg_to_bar
[docs]def convert_bar_to_psi(value):
"""SI --> imperial pressure conversion function
*Keyword Arguments:*
:value: (float) -- pressure in bar
*Returns:*
float -- pressure in psi
*Raise:*
<nothing>
"""
return float(value) * 14.5037744
[docs]def convert_psi_to_bar(value):
"""imperial --> SI pressure conversion function
*Keyword Arguments:*
:value: (float) -- pressure in psi
*Returns:*
float -- pressure in bar
*Raise:*
<nothing>
"""
return float(value) / 14.5037744
[docs]def convert_liter_to_cubicfeet(value):
"""SI --> imperial volume conversion function
*Keyword Arguments:*
:value: (float) -- volume in liter
*Returns:*
float -- volume in cubicfeet
*Raise:*
<nothing>
"""
return float(value) / (math.pow(0.3048, 3) * 1000)
[docs]def convert_cubicfeet_to_liter(value):
"""imperial --> SI volume conversion function
*Keyword Arguments:*
:value: (float) -- volume in cubicfeet
*Returns:*
float -- volume in liter
*Raise:*
<nothing>
"""
return float(value) * (math.pow(0.3048, 3) * 1000)
[docs]def convert_meter_to_feet(value):
"""SI --> imperial distance conversion function
*Keyword Arguments:*
:value: (float) -- volume in cubicfeet
*Returns:*
float -- volume in liter
*Raise:*
<nothing>
"""
return float(value) / 0.3048
[docs]def convert_feet_to_meter(value):
"""imperial --> SI distance conversion function
*Keyword Arguments:*
:value: (float) -- volume in cubicfeet
*Returns:*
float -- volume in liter
*Raise:*
<nothing>
"""
return float(value) * 0.3048