DmitrMakeev commited on
Commit
d4c05da
·
verified ·
1 Parent(s): 784fb9d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -102
app.py CHANGED
@@ -726,6 +726,8 @@ EC_COEFFICIENTS = {
726
  'N (NO3-)': 0.0017, 'N (NH4+)': 0.0019
727
  }
728
 
 
 
729
  class NutrientCalculator:
730
  def __init__(self, volume_liters=1.0, profile=None):
731
  self.volume = volume_liters
@@ -746,16 +748,8 @@ class NutrientCalculator:
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,116 +761,80 @@ class NutrientCalculator:
767
 
768
  def calculate(self):
769
  try:
770
- max_iterations = 10 # Максимальное количество итераций для корректировки
771
- iteration = 0
772
- while iteration < max_iterations:
773
- self._reset_actual_profile()
774
- self._compensate_main_elements()
775
- self._compensate_nitrogen()
776
- self._compensate_secondary_elements()
777
 
778
- # Проверка результатов
779
- if self.validate_results():
780
- break
781
 
782
- # Корректировка перебора
783
- self._adjust_overages()
784
- iteration += 1
785
 
786
- if iteration == max_iterations:
787
- raise ValueError("Не удалось достичь целевых значений после максимального количества итераций.")
 
 
 
 
788
 
789
- return self.results
790
  except Exception as e:
791
  print(f"Ошибка при расчёте: {str(e)}")
792
  raise
793
 
794
- def validate_results(self):
795
- """Проверка соответствия целевым значениям"""
796
- for element, target_value in self.target_profile.items():
797
- actual_value = self.actual_profile[element]
798
- if abs(actual_value - target_value) > 0.1: # Допустимая погрешность
799
- print(f"Несоответствие: {element} (цель: {target_value:.2f}, фактически: {actual_value:.2f})")
800
- return False
801
- return True
802
 
803
  def _reset_actual_profile(self):
804
- """Сброс фактического профиля перед новой итерацией"""
805
  self.actual_profile = {k: 0.0 for k in self.target_profile}
806
  self.total_ec = 0.0
807
  self.results = {}
808
 
809
- def _compensate_main_elements(self):
810
- """Компенсация основных элементов (Ca, Mg, P)"""
811
- for element, weight_data in self.compensation_weights.items():
812
- if element in ["Ca", "Mg", "P"]:
813
- fert_name = weight_data["fert"]
814
- main_element = weight_data["main_element"]
815
- required_ppm = self.target_profile[main_element] - self.actual_profile[main_element]
816
- if required_ppm > 0.1:
817
- self._apply_with_limit(fert_name, main_element, required_ppm)
818
-
819
- def _compensate_nitrogen(self):
820
- """Компенсация азота (NO3-, NH4+)"""
821
- for nitrogen_type in ["N (NO3-)", "N (NH4+)"]:
822
- required_ppm = self.target_profile[nitrogen_type] - self.actual_profile[nitrogen_type]
823
- if required_ppm > 0.1:
824
- fert_name = self.compensation_weights[nitrogen_type]["fert"]
825
- self._apply_with_limit(fert_name, nitrogen_type, required_ppm)
826
-
827
- def _compensate_secondary_elements(self):
828
- """Компенсация второстепенных элементов (K, S)"""
829
- for element, weight_data in self.compensation_weights.items():
830
- if element in ["K", "S"]:
831
- fert_name = weight_data["fert"]
832
- main_element = weight_data["main_element"]
833
- required_ppm = self.target_profile[main_element] - self.actual_profile[main_element]
834
  if required_ppm > 0.1:
835
- self._apply_with_limit(fert_name, main_element, required_ppm)
836
 
837
- def _apply_with_limit(self, fert_name, main_element, required_ppm):
838
- """Применение удобрения с ограничением по перебору"""
839
- if required_ppm <= 0:
840
- return
 
 
 
 
841
 
842
- try:
843
- content = self.fertilizers[fert_name][main_element]
844
- max_allowed_ppm = self.target_profile[main_element] - self.actual_profile[main_element]
845
- grams = min((required_ppm * self.volume) / (content * 1000), (max_allowed_ppm * self.volume) / (content * 1000))
846
-
847
- if fert_name not in self.results:
848
- result = {
849
- 'граммы': 0.0,
850
- 'миллиграммы': 0,
851
- 'вклад в EC': 0.0
852
- }
853
- for element in self.fertilizers[fert_name]:
854
- result[f'внесет {self._label(element)}'] = 0.0
855
- self.results[fert_name] = result
856
-
857
- self.results[fert_name]['граммы'] += grams
858
- self.results[fert_name]['миллиграммы'] += int(grams * 1000)
859
-
860
- fert_ec = 0.0
861
- for element, percent in self.fertilizers[fert_name].items():
862
- added_ppm = (grams * percent * 1000) / self.volume
863
- self.results[fert_name][f'внесет {self._label(element)}'] += added_ppm
864
- self.actual_profile[element] += added_ppm
865
- fert_ec += added_ppm * EC_COEFFICIENTS.get(element, 0.0015)
866
-
867
- self.results[fert_name]['вклад в EC'] += fert_ec
868
- self.total_ec += fert_ec
869
- except KeyError as e:
870
- print(f"Ошибка: отсутствует элемент {str(e)} в удобрении {fert_name}")
871
- raise
872
 
873
- def _adjust_overages(self):
874
- """Корректировка перебора элементов"""
875
- for element in self.actual_profile:
876
- if self.actual_profile[element] > self.target_profile[element]:
877
- overage = self.actual_profile[element] - self.target_profile[element]
878
- self.actual_profile[element] -= overage
879
- print(f"Корректировка перебора: {element} уменьшен на {overage:.2f} ppm")
 
 
 
 
880
 
881
  def calculate_ec(self):
882
  return round(self.total_ec, 2)
 
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
 
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
 
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)