DmitrMakeev commited on
Commit
04dfc3f
·
verified ·
1 Parent(s): d4c05da

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +103 -71
app.py CHANGED
@@ -726,15 +726,13 @@ EC_COEFFICIENTS = {
726
  'N (NO3-)': 0.0017, 'N (NH4+)': 0.0019
727
  }
728
 
729
- import itertools
730
-
731
  class NutrientCalculator:
732
- def __init__(self, volume_liters=1.0, profile=None):
733
  self.volume = volume_liters
734
  self.results = {}
735
- self.target_profile = profile.copy() if profile else BASE_PROFILE.copy()
736
  self.actual_profile = {k: 0.0 for k in self.target_profile}
737
- self.fertilizers = NUTRIENT_CONTENT_IN_FERTILIZERS
738
  self.total_ec = 0.0
739
 
740
  # Расчёт азота
@@ -748,8 +746,16 @@ class NutrientCalculator:
748
  "NH4+": self.target_profile['N (NH4+)']
749
  }
750
 
751
- # Список удобрений для перебора
752
- self.fertilizer_list = list(self.fertilizers.keys())
 
 
 
 
 
 
 
 
753
 
754
  def _label(self, element):
755
  """Форматирование названий элементов для вывода"""
@@ -761,80 +767,106 @@ class NutrientCalculator:
761
 
762
  def calculate(self):
763
  try:
764
- max_attempts = 100 # Максимальное количество попыток
765
- attempt = 0
766
- while attempt < max_attempts:
767
- attempt += 1
768
- print(f"Попытка {attempt} из {max_attempts}")
769
-
770
- # Генерация случайного порядка удобрений
771
- fertilizer_order = self._shuffle_fertilizers()
772
 
773
- # Сброс фактического профиля
774
- self._reset_actual_profile()
775
 
776
- # Пробуем рассчитать с текущим порядком удобрений
777
- if self._try_combination(fertilizer_order):
778
- print("Успешная комбинация найдена!")
779
- return self.results
780
 
781
- raise ValueError("Не удалось найти подходящую комбинацию удобрений после максимального количества попыток.")
 
782
 
 
783
  except Exception as e:
784
  print(f"Ошибка при расчёте: {str(e)}")
785
  raise
786
 
787
- def _shuffle_fertilizers(self):
788
- """Генерация случайного порядка удобрений"""
789
- return list(itertools.permutations(self.fertilizer_list))[hash(str(self.target_profile)) % len(self.fertilizer_list)]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
790
 
791
- def _reset_actual_profile(self):
792
- """Сброс фактического профиля перед новой попыткой"""
793
- self.actual_profile = {k: 0.0 for k in self.target_profile}
794
- self.total_ec = 0.0
795
- self.results = {}
796
 
797
- def _try_combination(self, fertilizer_order):
798
- """Попытка расчета с заданным порядком удобрений"""
799
- for fert_name in fertilizer_order:
800
- for element, content in self.fertilizers[fert_name].items():
801
- required_ppm = self.target_profile[element] - self.actual_profile[element]
802
- if required_ppm > 0.1:
803
- grams = (required_ppm * self.volume) / (content * 1000)
804
-
805
- if fert_name not in self.results:
806
- self.results[fert_name] = {
807
- 'граммы': 0.0,
808
- 'миллиграммы': 0,
809
- 'вклад в EC': 0.0
810
- }
811
- for elem in self.fertilizers[fert_name]:
812
- self.results[fert_name][f'внесет {self._label(elem)}'] = 0.0
813
-
814
- self.results[fert_name]['граммы'] += grams
815
- self.results[fert_name]['миллиграммы'] += int(grams * 1000)
816
-
817
- fert_ec = 0.0
818
- for elem, percent in self.fertilizers[fert_name].items():
819
- added_ppm = (grams * percent * 1000) / self.volume
820
- self.results[fert_name][f'внесет {self._label(elem)}'] += added_ppm
821
- self.actual_profile[elem] += added_ppm
822
- fert_ec += added_ppm * EC_COEFFICIENTS.get(elem, 0.0015)
823
-
824
- self.results[fert_name]['вклад в EC'] += fert_ec
825
- self.total_ec += fert_ec
826
-
827
- # Проверка результатов
828
- return self.validate_results()
829
-
830
- def validate_results(self):
831
- """Проверка соответствия целевым значениям"""
832
- for element, target_value in self.target_profile.items():
833
- actual_value = self.actual_profile[element]
834
- if abs(actual_value - target_value) > 0.1: # Допустимая погрешность
835
- print(f"Несоответствие: {element} (цель: {target_value:.2f}, фактически: {actual_value:.2f})")
836
- return False
837
- return True
 
 
 
 
 
 
 
 
 
838
 
839
  def calculate_ec(self):
840
  return round(self.total_ec, 2)
 
726
  'N (NO3-)': 0.0017, 'N (NH4+)': 0.0019
727
  }
728
 
 
 
729
  class NutrientCalculator:
730
+ def __init__(self, volume_liters=1.0, profile=BASE_PROFILE):
731
  self.volume = volume_liters
732
  self.results = {}
733
+ self.target_profile = profile.copy()
734
  self.actual_profile = {k: 0.0 for k in self.target_profile}
735
+ self.fertilizers = NUTRIENT_CONTENT_IN_FERTILIZERS
736
  self.total_ec = 0.0
737
 
738
  # Расчёт азота
 
746
  "NH4+": self.target_profile['N (NH4+)']
747
  }
748
 
749
+ # Веса компенсации
750
+ self.compensation_weights = {
751
+ "Ca": {"weight": 0.3, "fert": "Сульфат кальция", "main_element": "Ca"},
752
+ "K": {"weight": 0.2, "fert": "Калий азотнокислый", "main_element": "K"},
753
+ "Mg": {"weight": 0.2, "fert": "Сульфат магния", "main_element": "Mg"},
754
+ "P": {"weight": 0.1, "fert": "Монофосфат калия", "main_element": "P"},
755
+ "S": {"weight": 0.1, "fert": "Калий сернокислый", "main_element": "S"},
756
+ "N (NO3-)": {"weight": 0.05, "fert": "Калий азотнокислый", "main_element": "N (NO3-)"},
757
+ "N (NH4+)": {"weight": 0.05, "fert": "Аммоний азотнокислый", "main_element": "N (NH4+)"}
758
+ }
759
 
760
  def _label(self, element):
761
  """Форматирование названий элементов для вывода"""
 
767
 
768
  def calculate(self):
769
  try:
770
+ # Первый проход: компенсация основных элементов
771
+ self._compensate_main_elements()
 
 
 
 
 
 
772
 
773
+ # Второй проход: компенсация азота
774
+ self._compensate_nitrogen()
775
 
776
+ # Третий проход: компенсация второстепенных элементов
777
+ self._compensate_secondary_elements()
 
 
778
 
779
+ # Четвертый проход: корректировка перебора
780
+ self._adjust_overages()
781
 
782
+ return self.results
783
  except Exception as e:
784
  print(f"Ошибка при расчёте: {str(e)}")
785
  raise
786
 
787
+ def _compensate_main_elements(self):
788
+ """Компенсация основных элементов (Ca, Mg, P)"""
789
+ for element, weight_data in self.compensation_weights.items():
790
+ if element in ["Ca", "Mg", "P"]:
791
+ fert_name = weight_data["fert"]
792
+ main_element = weight_data["main_element"]
793
+ required_ppm = self.target_profile[main_element] - self.actual_profile[main_element]
794
+ if required_ppm > 0.1:
795
+ self._apply_with_limit(fert_name, main_element, required_ppm)
796
+
797
+ def _compensate_nitrogen(self):
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._apply_with_limit(fert_name, main_element, required_ppm)
814
 
815
+ def _apply_with_limit(self, fert_name, main_element, required_ppm):
816
+ """Применение удобрения с ограничением по перебору"""
817
+ if required_ppm <= 0:
818
+ return
 
819
 
820
+ try:
821
+ content = self.fertilizers[fert_name][main_element]
822
+ max_allowed_ppm = self.target_profile[main_element] - self.actual_profile[main_element]
823
+ grams = min((required_ppm * self.volume) / (content * 1000), (max_allowed_ppm * self.volume) / (content * 1000))
824
+
825
+ if fert_name not in self.results:
826
+ result = {
827
+ 'граммы': 0.0,
828
+ 'миллиграммы': 0,
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
+ """Корректировка перебора элементов"""
853
+ for element in self.actual_profile:
854
+ if self.actual_profile[element] > self.target_profile[element]:
855
+ overage = self.actual_profile[element] - self.target_profile[element]
856
+ self.actual_profile[element] -= overage
857
+ print(f"Корректировка перебора: {element} уменьшен на {overage:.2f} ppm")
858
+
859
+ def calculate_ec(self):
860
+ return round(self.total_ec, 2)
861
+
862
+ def print_initial_nitrogen_report(self):
863
+ try:
864
+ print("Исходный расчёт азота:")
865
+ print(f" NO3-: {self.initial_n_profile['NO3-']} ppm")
866
+ print(f" NH4+: {self.initial_n_profile['NH4+']} ppm")
867
+ except Exception as e:
868
+ print(f"Ошибка при выводе отчёта: {str(e)}")
869
+ raise
870
 
871
  def calculate_ec(self):
872
  return round(self.total_ec, 2)