Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -693,237 +693,177 @@ def nutri_call():
|
|
693 |
|
694 |
|
695 |
|
696 |
-
|
697 |
from tabulate import tabulate
|
|
|
698 |
|
699 |
-
#
|
700 |
-
TOTAL_NITROGEN =
|
701 |
-
NO3_RATIO = 8.
|
702 |
-
NH4_RATIO = 1.
|
703 |
VOLUME_LITERS = 100
|
704 |
|
705 |
-
#
|
706 |
-
EC_COEFFICIENTS = {
|
707 |
-
'P': 0.0012, 'K': 0.0018, 'Mg': 0.0015,
|
708 |
-
'Ca': 0.0016, 'S': 0.0014,
|
709 |
-
'N (NO3-)': 0.0017, 'N (NH4+)': 0.0019
|
710 |
-
}
|
711 |
-
|
712 |
-
# Базовый профиль питательного раствора
|
713 |
BASE_PROFILE = {
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
}
|
718 |
|
719 |
-
#
|
720 |
-
|
721 |
"Кальциевая селитра": {"N (NO3-)": 0.11863, "Ca": 0.16972},
|
722 |
"Калий азотнокислый": {"N (NO3-)": 0.136, "K": 0.382},
|
|
|
723 |
"Аммоний азотнокислый": {"N (NO3-)": 0.17499, "N (NH4+)": 0.17499},
|
724 |
"Сульфат магния": {"Mg": 0.09861, "S": 0.13010},
|
725 |
"Монофосфат калия": {"P": 0.218, "K": 0.275},
|
726 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
727 |
}
|
728 |
|
729 |
class NutrientCalculator:
|
730 |
-
def __init__(self,
|
731 |
-
|
732 |
-
self.
|
|
|
733 |
self.results = {}
|
734 |
-
self.
|
735 |
-
self.actual_profile = {k: 0.0 for k in BASE_PROFILE}
|
736 |
-
self.fertilizers = NUTRIENT_CONTENT_IN_FERTILIZERS
|
737 |
self.total_ec = 0.0
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
|
744 |
-
}
|
745 |
-
|
746 |
-
# Коэффициенты распределения для кальциевой селитры
|
747 |
-
self.calcium_nitrate_ratios = {
|
748 |
-
"Ca": 0.7, # 70% дефицита кальция покрываем кальциевой селитрой
|
749 |
-
"NO3": 0.2 # 30% дефицита NO3 покрываем кальциевой селитрой
|
750 |
-
}
|
751 |
-
|
752 |
-
# Расчёт соотношений азотов
|
753 |
-
total_parts = NO3_RATIO + NH4_RATIO
|
754 |
-
self.target_profile['N (NO3-)'] = TOTAL_NITROGEN * (NO3_RATIO / total_parts)
|
755 |
-
self.target_profile['N (NH4+)'] = TOTAL_NITROGEN * (NH4_RATIO / total_parts)
|
756 |
-
|
757 |
-
def _label(self, element):
|
758 |
-
"""Форматирование названий элементов для вывода"""
|
759 |
-
labels = {
|
760 |
-
'N (NO3-)': 'NO3',
|
761 |
-
'N (NH4+)': 'NH4'
|
762 |
-
}
|
763 |
-
return labels.get(element, element)
|
764 |
-
|
765 |
def calculate(self):
|
766 |
-
|
767 |
-
|
768 |
-
|
769 |
-
self.
|
770 |
-
|
771 |
-
|
772 |
-
|
773 |
-
|
774 |
-
|
775 |
-
|
776 |
-
|
777 |
-
|
778 |
-
|
779 |
-
self.
|
780 |
-
|
781 |
-
|
782 |
-
|
783 |
-
|
784 |
-
|
785 |
-
|
786 |
-
|
787 |
-
|
788 |
-
|
789 |
-
|
790 |
-
|
791 |
-
|
792 |
-
|
793 |
-
|
794 |
-
|
795 |
-
|
796 |
-
|
797 |
-
|
798 |
-
|
799 |
-
|
800 |
-
|
801 |
-
|
802 |
-
|
803 |
-
|
804 |
-
|
805 |
-
|
806 |
-
|
807 |
-
|
808 |
-
self.
|
809 |
-
|
810 |
-
|
811 |
-
|
812 |
-
|
813 |
-
|
814 |
-
|
815 |
-
|
816 |
-
|
817 |
-
|
818 |
-
|
819 |
-
|
820 |
-
|
821 |
-
|
822 |
-
|
823 |
-
|
824 |
-
|
825 |
-
|
826 |
-
|
827 |
-
|
828 |
-
|
829 |
-
|
830 |
-
|
831 |
-
|
832 |
-
|
833 |
-
self.
|
834 |
-
|
835 |
-
|
836 |
-
|
837 |
-
|
838 |
-
|
839 |
-
|
840 |
-
|
841 |
-
|
842 |
-
|
843 |
-
|
844 |
-
|
845 |
-
|
846 |
-
|
847 |
-
|
848 |
-
|
849 |
-
|
850 |
-
for element in self.fertilizers[fert_name]:
|
851 |
-
result[f'внесет {self._label(element)}'] = 0.0
|
852 |
-
self.results[fert_name] = result
|
853 |
-
|
854 |
-
self.results[fert_name]['граммы'] += grams
|
855 |
-
self.results[fert_name]['миллиграммы'] += int(grams * 1000)
|
856 |
-
|
857 |
-
fert_ec = 0.0
|
858 |
-
for element, percent in self.fertilizers[fert_name].items():
|
859 |
-
added_ppm = (grams * percent * 1000) / self.volume
|
860 |
-
self.results[fert_name][f'внесет {self._label(element)}'] += added_ppm
|
861 |
-
self.actual_profile[element] += added_ppm
|
862 |
-
fert_ec += added_ppm * EC_COEFFICIENTS.get(element, 0.0015)
|
863 |
-
|
864 |
-
self.results[fert_name]['вклад в EC'] += fert_ec
|
865 |
-
self.total_ec += fert_ec
|
866 |
-
except KeyError as e:
|
867 |
-
print(f"Ошибка: отсутствует элемент {str(e)} в удобрении {fert_name}")
|
868 |
-
raise
|
869 |
-
|
870 |
-
def calculate_ec(self):
|
871 |
-
"""Расчет общей электропроводности (EC)"""
|
872 |
-
return round(self.total_ec, 2)
|
873 |
-
|
874 |
def print_report(self):
|
875 |
-
""
|
876 |
-
|
877 |
-
|
878 |
-
|
879 |
-
|
880 |
-
|
881 |
-
|
882 |
-
|
883 |
-
|
884 |
-
|
885 |
-
|
886 |
-
|
887 |
-
|
888 |
-
|
889 |
-
|
890 |
-
fert_table
|
891 |
-
|
892 |
-
|
893 |
-
|
894 |
-
|
895 |
-
|
896 |
-
|
897 |
-
|
898 |
-
|
899 |
-
|
900 |
-
|
901 |
-
headers=["Удобрение", "Граммы", "Миллиграммы", "EC (мСм/см)", "Добавит"]))
|
902 |
-
|
903 |
print("\nОСТАТОЧНЫЙ ДЕФИЦИТ:")
|
904 |
-
|
905 |
-
|
906 |
-
|
907 |
-
|
908 |
-
}
|
909 |
-
if deficit:
|
910 |
-
for el, val in deficit.items():
|
911 |
-
print(f" {el}: {val} ppm")
|
912 |
-
else:
|
913 |
-
print(" Все элементы покрыты полностью")
|
914 |
-
except Exception as e:
|
915 |
-
print(f"Ошибка при выводе отчёта: {str(e)}")
|
916 |
-
raise
|
917 |
-
|
918 |
|
|
|
919 |
if __name__ == "__main__":
|
920 |
-
|
921 |
-
|
922 |
-
|
923 |
-
calculator.print_report() # Правильный вызов метода класса
|
924 |
-
except Exception as e:
|
925 |
-
print(f"Критическая ошибка: {str(e)}")
|
926 |
-
|
927 |
|
928 |
|
929 |
|
|
|
693 |
|
694 |
|
695 |
|
|
|
696 |
from tabulate import tabulate
|
697 |
+
import numpy as np
|
698 |
|
699 |
+
# Глобальные параметры
|
700 |
+
TOTAL_NITROGEN = 120.0
|
701 |
+
NO3_RATIO = 8.0
|
702 |
+
NH4_RATIO = 1.0
|
703 |
VOLUME_LITERS = 100
|
704 |
|
705 |
+
# Базовый профиль
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
706 |
BASE_PROFILE = {
|
707 |
+
"P": 50, "K": 210, "Mg": 120,
|
708 |
+
"Ca": 150, "S": 50,
|
709 |
+
"N (NO3-)": 0, "N (NH4+)": 0
|
710 |
}
|
711 |
|
712 |
+
# Состав удобрений (в долях)
|
713 |
+
NUTRIENT_CONTENT = {
|
714 |
"Кальциевая селитра": {"N (NO3-)": 0.11863, "Ca": 0.16972},
|
715 |
"Калий азотнокислый": {"N (NO3-)": 0.136, "K": 0.382},
|
716 |
+
"Калий сернокислый": {"K": 0.44874, "S": 0.18401},
|
717 |
"Аммоний азотнокислый": {"N (NO3-)": 0.17499, "N (NH4+)": 0.17499},
|
718 |
"Сульфат магния": {"Mg": 0.09861, "S": 0.13010},
|
719 |
"Монофосфат калия": {"P": 0.218, "K": 0.275},
|
720 |
+
"Сульфат кальция": {"Ca": 0.23, "S": 0.186}
|
721 |
+
}
|
722 |
+
|
723 |
+
# Коэффициенты EC
|
724 |
+
EC_COEFF = {
|
725 |
+
'P': 0.0012, 'K': 0.0018, 'Mg': 0.0015,
|
726 |
+
'Ca': 0.0016, 'S': 0.0014,
|
727 |
+
'N (NO3-)': 0.0017, 'N (NH4+)': 0.0019
|
728 |
}
|
729 |
|
730 |
class NutrientCalculator:
|
731 |
+
def __init__(self, volume=1.0):
|
732 |
+
self.volume = volume
|
733 |
+
self.target = BASE_PROFILE.copy()
|
734 |
+
self._init_nitrogen()
|
735 |
self.results = {}
|
736 |
+
self.actual = {k: 0.0 for k in self.target}
|
|
|
|
|
737 |
self.total_ec = 0.0
|
738 |
+
|
739 |
+
def _init_nitrogen(self):
|
740 |
+
total = NO3_RATIO + NH4_RATIO
|
741 |
+
self.target['N (NO3-)'] = TOTAL_NITROGEN * (NO3_RATIO / total)
|
742 |
+
self.target['N (NH4+)'] = TOTAL_NITROGEN * (NH4_RATIO / total)
|
743 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
744 |
def calculate(self):
|
745 |
+
# 1. Вносим кальций (приоритет Ca(NO3)2)
|
746 |
+
ca_needed = self.target['Ca'] - self.actual['Ca']
|
747 |
+
if ca_needed > 0:
|
748 |
+
self._apply_fert("Кальциевая селитра", "Ca", ca_needed)
|
749 |
+
|
750 |
+
# 2. Вносим NH4
|
751 |
+
nh4_needed = self.target['N (NH4+)'] - self.actual['N (NH4+)']
|
752 |
+
if nh4_needed > 0:
|
753 |
+
self._apply_fert("Аммоний азотнокислый", "N (NH4+)", nh4_needed)
|
754 |
+
|
755 |
+
# 3. Компенсируем NO3
|
756 |
+
no3_needed = self.target['N (NO3-)'] - self.actual['N (NO3-)']
|
757 |
+
if no3_needed > 0:
|
758 |
+
self._apply_fert("Калий азотнокислый", "N (NO3-)", no3_needed)
|
759 |
+
|
760 |
+
# 4. Вносим фосфор
|
761 |
+
p_needed = self.target['P'] - self.actual['P']
|
762 |
+
if p_needed > 0:
|
763 |
+
self._apply_fert("Монофосфат калия", "P", p_needed)
|
764 |
+
|
765 |
+
# 5. Компенсируем магний
|
766 |
+
mg_needed = self.target['Mg'] - self.actual['Mg']
|
767 |
+
if mg_needed > 0:
|
768 |
+
self._apply_fert("Сульфат магния", "Mg", mg_needed)
|
769 |
+
|
770 |
+
# 6. Корректируем калий и серу
|
771 |
+
self._balance_k_s()
|
772 |
+
|
773 |
+
return self._prepare_results()
|
774 |
+
|
775 |
+
def _apply_fert(self, name, element, needed_ppm):
|
776 |
+
content = NUTRIENT_CONTENT[name][element]
|
777 |
+
grams = (needed_ppm * self.volume) / (content * 1000)
|
778 |
+
|
779 |
+
if name not in self.results:
|
780 |
+
self.results[name] = {'граммы': 0, 'вклад': {}}
|
781 |
+
|
782 |
+
self.results[name]['граммы'] += grams
|
783 |
+
|
784 |
+
for el, val in NUTRIENT_CONTENT[name].items():
|
785 |
+
added = grams * val * 1000 / self.volume
|
786 |
+
self.actual[el] += added
|
787 |
+
self.total_ec += added * EC_COEFF.get(el, 0)
|
788 |
+
|
789 |
+
if el not in self.results[name]['вклад']:
|
790 |
+
self.results[name]['вклад'][el] = 0
|
791 |
+
self.results[name]['вклад'][el] += added
|
792 |
+
|
793 |
+
def _balance_k_s(self):
|
794 |
+
k_deficit = self.target['K'] - self.actual['K']
|
795 |
+
s_deficit = self.target['S'] - self.actual['S']
|
796 |
+
|
797 |
+
# Выбираем удобрение в зависимости от дефицита
|
798 |
+
if k_deficit > 0 and s_deficit > 0:
|
799 |
+
# Используем K2SO4 для одновременного восполнения
|
800 |
+
self._apply_fert("Калий сернокислый", "K", min(k_deficit, s_deficit*0.44874/0.18401))
|
801 |
+
elif k_deficit > 0:
|
802 |
+
self._apply_fert("Калий азотнокислый", "K", k_deficit)
|
803 |
+
|
804 |
+
def _prepare_results(self):
|
805 |
+
# Расчет дефицитов
|
806 |
+
deficits = {k: self.target[k] - self.actual[k]
|
807 |
+
for k in self.target if abs(self.target[k] - self.actual[k]) > 0.1}
|
808 |
+
|
809 |
+
return {
|
810 |
+
"actual_profile": self.actual,
|
811 |
+
"fertilizers": self._format_fertilizers(),
|
812 |
+
"total_ec": round(self.total_ec, 2),
|
813 |
+
"total_ppm": round(sum(self.actual.values()), 2),
|
814 |
+
"deficits": deficits
|
815 |
+
}
|
816 |
+
|
817 |
+
def _format_fertilizers(self):
|
818 |
+
formatted = {}
|
819 |
+
for name, data in self.results.items():
|
820 |
+
formatted[name] = {
|
821 |
+
'граммы': round(data['граммы'], 3),
|
822 |
+
'миллиграммы': int(data['граммы'] * 1000),
|
823 |
+
'вклад в EC': round(sum(v * EC_COEFF.get(k, 0)
|
824 |
+
for k, v in data['вклад'].items()), 3),
|
825 |
+
'добавит': [f"{k}: {round(v, 1)} ppm" for k, v in data['вклад'].items()]
|
826 |
+
}
|
827 |
+
return formatted
|
828 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
829 |
def print_report(self):
|
830 |
+
print("\n" + "="*60)
|
831 |
+
print("ПРОФИЛЬ ПИТАТЕЛЬНОГО РАСТВОРА (ИТОГО):")
|
832 |
+
print("="*60)
|
833 |
+
print(tabulate([[k, round(v, 1)] for k, v in self.actual.items()],
|
834 |
+
headers=["Элемент", "ppm"]))
|
835 |
+
|
836 |
+
print("\n" + "="*60)
|
837 |
+
print(f"РАСЧЕТ ДЛЯ {self.volume} ЛИТРОВ")
|
838 |
+
print("="*60)
|
839 |
+
print(f"Общая концентрация: {round(sum(self.actual.values()), 1)} ppm")
|
840 |
+
print(f"EC: {round(self.total_ec, 2)} mS/cm")
|
841 |
+
|
842 |
+
print("\nРЕКОМЕНДУЕМЫЕ УДОБРЕНИЯ:")
|
843 |
+
fert_table = []
|
844 |
+
for name, data in self._format_fertilizers().items():
|
845 |
+
fert_table.append([
|
846 |
+
name,
|
847 |
+
data['граммы'],
|
848 |
+
data['миллиграммы'],
|
849 |
+
data['вклад в EC'],
|
850 |
+
"\n".join(data['добавит'])
|
851 |
+
])
|
852 |
+
print(tabulate(fert_table,
|
853 |
+
headers=["Удобрение", "Граммы", "Миллиграммы", "EC", "Добавит"]))
|
854 |
+
|
855 |
+
if self._prepare_results()['deficits']:
|
|
|
|
|
856 |
print("\nОСТАТОЧНЫЙ ДЕФИЦИТ:")
|
857 |
+
for el, val in self._prepare_results()['deficits'].items():
|
858 |
+
print(f" {el}: {round(val, 1)} ppm")
|
859 |
+
else:
|
860 |
+
print("\nВсе элементы покрыты полностью")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
861 |
|
862 |
+
# Пример использования
|
863 |
if __name__ == "__main__":
|
864 |
+
calc = NutrientCalculator(VOLUME_LITERS)
|
865 |
+
results = calc.calculate()
|
866 |
+
calc.print_report()
|
|
|
|
|
|
|
|
|
867 |
|
868 |
|
869 |
|