Source code for boozelib

""" Calculate blood alcohol content.

Functions to calculate the **blood alcohol content** of people.

Global Variables
================

This uses some constants and one variable you might want to review:

- :data:`ALCOHOL_DEGRADATION`: the default value for alcohol degradation;
  meaning the amount of alcohol (in gram) your body is degrading per minute, per
  kilogram body weight. This is usually a value between ``0.0017`` and
  ``0.0025`` (about 0.1—0.2 per thousand per hour).

Functions
=========

The two main functions are:

- ``get_blood_alcohol_content(age, weight, height, sex, volume, percent)``

    Return the **blood alcohol contents** raise (per mill) for a person after a
    drink.

    Given a drink containing *volume* (ml) of alcohol with the *percent*
    (vol/vol), for a person with *age* (years), *weight* (kg) and *height* (cm),
    using the formular for "female body types" if *sex* is true.

- ``get_blood_alcohol_degradation(
        age, weight, height, sex, minutes=1, degradation=None,
    )``

    Return the alcohol degradation (per mill) for a person over *minutes*.

    For a person with *age* (years), *weight* (kg) and *height* (cm), using the
    formular for "female body types" if *sex* is true, over the given *minutes*.
    If *degradation* is not set, :data:`ALCOHOL_DEGRADATION` is used as default.

Examples
--------

Return the **blood alcohol contents** raise (per mill) for a person after a
drink:

>>> get_blood_alcohol_content(
...     age=32, weight=96, height=186, sex=False, volume=500, percent=4.9
... )
0.28773587455687716

>>> get_blood_alcohol_content(
...     age=32, weight=48, height=162, sex=True, volume=500, percent=4.9
... )
0.5480779730398769

And to calculate alcohol degradation:

>>> get_blood_alcohol_degradation(
...     age=32, weight=96, height=186, sex=False, minutes=60
... )
0.21139778538872606

>>> get_blood_alcohol_degradation(
...     age=32, weight=48, height=162, sex=True, minutes=60
... )
0.20133476560648536

You can change the default for *alcohol degradation* globally via setting
:data:`ALCOHOL_DEGRADATION`. Or change the value for *alcohol degradation* per
call:

>>> get_blood_alcohol_degradation(
...     age=32, weight=48, height=162, sex=True, minutes=60, degradation=0.002
... )
0.16106781248518828

Thanks and Contributions
========================

* Big hugs to Mathilda for hanging around and helping me figuring out all that
  math and biology stuff.

If you find any bugs, issues or anything, please use the `issue tracker`_ on
GitHub.

.. _`issue tracker`: https://github.com/brutus/boozelib/issues

"""
import warnings
from typing import Optional

__version__ = "0.7.0"
__author__ = "Brutus [DMC] <brutus.dmc@googlemail.com>"
__license__ = (
    "GNU General Public License v3 or above - "
    "http://www.opensource.org/licenses/gpl-3.0.html"
)


__all__ = (
    "calculate_alcohol_degradation",
    "calculate_alcohol_weight",
    "calculate_body_water",
    "get_blood_alcohol_content",
    "get_blood_alcohol_degradation",
    "gramm_to_promille",
    "promille_to_gramm",
)


ALCOHOL_DENSITY: float = 0.8  #: density of alcohol (g/ml)
BLOOD_DENSITY: float = 1.055  #: density of blood (g/ml)
WATER_IN_BLOOD: float = 0.8  #: parts of water in blood (%)
ALCOHOL_DEGRADATION: float = 0.0025  #: for kg body weight per minute (g)

ALCOHOL_DEGRADATION_WARNING = """
In the next version the value used for alcohol degradation will be lowered. To
keep the current default, you can override `ALCOHOL_DEGRADATION`, or use the new
*degradation* argument to the `calculate_alcohol_degradation` and
`get_blood_alcohol_degradation` functions.
"""


[docs]def calculate_alcohol_weight(*, volume: int, percent: float) -> float: """Return the amount of alcohol (in gramm) contained in a drink. Given a drink with a *volume* (ml) containing *percent* (vol/vol) alcohol. """ return ALCOHOL_DENSITY * volume * (percent / 100)
[docs]def calculate_alcohol_degradation( *, weight: int, minutes: int = 1, degradation: Optional[float] = None ) -> float: """Return the alcohol degeneration (in gramm) over time. For a person with *weight* (in kg) over the given *minutes*. If *degradation* is not set, :data:`ALCOHOL_DEGRADATION` is used as default. """ warnings.warn(ALCOHOL_DEGRADATION_WARNING, DeprecationWarning) if degradation is None: degradation = ALCOHOL_DEGRADATION return degradation * weight * minutes
[docs]def calculate_body_water(*, age: int, weight: int, height: int, sex: bool) -> float: """Return the amount of water (in liter) in a persons body. For a person with *age* (years), *weight* (kg) and *height* (cm), using the formular for "female body types" if *sex* is true. """ if sex: # female return 0.203 - (0.07 * age) + (0.1069 * height) + (0.2466 * weight) else: # male return 2.447 - (0.09516 * age) + (0.1074 * height) + (0.3362 * weight)
[docs]def promille_to_gramm(*, promille: float, body_water: float) -> float: """Return the ammount of alcohol in a persons body (in gramm), given *promille* and *body water* (in liter). """ return (promille * (BLOOD_DENSITY * body_water)) / WATER_IN_BLOOD
[docs]def gramm_to_promille(*, gramm: float, body_water: float) -> float: """Return the blood alcohol contents of a person, given alcohol (in *gramm*) and *body water* (in liter). """ return (gramm * WATER_IN_BLOOD) / (BLOOD_DENSITY * body_water)
[docs]def get_blood_alcohol_content( *, age: int, weight: int, height: int, sex: bool, volume: int, percent: float, ) -> float: """Return the blood alcohol contents raise (per mill) for a person after a drink. Given a drink containing *volume* (ml) of alcohol with the *percent* (vol/vol), for a person with *age* (years), *weight* (kg) and *height* (cm), using the formular for "female body types" if *sex* is true. """ gramm = calculate_alcohol_weight(volume=volume, percent=percent) body_water = calculate_body_water(age=age, weight=weight, height=height, sex=sex) return gramm_to_promille(gramm=gramm, body_water=body_water)
[docs]def get_blood_alcohol_degradation( *, age: int, weight: int, height: int, sex: bool, minutes: int = 1, degradation: Optional[float] = None, ) -> float: """Return the alcohol degradation (per mill) for a person over *minutes*. For a person with *age* (years), *weight* (kg) and *height* (cm), using the formular for "female body types" if *sex* is true, over the given *minutes*. If *degradation* is not set, :data:`ALCOHOL_DEGRADATION` is used as default. """ warnings.warn(ALCOHOL_DEGRADATION_WARNING, DeprecationWarning) if degradation is None: degradation = ALCOHOL_DEGRADATION gramm = calculate_alcohol_degradation( weight=weight, minutes=minutes, degradation=degradation ) body_water = calculate_body_water(age=age, weight=weight, height=height, sex=sex) return gramm_to_promille(gramm=gramm, body_water=body_water)