Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -702,149 +702,105 @@ BASE_PROFILE = {
|
|
| 702 |
'N (NH4+)': 0
|
| 703 |
}
|
| 704 |
|
| 705 |
-
#
|
| 706 |
-
|
| 707 |
-
"Кальциевая селитра": {
|
| 708 |
-
|
| 709 |
-
},
|
| 710 |
-
"
|
| 711 |
-
|
| 712 |
-
}
|
| 713 |
-
"Калий сернокислый": {
|
| 714 |
-
"K": 0.448, "S": 0.184
|
| 715 |
-
},
|
| 716 |
-
"Аммоний азотнокислый": {
|
| 717 |
-
"N (NO3-)": 0.175, "N (NH4+)": 0.175
|
| 718 |
-
},
|
| 719 |
-
"Сульфат магния": {
|
| 720 |
-
"Mg": 0.098, "S": 0.13
|
| 721 |
-
},
|
| 722 |
-
"Калий фосфорнокислый": {
|
| 723 |
-
"P": 0.228, "K": 0.287
|
| 724 |
-
},
|
| 725 |
-
"Монофосфат калия": {
|
| 726 |
-
"P": 0.228, "K": 0.287
|
| 727 |
-
}
|
| 728 |
}
|
| 729 |
|
| 730 |
class NutrientCalculator:
|
| 731 |
def __init__(self, volume_liters=1.0):
|
| 732 |
self.volume = volume_liters
|
| 733 |
self.results = {}
|
| 734 |
-
self.
|
| 735 |
self.total_ppm = sum(BASE_PROFILE.values()) + TOTAL_NITROGEN
|
| 736 |
-
self.
|
| 737 |
-
|
| 738 |
-
|
| 739 |
-
|
| 740 |
-
|
| 741 |
|
| 742 |
def calculate(self):
|
| 743 |
-
# 1. Вносим
|
| 744 |
-
self.
|
| 745 |
-
|
| 746 |
-
|
| 747 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 748 |
self._apply_potassium_sulfate()
|
| 749 |
-
self._apply_potassium_nitrate()
|
| 750 |
-
self._apply_monopotassium_phosphate()
|
| 751 |
|
| 752 |
-
#
|
| 753 |
-
self.
|
| 754 |
|
| 755 |
-
#
|
| 756 |
-
self.
|
| 757 |
|
| 758 |
return self.results
|
| 759 |
|
| 760 |
-
def _apply_fertilizer(self,
|
| 761 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 762 |
'граммы': round(grams, 3),
|
| 763 |
'миллиграммы': int(grams * 1000),
|
|
|
|
| 764 |
}
|
| 765 |
-
self.results[fert_name].update(additions)
|
| 766 |
-
|
| 767 |
-
def _adjust_negative_values(self):
|
| 768 |
-
for element in self.final_profile:
|
| 769 |
-
if self.final_profile[element] < 0:
|
| 770 |
-
self.final_profile[element] = 0
|
| 771 |
-
|
| 772 |
-
def _recalculate_actual_nitrogen(self):
|
| 773 |
-
# Пересчитываем фактическое содержание азота на основе внесенных удобрений
|
| 774 |
-
no3_added = 0
|
| 775 |
-
nh4_added = 0
|
| 776 |
-
|
| 777 |
-
for fert in self.results.values():
|
| 778 |
-
if 'внесет NO3' in fert:
|
| 779 |
-
no3_added += fert['внесет NO3']
|
| 780 |
-
if 'внесет NH4' in fert:
|
| 781 |
-
nh4_added += fert['внесет NH4']
|
| 782 |
-
|
| 783 |
-
self.final_profile['N (NO3-)'] = no3_added
|
| 784 |
-
self.final_profile['N (NH4+)'] = nh4_added
|
| 785 |
-
|
| 786 |
-
def _apply_magnesium_sulfate(self):
|
| 787 |
-
mg_need = self.final_profile['Mg']
|
| 788 |
-
if mg_need <= 0:
|
| 789 |
-
return
|
| 790 |
-
|
| 791 |
-
mg_content = self.fertilizers_db["Сульфат магния"]["Mg"]
|
| 792 |
-
grams = (mg_need * self.volume) / (mg_content * 1000)
|
| 793 |
-
added_s = grams * self.fertilizers_db["Сульфат магния"]["S"] * 1000 / self.volume
|
| 794 |
-
|
| 795 |
-
self.final_profile['S'] -= added_s
|
| 796 |
-
self._apply_fertilizer("Сульфат магния", grams, {'внесет S': round(added_s, 1)})
|
| 797 |
-
self.final_profile['Mg'] = 0
|
| 798 |
-
|
| 799 |
-
def _apply_calcium_nitrate(self):
|
| 800 |
-
ca_need = self.final_profile['Ca']
|
| 801 |
-
if ca_need <= 0:
|
| 802 |
-
return
|
| 803 |
-
|
| 804 |
-
ca_content = self.fertilizers_db["Кальциевая селитра"]["Ca"]
|
| 805 |
-
grams = (ca_need * self.volume) / (ca_content * 1000)
|
| 806 |
-
added_n = grams * self.fertilizers_db["Кальциевая селитра"]["N (NO3-)"] * 1000 / self.volume
|
| 807 |
-
|
| 808 |
-
self._apply_fertilizer("Кальциевая селитра", grams, {'внесет NO3': round(added_n, 1)})
|
| 809 |
-
self.final_profile['Ca'] = 0
|
| 810 |
-
|
| 811 |
-
def _apply_potassium_phosphate(self):
|
| 812 |
-
p_need = self.final_profile['P']
|
| 813 |
-
if p_need <= 0:
|
| 814 |
-
return
|
| 815 |
-
|
| 816 |
-
p_content = self.fertilizers_db["Калий фосфорнокислый"]["P"]
|
| 817 |
-
grams = (p_need * self.volume) / (p_content * 1000)
|
| 818 |
-
added_k = grams * self.fertilizers_db["Калий фосфорнокислый"]["K"] * 1000 / self.volume
|
| 819 |
-
|
| 820 |
-
self.final_profile['K'] -= added_k
|
| 821 |
-
self._apply_fertilizer("Калий фосфорнокислый", grams, {'внесет K': round(added_k, 1)})
|
| 822 |
-
self.final_profile['P'] = 0
|
| 823 |
-
|
| 824 |
-
def _apply_ammonium_nitrate(self):
|
| 825 |
-
nh4_need = self.target_nitrogen['NH4']
|
| 826 |
-
if nh4_need <= 0:
|
| 827 |
-
return
|
| 828 |
-
|
| 829 |
-
nh4_content = self.fertilizers_db["Аммоний азотнокислый"]["N (NH4+)"]
|
| 830 |
-
grams = (nh4_need * self.volume) / (nh4_content * 1000)
|
| 831 |
-
added_n = grams * self.fertilizers_db["Аммоний азотнокислый"]["N (NO3-)"] * 1000 / self.volume
|
| 832 |
-
|
| 833 |
-
self._apply_fertilizer("Аммоний азотнокислый", grams, {
|
| 834 |
-
'внесет NO3': round(added_n, 1),
|
| 835 |
-
'внесет NH4': round(nh4_need, 1)
|
| 836 |
-
})
|
| 837 |
|
| 838 |
def _apply_potassium_sulfate(self):
|
| 839 |
-
k_need = self.
|
| 840 |
-
s_need = self.
|
| 841 |
|
| 842 |
if k_need <= 0 or s_need <= 0:
|
| 843 |
return
|
| 844 |
|
| 845 |
-
k_content = self.
|
| 846 |
-
s_content = self.
|
| 847 |
|
|
|
|
| 848 |
grams = min(
|
| 849 |
(k_need * self.volume) / (k_content * 1000),
|
| 850 |
(s_need * self.volume) / (s_content * 1000)
|
|
@@ -853,63 +809,62 @@ class NutrientCalculator:
|
|
| 853 |
added_k = grams * k_content * 1000 / self.volume
|
| 854 |
added_s = grams * s_content * 1000 / self.volume
|
| 855 |
|
| 856 |
-
self.
|
| 857 |
-
self.
|
| 858 |
-
self.
|
| 859 |
-
'
|
| 860 |
-
'
|
| 861 |
-
|
|
|
|
|
|
|
| 862 |
|
| 863 |
def _apply_potassium_nitrate(self):
|
| 864 |
-
k_need = self.
|
| 865 |
if k_need <= 0:
|
| 866 |
return
|
| 867 |
|
| 868 |
-
k_content = self.
|
| 869 |
grams = (k_need * self.volume) / (k_content * 1000)
|
| 870 |
-
added_n = grams * self.
|
| 871 |
-
|
| 872 |
-
self.final_profile['K'] = 0
|
| 873 |
-
self._apply_fertilizer("Калий азотнокислый", grams, {'внесет NO3': round(added_n, 2)})
|
| 874 |
|
| 875 |
-
|
| 876 |
-
|
| 877 |
-
|
| 878 |
-
|
| 879 |
-
|
| 880 |
-
|
| 881 |
-
p_content = self.fertilizers_db["Монофосфат калия"]["P"]
|
| 882 |
-
grams = (p_need * self.volume) / (p_content * 1000)
|
| 883 |
-
added_k = grams * self.fertilizers_db["Монофосфат калия"]["K"] * 1000 / self.volume
|
| 884 |
|
| 885 |
-
|
| 886 |
-
|
| 887 |
-
|
| 888 |
-
|
| 889 |
-
|
| 890 |
-
self.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 891 |
|
| 892 |
def calculate_ec(self):
|
| 893 |
return round(self.total_ppm / 700, 2)
|
| 894 |
|
| 895 |
def print_report(self):
|
| 896 |
print("\n" + "="*60)
|
| 897 |
-
print("ПРОФИЛЬ ПИТАТЕЛЬНОГО
|
| 898 |
print("="*60)
|
| 899 |
-
table = [[el, round(val, 1)] for el, val in self.
|
| 900 |
print(tabulate(table, headers=["Элемент", "ppm"]))
|
| 901 |
|
| 902 |
-
print("\nЦелевые значения азота:")
|
| 903 |
-
print(f" N (NO3-): {round(self.target_nitrogen['NO3'], 1)} ppm")
|
| 904 |
-
print(f" N (NH4+): {round(self.target_nitrogen['NH4'], 1)} ppm")
|
| 905 |
-
|
| 906 |
print("\n" + "="*60)
|
| 907 |
print(f"РАСЧЕТ ДЛЯ {self.volume} ЛИТРОВ РАСТВОРА")
|
| 908 |
print("="*60)
|
| 909 |
print(f"Общая концентрация: {round(self.total_ppm, 1)} ppm")
|
| 910 |
print(f"EC: {self.calculate_ec()} mS/cm")
|
| 911 |
|
| 912 |
-
print("\nРЕКОМЕНДУЕМЫЕ
|
| 913 |
fert_table = []
|
| 914 |
for fert, data in self.results.items():
|
| 915 |
details = [f"+{k}: {v} ppm" for k, v in data.items() if k.startswith('внесет')]
|
|
@@ -922,10 +877,10 @@ class NutrientCalculator:
|
|
| 922 |
print(tabulate(fert_table, headers=["Удобрение", "Граммы", "Миллиграммы", "Добавит"]))
|
| 923 |
|
| 924 |
print("\nОСТАТОЧНЫЙ ДЕФИЦИТ:")
|
| 925 |
-
deficit = {k: v for k, v in self.
|
| 926 |
if deficit:
|
| 927 |
for el, val in deficit.items():
|
| 928 |
-
print(f" {el}: {
|
| 929 |
else:
|
| 930 |
print(" Все элементы покрыты полностью")
|
| 931 |
|
|
|
|
| 702 |
'N (NH4+)': 0
|
| 703 |
}
|
| 704 |
|
| 705 |
+
# База удобрений (6 удобрений)
|
| 706 |
+
FERTILIZERS = {
|
| 707 |
+
"Кальциевая селитра": {"N (NO3-)": 0.118, "Ca": 0.169},
|
| 708 |
+
"Калий азотнокислый": {"N (NO3-)": 0.138, "K": 0.387},
|
| 709 |
+
"Калий сернокислый": {"K": 0.448, "S": 0.184},
|
| 710 |
+
"Аммоний азотнокислый": {"N (NO3-)": 0.175, "N (NH4+)": 0.175},
|
| 711 |
+
"Сульфат магния": {"Mg": 0.098, "S": 0.13},
|
| 712 |
+
"Калий фосфорнокислый": {"P": 0.228, "K": 0.287}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 713 |
}
|
| 714 |
|
| 715 |
class NutrientCalculator:
|
| 716 |
def __init__(self, volume_liters=1.0):
|
| 717 |
self.volume = volume_liters
|
| 718 |
self.results = {}
|
| 719 |
+
self.profile = BASE_PROFILE.copy()
|
| 720 |
self.total_ppm = sum(BASE_PROFILE.values()) + TOTAL_NITROGEN
|
| 721 |
+
self.fertilizers = FERTILIZERS
|
| 722 |
+
|
| 723 |
+
# Целевые значения азота
|
| 724 |
+
self.target_no3 = TOTAL_NITROGEN * (NO3_RATIO / (NO3_RATIO + NH4_RATIO))
|
| 725 |
+
self.target_nh4 = TOTAL_NITROGEN * (NH4_RATIO / (NO3_RATIO + NH4_RATIO))
|
| 726 |
|
| 727 |
def calculate(self):
|
| 728 |
+
# 1. Вносим сульфат магния (покрываем Mg)
|
| 729 |
+
self._apply_fertilizer(
|
| 730 |
+
"Сульфат магния",
|
| 731 |
+
self.profile['Mg'],
|
| 732 |
+
"Mg",
|
| 733 |
+
{"S": "внесет S"}
|
| 734 |
+
)
|
| 735 |
+
|
| 736 |
+
# 2. Вносим кальциевую селитру (покрываем Ca)
|
| 737 |
+
self._apply_fertilizer(
|
| 738 |
+
"Кальциевая селитра",
|
| 739 |
+
self.profile['Ca'],
|
| 740 |
+
"Ca",
|
| 741 |
+
{"N (NO3-)": "внесет NO3"}
|
| 742 |
+
)
|
| 743 |
+
|
| 744 |
+
# 3. Вносим калий фосфорнокислый (покрываем P)
|
| 745 |
+
self._apply_fertilizer(
|
| 746 |
+
"Калий фосфорнокислый",
|
| 747 |
+
self.profile['P'],
|
| 748 |
+
"P",
|
| 749 |
+
{"K": "внесет K"}
|
| 750 |
+
)
|
| 751 |
+
|
| 752 |
+
# 4. Вносим аммоний азотнокислый (покрываем NH4)
|
| 753 |
+
nh4_needed = self.target_nh4
|
| 754 |
+
if nh4_needed > 0:
|
| 755 |
+
self._apply_fertilizer(
|
| 756 |
+
"Аммоний азотнокислый",
|
| 757 |
+
nh4_needed,
|
| 758 |
+
"N (NH4+)",
|
| 759 |
+
{"N (NO3-)": "внесет NO3"}
|
| 760 |
+
)
|
| 761 |
+
|
| 762 |
+
# 5. Вносим калий сернокислый (покрываем K и S)
|
| 763 |
self._apply_potassium_sulfate()
|
|
|
|
|
|
|
| 764 |
|
| 765 |
+
# 6. Вносим калий азотнокислый (добираем K)
|
| 766 |
+
self._apply_potassium_nitrate()
|
| 767 |
|
| 768 |
+
# Пересчитываем фактическое содержание азота
|
| 769 |
+
self._recalculate_nitrogen()
|
| 770 |
|
| 771 |
return self.results
|
| 772 |
|
| 773 |
+
def _apply_fertilizer(self, name, need, main_element, additions):
|
| 774 |
+
if need <= 0:
|
| 775 |
+
return
|
| 776 |
+
|
| 777 |
+
content = self.fertilizers[name][main_element]
|
| 778 |
+
grams = (need * self.volume) / (content * 1000)
|
| 779 |
+
|
| 780 |
+
added = {}
|
| 781 |
+
for element, label in additions.items():
|
| 782 |
+
added_amount = grams * self.fertilizers[name][element] * 1000 / self.volume
|
| 783 |
+
added[label] = round(added_amount, 1)
|
| 784 |
+
self.profile[element] -= added_amount
|
| 785 |
+
|
| 786 |
+
self.profile[main_element] = 0
|
| 787 |
+
self.results[name] = {
|
| 788 |
'граммы': round(grams, 3),
|
| 789 |
'миллиграммы': int(grams * 1000),
|
| 790 |
+
**added
|
| 791 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 792 |
|
| 793 |
def _apply_potassium_sulfate(self):
|
| 794 |
+
k_need = self.profile['K']
|
| 795 |
+
s_need = self.profile['S']
|
| 796 |
|
| 797 |
if k_need <= 0 or s_need <= 0:
|
| 798 |
return
|
| 799 |
|
| 800 |
+
k_content = self.fertilizers["Калий сернокислый"]["K"]
|
| 801 |
+
s_content = self.fertilizers["Калий сернокислый"]["S"]
|
| 802 |
|
| 803 |
+
# Рассчитываем максимально возможное внесение
|
| 804 |
grams = min(
|
| 805 |
(k_need * self.volume) / (k_content * 1000),
|
| 806 |
(s_need * self.volume) / (s_content * 1000)
|
|
|
|
| 809 |
added_k = grams * k_content * 1000 / self.volume
|
| 810 |
added_s = grams * s_content * 1000 / self.volume
|
| 811 |
|
| 812 |
+
self.profile['K'] -= added_k
|
| 813 |
+
self.profile['S'] -= added_s
|
| 814 |
+
self.results["Калий сернокислый"] = {
|
| 815 |
+
'граммы': round(grams, 3),
|
| 816 |
+
'миллиграммы': int(grams * 1000),
|
| 817 |
+
'внесет K': round(added_k, 1),
|
| 818 |
+
'внесет S': round(added_s, 1)
|
| 819 |
+
}
|
| 820 |
|
| 821 |
def _apply_potassium_nitrate(self):
|
| 822 |
+
k_need = self.profile['K']
|
| 823 |
if k_need <= 0:
|
| 824 |
return
|
| 825 |
|
| 826 |
+
k_content = self.fertilizers["Калий азотнокислый"]["K"]
|
| 827 |
grams = (k_need * self.volume) / (k_content * 1000)
|
| 828 |
+
added_n = grams * self.fertilizers["Калий азотнокислый"]["N (NO3-)"] * 1000 / self.volume
|
|
|
|
|
|
|
|
|
|
| 829 |
|
| 830 |
+
self.profile['K'] = 0
|
| 831 |
+
self.results["Калий азотнокислый"] = {
|
| 832 |
+
'граммы': round(grams, 3),
|
| 833 |
+
'миллиграммы': int(grams * 1000),
|
| 834 |
+
'внесет NO3': round(added_n, 1)
|
| 835 |
+
}
|
|
|
|
|
|
|
|
|
|
| 836 |
|
| 837 |
+
def _recalculate_nitrogen(self):
|
| 838 |
+
# Считаем фактически внесенный азот
|
| 839 |
+
no3 = 0
|
| 840 |
+
nh4 = 0
|
| 841 |
+
|
| 842 |
+
for fert in self.results.values():
|
| 843 |
+
if 'внесет NO3' in fert:
|
| 844 |
+
no3 += fert['внесет NO3']
|
| 845 |
+
if 'внесет NH4' in fert:
|
| 846 |
+
nh4 += fert['внесет NH4']
|
| 847 |
+
|
| 848 |
+
self.profile['N (NO3-)'] = no3
|
| 849 |
+
self.profile['N (NH4+)'] = nh4
|
| 850 |
|
| 851 |
def calculate_ec(self):
|
| 852 |
return round(self.total_ppm / 700, 2)
|
| 853 |
|
| 854 |
def print_report(self):
|
| 855 |
print("\n" + "="*60)
|
| 856 |
+
print("ПРОФИЛЬ ПИТАТЕЛЬНОГО РАСТВОРА:")
|
| 857 |
print("="*60)
|
| 858 |
+
table = [[el, round(val, 1)] for el, val in self.profile.items()]
|
| 859 |
print(tabulate(table, headers=["Элемент", "ppm"]))
|
| 860 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 861 |
print("\n" + "="*60)
|
| 862 |
print(f"РАСЧЕТ ДЛЯ {self.volume} ЛИТРОВ РАСТВОРА")
|
| 863 |
print("="*60)
|
| 864 |
print(f"Общая концентрация: {round(self.total_ppm, 1)} ppm")
|
| 865 |
print(f"EC: {self.calculate_ec()} mS/cm")
|
| 866 |
|
| 867 |
+
print("\nРЕКОМЕНДУЕМЫЕ УДОБРЕНИЯ (6 штук):")
|
| 868 |
fert_table = []
|
| 869 |
for fert, data in self.results.items():
|
| 870 |
details = [f"+{k}: {v} ppm" for k, v in data.items() if k.startswith('внесет')]
|
|
|
|
| 877 |
print(tabulate(fert_table, headers=["Удобрение", "Граммы", "Миллиграммы", "Добавит"]))
|
| 878 |
|
| 879 |
print("\nОСТАТОЧНЫЙ ДЕФИЦИТ:")
|
| 880 |
+
deficit = {k: round(v, 1) for k, v in self.profile.items() if v > 0.1}
|
| 881 |
if deficit:
|
| 882 |
for el, val in deficit.items():
|
| 883 |
+
print(f" {el}: {val} ppm")
|
| 884 |
else:
|
| 885 |
print(" Все элементы покрыты полностью")
|
| 886 |
|