Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -767,86 +767,70 @@ class NutrientCalculator:
|
|
| 767 |
|
| 768 |
def calculate(self):
|
| 769 |
try:
|
| 770 |
-
|
| 771 |
-
|
|
|
|
|
|
|
|
|
|
| 772 |
|
| 773 |
-
|
| 774 |
-
|
| 775 |
|
| 776 |
-
|
| 777 |
-
|
| 778 |
|
| 779 |
-
|
| 780 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 781 |
|
| 782 |
-
return self.results
|
| 783 |
except Exception as e:
|
| 784 |
print(f"Ошибка при расчёте: {str(e)}")
|
| 785 |
raise
|
| 786 |
|
| 787 |
-
def
|
| 788 |
-
"""
|
| 789 |
-
for
|
| 790 |
-
|
| 791 |
-
|
| 792 |
-
|
| 793 |
-
|
| 794 |
-
|
| 795 |
-
|
| 796 |
-
|
| 797 |
-
|
| 798 |
-
"""Компенсация азота (NO3-, NH4+)"""
|
| 799 |
-
for nitrogen_type in ["N (NO3-)", "N (NH4+)"]:
|
| 800 |
-
required_ppm = self.target_profile[nitrogen_type] - self.actual_profile[nitrogen_type]
|
| 801 |
-
if required_ppm > 0.1:
|
| 802 |
-
fert_name = self.compensation_weights[nitrogen_type]["fert"]
|
| 803 |
-
self._apply_with_limit(fert_name, nitrogen_type, required_ppm)
|
| 804 |
-
|
| 805 |
-
def _compensate_secondary_elements(self):
|
| 806 |
-
"""Компенсация второстепенных элементов (K, S)"""
|
| 807 |
-
for element, weight_data in self.compensation_weights.items():
|
| 808 |
-
if element in ["K", "S"]:
|
| 809 |
-
fert_name = weight_data["fert"]
|
| 810 |
-
main_element = weight_data["main_element"]
|
| 811 |
-
required_ppm = self.target_profile[main_element] - self.actual_profile[main_element]
|
| 812 |
if required_ppm > 0.1:
|
| 813 |
-
self.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 814 |
|
| 815 |
-
|
| 816 |
-
|
| 817 |
-
if required_ppm <= 0:
|
| 818 |
-
return
|
| 819 |
|
| 820 |
-
|
| 821 |
-
|
| 822 |
-
|
| 823 |
-
|
| 824 |
-
|
| 825 |
-
|
| 826 |
-
|
| 827 |
-
|
| 828 |
-
|
| 829 |
-
'вклад в EC': 0.0
|
| 830 |
-
}
|
| 831 |
-
for element in self.fertilizers[fert_name]:
|
| 832 |
-
result[f'внесет {self._label(element)}'] = 0.0
|
| 833 |
-
self.results[fert_name] = result
|
| 834 |
-
|
| 835 |
-
self.results[fert_name]['граммы'] += grams
|
| 836 |
-
self.results[fert_name]['миллиграммы'] += int(grams * 1000)
|
| 837 |
-
|
| 838 |
-
fert_ec = 0.0
|
| 839 |
-
for element, percent in self.fertilizers[fert_name].items():
|
| 840 |
-
added_ppm = (grams * percent * 1000) / self.volume
|
| 841 |
-
self.results[fert_name][f'внесет {self._label(element)}'] += added_ppm
|
| 842 |
-
self.actual_profile[element] += added_ppm
|
| 843 |
-
fert_ec += added_ppm * EC_COEFFICIENTS.get(element, 0.0015)
|
| 844 |
-
|
| 845 |
-
self.results[fert_name]['вклад в EC'] += fert_ec
|
| 846 |
-
self.total_ec += fert_ec
|
| 847 |
-
except KeyError as e:
|
| 848 |
-
print(f"Ошибка: отсутствует элемент {str(e)} в удобрении {fert_name}")
|
| 849 |
-
raise
|
| 850 |
|
| 851 |
def _adjust_overages(self):
|
| 852 |
"""Корректировка перебора элементов"""
|
|
@@ -854,45 +838,41 @@ class NutrientCalculator:
|
|
| 854 |
if self.actual_profile[element] > self.target_profile[element]:
|
| 855 |
overage = self.actual_profile[element] - self.target_profile[element]
|
| 856 |
print(f"Корректировка перебора: {element} уменьшен на {overage:.2f} ppm")
|
| 857 |
-
|
| 858 |
# Уменьшаем фактическое значение
|
| 859 |
self.actual_profile[element] -= overage
|
| 860 |
-
|
| 861 |
# Обновляем результаты удобрений
|
| 862 |
for fert_name, fert_data in self.results.items():
|
| 863 |
if f'внесет {self._label(element)}' in fert_data:
|
| 864 |
-
fert_data[f'внесет {self._label(element)}']
|
| 865 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 866 |
# Пересчитываем граммы удобрения
|
| 867 |
if element in self.fertilizers[fert_name]:
|
| 868 |
content = self.fertilizers[fert_name][element]
|
| 869 |
-
grams_to_remove = (
|
| 870 |
fert_data['граммы'] -= grams_to_remove
|
| 871 |
fert_data['миллиграммы'] -= int(grams_to_remove * 1000)
|
| 872 |
|
| 873 |
-
|
| 874 |
-
|
| 875 |
-
|
| 876 |
-
|
| 877 |
-
|
| 878 |
-
|
| 879 |
-
|
| 880 |
-
|
| 881 |
-
|
| 882 |
-
|
| 883 |
-
|
| 884 |
-
|
| 885 |
-
|
| 886 |
-
return round(self.total_ec, 2)
|
| 887 |
-
|
| 888 |
-
def print_initial_nitrogen_report(self):
|
| 889 |
-
try:
|
| 890 |
-
print("Исходный расчёт азота:")
|
| 891 |
-
print(f" NO3-: {self.initial_n_profile['NO3-']} ppm")
|
| 892 |
-
print(f" NH4+: {self.initial_n_profile['NH4+']} ppm")
|
| 893 |
-
except Exception as e:
|
| 894 |
-
print(f"Ошибка при выводе отчёта: {str(e)}")
|
| 895 |
-
raise
|
| 896 |
|
| 897 |
def calculate_ec(self):
|
| 898 |
return round(self.total_ec, 2)
|
|
|
|
| 767 |
|
| 768 |
def calculate(self):
|
| 769 |
try:
|
| 770 |
+
max_iterations = 100 # Максимальное количество итераций
|
| 771 |
+
iteration = 0
|
| 772 |
+
while iteration < max_iterations:
|
| 773 |
+
iteration += 1
|
| 774 |
+
print(f"Итерация {iteration} из {max_iterations}")
|
| 775 |
|
| 776 |
+
# Сброс фактического профиля
|
| 777 |
+
self._reset_actual_profile()
|
| 778 |
|
| 779 |
+
# Применение удобрений
|
| 780 |
+
self._apply_fertilizers()
|
| 781 |
|
| 782 |
+
# Проверка результатов
|
| 783 |
+
if self.validate_results():
|
| 784 |
+
print("Успешная комбинация найдена!")
|
| 785 |
+
return self.results
|
| 786 |
+
|
| 787 |
+
# Корректировка перебора
|
| 788 |
+
self._adjust_overages()
|
| 789 |
+
|
| 790 |
+
raise ValueError("Не удалось найти подходящую комбинацию удобрений после максимального количества итераций.")
|
| 791 |
|
|
|
|
| 792 |
except Exception as e:
|
| 793 |
print(f"Ошибка при расчёте: {str(e)}")
|
| 794 |
raise
|
| 795 |
|
| 796 |
+
def _reset_actual_profile(self):
|
| 797 |
+
"""Сброс фактического профиля перед новой итерацией"""
|
| 798 |
+
self.actual_profile = {k: 0.0 for k in BASE_PROFILE}
|
| 799 |
+
self.total_ec = 0.0
|
| 800 |
+
self.results = {}
|
| 801 |
+
|
| 802 |
+
def _apply_fertilizers(self):
|
| 803 |
+
"""Применение удобрений"""
|
| 804 |
+
for fert_name, fert_data in self.fertilizers.items():
|
| 805 |
+
for element, content in fert_data.items():
|
| 806 |
+
required_ppm = self.target_profile[element] - self.actual_profile[element]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 807 |
if required_ppm > 0.1:
|
| 808 |
+
grams = min((required_ppm * self.volume) / (content * 1000), 100) # Ограничение на граммы
|
| 809 |
+
self._apply_with_limit(fert_name, element, grams, content)
|
| 810 |
+
|
| 811 |
+
def _apply_with_limit(self, fert_name, element, grams, content):
|
| 812 |
+
"""Применение удобрения с ограничением"""
|
| 813 |
+
if fert_name not in self.results:
|
| 814 |
+
self.results[fert_name] = {
|
| 815 |
+
'граммы': 0.0,
|
| 816 |
+
'миллиграммы': 0,
|
| 817 |
+
'вклад в EC': 0.0
|
| 818 |
+
}
|
| 819 |
+
for elem in self.fertilizers[fert_name]:
|
| 820 |
+
self.results[fert_name][f'внесет {self._label(elem)}'] = 0.0
|
| 821 |
|
| 822 |
+
self.results[fert_name]['граммы'] += grams
|
| 823 |
+
self.results[fert_name]['миллиграммы'] += int(grams * 1000)
|
|
|
|
|
|
|
| 824 |
|
| 825 |
+
fert_ec = 0.0
|
| 826 |
+
for elem, percent in self.fertilizers[fert_name].items():
|
| 827 |
+
added_ppm = (grams * percent * 1000) / self.volume
|
| 828 |
+
self.results[fert_name][f'внесет {self._label(elem)}'] += added_ppm
|
| 829 |
+
self.actual_profile[elem] += added_ppm
|
| 830 |
+
fert_ec += added_ppm * EC_COEFFICIENTS.get(elem, 0.0015)
|
| 831 |
+
|
| 832 |
+
self.results[fert_name]['вклад в EC'] += fert_ec
|
| 833 |
+
self.total_ec += fert_ec
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 834 |
|
| 835 |
def _adjust_overages(self):
|
| 836 |
"""Корректировка перебора элементов"""
|
|
|
|
| 838 |
if self.actual_profile[element] > self.target_profile[element]:
|
| 839 |
overage = self.actual_profile[element] - self.target_profile[element]
|
| 840 |
print(f"Корректировка перебора: {element} уменьшен на {overage:.2f} ppm")
|
| 841 |
+
|
| 842 |
# Уменьшаем фактическое значение
|
| 843 |
self.actual_profile[element] -= overage
|
| 844 |
+
|
| 845 |
# Обновляем результаты удобрений
|
| 846 |
for fert_name, fert_data in self.results.items():
|
| 847 |
if f'внесет {self._label(element)}' in fert_data:
|
| 848 |
+
current_value = fert_data[f'внесет {self._label(element)}']
|
| 849 |
+
if current_value > overage:
|
| 850 |
+
fert_data[f'внесет {self._label(element)}'] -= overage
|
| 851 |
+
overage = 0
|
| 852 |
+
else:
|
| 853 |
+
overage -= current_value
|
| 854 |
+
fert_data[f'внесет {self._label(element)}'] = 0
|
| 855 |
+
|
| 856 |
# Пересчитываем граммы удобрения
|
| 857 |
if element in self.fertilizers[fert_name]:
|
| 858 |
content = self.fertilizers[fert_name][element]
|
| 859 |
+
grams_to_remove = (current_value * self.volume) / (content * 1000)
|
| 860 |
fert_data['граммы'] -= grams_to_remove
|
| 861 |
fert_data['миллиграммы'] -= int(grams_to_remove * 1000)
|
| 862 |
|
| 863 |
+
# Убеждаемся, что граммы не отрицательны
|
| 864 |
+
if fert_data['граммы'] < 0:
|
| 865 |
+
fert_data['граммы'] = 0
|
| 866 |
+
fert_data['миллиграммы'] = 0
|
| 867 |
+
|
| 868 |
+
def validate_results(self):
|
| 869 |
+
"""Проверка соответствия целевым значениям"""
|
| 870 |
+
for element, target_value in self.target_profile.items():
|
| 871 |
+
actual_value = self.actual_profile[element]
|
| 872 |
+
if abs(actual_value - target_value) > 0.1: # Допустимая погрешность
|
| 873 |
+
print(f"Несоответствие: {element} (цель: {target_value:.2f}, фактически: {actual_value:.2f})")
|
| 874 |
+
return False
|
| 875 |
+
return True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 876 |
|
| 877 |
def calculate_ec(self):
|
| 878 |
return round(self.total_ec, 2)
|