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 |
|