overthesun / simoc

A scalable model of an interactive, off-world community
https://ngs.simoc.space/
GNU General Public License v3.0
2 stars 1 forks source link

Macronutrients and calories tracking #161

Open ezio-melotti opened 2 years ago

ezio-melotti commented 2 years ago

We discussed tracking calories and macronutrients (aka macros, i.e. carbs, proteins, fats) to ensure the humans gets both enough calories and a balanced diet. The average amount of calories and macros breakdown is known for each type of food, so we can add these data to the currency_desc.json file. The amount of calories is also related to #153, however the current issue is independent from the calories validation -- i.e. for now we can still assume average calories without necessarily validate that the plant got enough energy input to produce them.

The calories and macro breakdown values are available from different sources, e.g.:

The USDA DBs seem available for download here: https://fdc.nal.usda.gov/download-datasets.html

From these data we can figure out the ratio of the macro and calculate both the total amount of calories and the amount of each macro based on the mass of the given food. We also know that carbs, proteins, and fats, have respectively 4, 4, and 9 calories.

I included below extract from a couple of mail threads that provide more background and information.


This is copied from the thread Future features for SIMOC from 2020-11-01. It discusses the chemical composition of the macros in the context of elemental validation. However it appears that attempting to track and/or validate chemical elements contained inside macros is not a realistic endeavor, and the following is just copied for reference/curiosity.

https://en.wikipedia.org/wiki/Nutrient#Macronutrients says:

https://en.wikipedia.org/wiki/Protein_(nutrient) says that proteins are made by amino acids linked together by peptide bonds. The composition of the amino acids is known, but it might be difficult to determine which amino acids form the different kinds of proteins.

https://en.wikipedia.org/wiki/Carbohydrate#Division these seem to be the most complex with three major classes further divided in subgroups and components. If our food source is limited to plants it might be easier to find out the components.

https://en.wikipedia.org/wiki/Fat#Chemical_structure says that different kinds of fats contain different amounts of saturated, monounsaturated, polyunsaturated fats, and these amounts might be known (depending on the food). It also mentions that triglycerides are the most commonly fat eaten by humans, and their chemical formula is known.


This is copied from the thread [simoc] meeting minutes - dev: 2021 10/17. It discusses the relation between calories and macros (with some math) and speculates on the relation between macros and elements.

[...] given the same amount of C/H/O elements, you could have a different amount of calories based on how those elements are combined. What I think is responsible for this difference is the energy stored in the chemical bounds of the molecules that form the macronutrients -- energy that is released as our digestive system burns the macros down and releases the energy from the bounds to be used by the human.

Even though the amount of energy released depends on the amount of energy stored in the chemical bounds of the molecules (which in turn depends on the type/amount of molecules/macros), the energy is still somewhat independent from the total mass/breakdown of the elements (within certain limits). In order to form certain molecules of carbs/protein/fat the plant will require varying amounts of energy, and the total energy of the potato will be equal to the sum of the energy that went in the potato and got stored in the molecular bounds, regardless of the actual molecular composition of the potato.

We know that:

food = C + H + O (+ others)
food = carbs + prot + fat
total_calories = carbs*4 + proteins*4 + fat*9

So with 1kg of potatoes we have:

potato_mass = 1kg
potato_calories = 770 calories / kg
potato = 170g (carbs) + 20g (protein) + 1g (fat) (+ 809g (others (water?))) = 1kg
potato_calories = 680 (170*4 carbs) + 80 (20*4 proteins) + 9 (1*9 fat) == 769 calories

So far, my potato math seems to check out. Note that for most foods we know both the average carbs/proteins/fat breakdown and the average amount of calories, since one can be derived from the other.

I tried to go one step further but as expected it gets tricky. The empirical formula for carbs is C_m(H2O)_n (where m and n are variable), for protein it seems to be RCH(NH2)COOH (with R representing a variable group of amino acids), and for fats it seems even more complicated: https://chem.libretexts.org/Bookshelves/General_Chemistry/Book%3A_ChemPRIME_(Moore_et_al.)/03%3A_Using_Chemical_Equations_in_Calculations/3.05%3A_Analysis_of_Compounds/3.5.01%3A_Foods-_Burning_or_Metabolizing_Fats_and_Sugars

One thing that I'm trying to figure out is that we know that 1kg of potatoes has, on average, 770 calories. We saw that the amount of calories depends on the energy that went into the potato. If we had a blackout in the greenhouse and grew less-than-average potatoes, then the 1kg of potatoes that we harvest will likely have less than the average 770 calories.

I haven't looked into the relation between energy/heat/calories yet, but they should be related, and in theory we should be able to calculate the actual amount of calories for each potato we harvest based on how much energy went into the potato while it was growing. [see #153]

So it seems to me that:

ezio-melotti commented 2 years ago

FWIW I took a quick look at the data included in the JSON DB:


>>> import json
>>> with open('FoodData_Central_survey_food_json_2021-10-28.json') as f: j = json.load(f)
...
>>> j.keys()
dict_keys(['SurveyFoods'])
>>> j = j['SurveyFoods']
>>> p = [x for x in j if 'potato' in x['description'].lower()]  # find all potatoes
>>> p.sort(key=lambda x: len(x['description']))  # sort them by name length
>>> [x['description'] for x in p[:10]]  # print the first 10 results
['Potato, NFS', 'Potato patty', 'Bread, potato', 'Knish, potato', 'Potato pancake', 'Potato chowder',
 'Gnocchi, potato', 'Stewed potatoes', 'Potato tots, NFS', 'Pie, sweet potato']
>>> potato = p[0]  # take the first potato
>>> potato.keys()
dict_keys(['foodClass', 'description', 'foodNutrients', 'foodAttributes', 'foodCode', 'startDate',
 'endDate', 'wweiaFoodCategory', 'fdcId', 'dataType', 'publicationDate', 'inputFoods', 'foodPortions'])
>>> potato['foodNutrients'][0]  # inspect the nutrients
{'type': 'FoodNutrient', 'id': 13224203, 'nutrient': {'id': 1003, 'number': '203', 'name': 'Protein',
 'rank': 600, 'unitName': 'g'}, 'amount': 1.87}
>>> potato['foodNutrients'][1]
{'type': 'FoodNutrient', 'id': 13224204, 'nutrient': {'id': 1004, 'number': '204', 'name': 'Total lipid (fat)',
 'rank': 800, 'unitName': 'g'}, 'amount': 4.24}
>>> # print all the nutrients
>>> for fn in potato['foodNutrients']:
...     print(f'{fn["nutrient"]["name"]:<20}: {fn["amount"]:>5} {fn["nutrient"]["unitName"]}')
... 
Protein             :  1.87 g
Total lipid (fat)   :  4.24 g
Carbohydrate, by difference:  20.4 g
Energy              :   125 kcal
Alcohol, ethyl      :   0.0 g
Water               :  72.1 g
Caffeine            :   0.0 mg
Theobromine         :   0.0 mg
Sugars, total including NLEA:  1.61 g
Fiber, total dietary:   1.4 g
Calcium, Ca         :   5.0 mg
Iron, Fe            :  0.34 mg
Magnesium, Mg       :  24.0 mg
Phosphorus, P       :  48.0 mg
Potassium, K        :   372 mg
Sodium, Na          :   167 mg
Zinc, Zn            :  0.28 mg
Copper, Cu          : 0.204 mg
Selenium, Se        :   0.3 µg
Retinol             :  17.0 µg
Vitamin A, RAE      :  18.0 µg
Carotene, beta      :   8.0 µg
Carotene, alpha     :   0.0 µg
Vitamin E (alpha-tocopherol):  0.52 mg
Vitamin D (D2 + D3) :   0.0 µg
Cryptoxanthin, beta :   0.0 µg
Lycopene            :   0.0 µg
Lutein + zeaxanthin :   0.0 µg
Vitamin C, total ascorbic acid:  12.1 mg
Thiamin             :   0.1 mg
Riboflavin          : 0.021 mg
Niacin              :  1.32 mg
Vitamin B-6         : 0.312 mg
Folate, total       :   9.0 µg
Vitamin B-12        :   0.0 µg
Choline, total      :  14.1 mg
Vitamin K (phylloquinone):   4.1 µg
Folic acid          :   0.0 µg
Folate, food        :   9.0 µg
Folate, DFE         :   9.0 µg
Vitamin E, added    :   0.0 mg
Vitamin B-12, added :   0.0 µg
Cholesterol         :   3.0 mg
Fatty acids, total saturated:   1.2 g
SFA 4:0             : 0.046 g
SFA 6:0             : 0.029 g
SFA 8:0             : 0.017 g
SFA 10:0            : 0.037 g
SFA 12:0            : 0.041 g
SFA 14:0            : 0.108 g
SFA 16:0            : 0.621 g
SFA 18:0            : 0.271 g
MUFA 18:1           :  1.49 g
PUFA 18:2           :  1.15 g
PUFA 18:3           : 0.158 g
PUFA 20:4           :   0.0 g
PUFA 22:6 n-3 (DHA) :   0.0 g
MUFA 16:1           : 0.024 g
PUFA 18:4           :   0.0 g
MUFA 20:1           : 0.013 g
PUFA 2:5 n-3 (EPA)  :   0.0 g
MUFA 22:1           :   0.0 g
PUFA 22:5 n-3 (DPA) :   0.0 g
Fatty acids, total monounsaturated:  1.52 g
Fatty acids, total polyunsaturated:  1.31 g
>>>
granawkins commented 2 years ago

As part of the "Plant CO2 Responses" project, I want to measure usable kcal per m2 of crop, in order to quantify the increase and develop some composite metrics for plant fitness. I've updated the currency_desc.json to the following format on the latest working branch:

        "rice": {
            "description": "Rice, white, regular, cooked",
            "source": "http://www.nutritiontable.com/nutritions/nutrient/?id=796",
            "unit": "kg",
            "nutrition": {
                "kcal": 960,
                "water": 753,
                "protein": 25,
                "carbohydrate": 200,
                "fat": 4
            },
            "label": "Rice"
        },

On our December 29 call, Kai sent a file named plant_energy.pdf which contains values per plant in kJ. Following the link back to the source, a detailed breakdown is given including all the fields above (and much more).

I used the values from that pdf to determine which specific plant to reference (e.g. dry_bean = Lima beans, cooked, boiled), and note it explicitly in the currency_desc along with a link to the data.

I have preliminary values for rations based on the BVAD, as referenced by our new source for human input values (#167), but we should discuss how/whether to account for rehydrating water when consuming rations.

In terms of next steps: A) For the "Plant CO2 Responses" project, this is enough. I can simply convert kg to kcal when compiling charts and fitness metrics. B) As a general project, we should modify humans so their food consumption is based on calories instead of kilograms, and build out functionality to support that. C) We should display the macronutrient breakdown of the current diet on the frontend, and figure out the best way to do this.