# -*- coding: utf-8 -*-
# SPDX-FileCopyrightText: 2022-2023 Tanguy Fardet
# SPDX-License-Identifier: GPL-3.0-or-later
# orgmatt/agrifood/human_consumption.py
from collections import defaultdict
from typing import Optional, Union
from pint import Quantity
from .._utils import _filter_dataframe, return_values, auto_format
from ..data import nutrients_intake
from ..typing import NumericArrayLike, NumericOrArray
from ..units import check_dim, day, g, gN, ureg
[docs]
@check_dim(arglist=('nitrogen_mass', 0, '[mass]*[nitrogen]'), result='[mass]')
def nitrogen_to_protein(
nitrogen_mass: Quantity,
food_type: Optional[str] = None
) -> Quantity:
'''
Calculate the amount of nitrogen associated to a mass of protein based
on the conversion factors from [Mariotti2008]_.
Parameters
----------
protein_mass : float [mass]*[nitrogen]
Mass of protein to convert to nitrogen content.
food_type : str, optional (default: average conversion factor)
Type of food considered, among: 'dairy', 'meat' (including fish and
eggs), 'cereal' (except corn), 'corn', 'soy', 'legume' (except soy),
and 'vegetable' (including mushrooms). If not specified or invalid, a
default conversion factor of 5.6 g of protein per gram of nitrogen is
used.
References
----------
.. [Mariotti2008] Mariotti, Tomé, and Mirand. "Converting Nitrogen into
Protein—Beyond 6.25 and Jones’ Factors." Critical Reviews in Food
Science and Nutrition 48-2 (2008): 177‑84.
:doi:`10.1080/10408390701279749`.
'''
food_type = "other" if food_type is None else food_type
convertor: dict[str, float] = defaultdict(lambda: 5.6)
convertor.update({
"dairy": 5.85,
"meat": 5.6,
"cereal": 5.4,
"corn": 5.6,
"soybean": 5.5,
"legume": 5.4,
"vegetable": 4.4
})
return nitrogen_mass.to(gN).m * convertor[food_type.lower()] * g
[docs]
@check_dim(arglist=('protein_mass', 0, '[mass]'), result='[mass]*[nitrogen]')
def protein_to_nitrogen(
protein_mass: Quantity,
food_type: Optional[str] = None
) -> Quantity:
'''
Calculate the amount of nitrogen associated to a mass of protein based
on Jones' factors (simply 6.25 for now).
Parameters
----------
protein_mass : float [mass]
Mass of protein to convert to nitrogen content.
food_type : str, optional (default: average conversion factor)
Type of food considered, among: 'dairy', 'meat' (including fish and
eggs), 'cereal' (except corn), 'corn', 'soy', 'legume' (except soy),
and 'vegetable' (including mushrooms). Currently unused, a 6.25
conversion factor is used for all food types.
'''
return protein_mass.to("gram").m / 6.25 * gN
[docs]
@auto_format
@check_dim(arglist=('duration', 1, '[time]'), result='[mass]*[X]')
def nutrient_intake(
pop: NumericOrArray,
duration: Quantity,
nutrient: str,
ci: int = 0,
q: Optional[NumericArrayLike] = None,
**kwargs
) -> Quantity:
'''
Compute the amount of nutrient ingested by a given population over a
certain duration using the ``food.csv`` database.
Parameters
----------
pop : float or list-like object
Number of inhabitants.
duration : float [time]
Time interval over which the nitrogen is excreted.
nutrient : str
Nutrient of interest among ('N', 'K', 'P', 'Mg', 'Ca').
ci : int (optional, default: 0)
Confidence interval (CI). If non-zero, the function will also return
the low and high expected values corresponding to that CI.
q : array-like of floats (optional: default: None)
Percentiles to compute (supersedes `ci`).
**kwargs : arguments to use a subset of the database
Additional arguments can be use to restrict the results to a subset of
the full database. E.g. one can add `excreta="feces"` to return only
nitrogen contained in feces, or `region="Europe"` to use only values
obtained from studies in European countries.
Returns
-------
nutrient_mass : float or array of dimension D [mass]
Mean mass of excreted nitrogen if `q` is None or `ci` is 0. If `q` is
provided, returns the values associated to each percentile in `q` for
each entry in `amount`; otherwise one (low, mean, high) result per
entry in `amount`, giving the masses expected for the requested
confidence interval.
The dimension D is either 3, len(q), (len(amount), 3), or
(len(amount), len(q)) depending on `ci` and `q`.
Notes
-----
* Nitrogen results are computed from protein data via
:func:`~orgmatt.agrifood.protein_to_nitrogen` using the default value.
* By default, only values for adults are returned, use `group` or `age` to
select a specific subpopulation.
'''
# special case for N that is computed from protein data
cmpd = "protein" if nutrient == "N" else nutrient
df = nutrients_intake[nutrients_intake.compound == cmpd]
df = _filter_dataframe(df, kwargs)
nintake = return_values(df, "intake", pop, ci, q)
if cmpd == "protein":
# special case for N, we convert from N to protein
return protein_to_nitrogen(duration*nintake*g/day)
return ureg(f'mg{nutrient}/day') * duration * nintake