DmitrMakeev commited on
Commit
8255bf9
·
verified ·
1 Parent(s): 683a6e7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +106 -106
app.py CHANGED
@@ -696,69 +696,64 @@ def nutri_call():
696
 
697
  from tabulate import tabulate
698
 
699
- # Глобальные параметры
700
- TOTAL_NITROGEN = 120.0 # Общее количество азота
701
- NO3_RATIO = 8.0 # Соотношение NO3:NH4
702
- NH4_RATIO = 1.00 # Соотношение NH4:NO3
703
- VOLUME_LITERS = 100 # Объем раствора
704
 
 
 
 
 
 
 
 
 
705
  BASE_PROFILE = {
706
- "P": 50, # Фосфор
707
- "K": 300, # Калий
708
- "Mg": 120, # Магний (высокий уровень)
709
- "Ca": 150, # Кальций
710
- "S": 100, # Сера
711
- "N (NO3-)": 0, # Рассчитывается автоматически
712
- "N (NH4+)": 0 # Рассчитывается автоматически
713
  }
714
 
 
715
  NUTRIENT_CONTENT_IN_FERTILIZERS = {
716
  "Кальциевая селитра": {"N (NO3-)": 0.11863, "Ca": 0.16972},
717
  "Калий азотнокислый": {"N (NO3-)": 0.136, "K": 0.382},
718
- "Калий сернокислый": {"K": 0.44874, "S": 0.18401},
719
  "Аммоний азотнокислый": {"N (NO3-)": 0.17499, "N (NH4+)": 0.17499},
720
  "Сульфат магния": {"Mg": 0.09861, "S": 0.13010},
721
  "Монофосфат калия": {"P": 0.218, "K": 0.275},
722
- "Сульфат кальция": {"Ca": 0.23, "S": 0.186}
723
- }
724
-
725
- EC_COEFFICIENTS = {
726
- 'P': 0.0012, 'K': 0.0018, 'Mg': 0.0015,
727
- 'Ca': 0.0016, 'S': 0.0014,
728
- 'N (NO3-)': 0.0017, 'N (NH4+)': 0.0019
729
  }
730
 
731
  class NutrientCalculator:
732
- def __init__(self, volume_liters=1.0, profile=BASE_PROFILE):
 
733
  self.volume = volume_liters
734
  self.results = {}
735
- self.target_profile = 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
- # Расчёт азота
741
- total_parts = NO3_RATIO + NH4_RATIO
742
- self.target_profile['N (NO3-)'] = TOTAL_NITROGEN * (NO3_RATIO / total_parts)
743
- self.target_profile['N (NH4+)'] = TOTAL_NITROGEN * (NH4_RATIO / total_parts)
744
-
745
- # Сохраняем исходный профиль азота
746
- self.initial_n_profile = {
747
- "NO3-": self.target_profile['N (NO3-)'],
748
- "NH4+": self.target_profile['N (NH4+)']
749
  }
750
 
751
- # Веса компенсации
752
- self.compensation_weights = {
753
- "Ca": {"weight": 0.3, "fert": "Сульфат кальция", "main_element": "Ca"},
754
- "K": {"weight": 0.2, "fert": "Калий азотнокислый", "main_element": "K"},
755
- "Mg": {"weight": 0.2, "fert": "Сульфат магния", "main_element": "Mg"},
756
- "P": {"weight": 0.1, "fert": "Монофосфат калия", "main_element": "P"},
757
- "S": {"weight": 0.1, "fert": "Калий сернокислый", "main_element": "S"},
758
- "N (NO3-)": {"weight": 0.05, "fert": "Калий азотнокислый", "main_element": "N (NO3-)"},
759
- "N (NH4+)": {"weight": 0.05, "fert": "Аммоний азотнокислый", "main_element": "N (NH4+)"}
760
  }
761
 
 
 
 
 
 
762
  def _label(self, element):
763
  """Форматирование названий элементов для вывода"""
764
  labels = {
@@ -768,62 +763,84 @@ class NutrientCalculator:
768
  return labels.get(element, element)
769
 
770
  def calculate(self):
 
771
  try:
772
- # Первый проход: компенсация основных элементов
773
- self._compensate_main_elements()
774
 
775
- # Второй проход: компенсация азота
776
- self._compensate_nitrogen()
777
 
778
- # Третий проход: компенсация второстепенных элементов
779
- self._compensate_secondary_elements()
780
 
781
- # Четвертый проход: корректировка перебора
782
- self._adjust_overages()
 
 
 
783
 
784
  return self.results
785
  except Exception as e:
786
  print(f"Ошибка при расчёте: {str(e)}")
787
  raise
788
 
789
- def _compensate_main_elements(self):
790
- """Компенсация основных элементов (Ca, Mg, P)"""
791
- for element, weight_data in self.compensation_weights.items():
792
- if element in ["Ca", "Mg", "P"]:
793
- fert_name = weight_data["fert"]
794
- main_element = weight_data["main_element"]
795
- required_ppm = self.target_profile[main_element] - self.actual_profile[main_element]
796
- if required_ppm > 0.1:
797
- self._apply_with_limit(fert_name, main_element, required_ppm)
798
-
799
- def _compensate_nitrogen(self):
800
- """Компенсация азота (NO3-, NH4+)"""
801
- for nitrogen_type in ["N (NO3-)", "N (NH4+)"]:
802
- required_ppm = self.target_profile[nitrogen_type] - self.actual_profile[nitrogen_type]
803
- if required_ppm > 0.1:
804
- fert_name = self.compensation_weights[nitrogen_type]["fert"]
805
- self._apply_with_limit(fert_name, nitrogen_type, required_ppm)
806
-
807
- def _compensate_secondary_elements(self):
808
- """Компенсация второстепенных элементов (K, S)"""
809
- for element, weight_data in self.compensation_weights.items():
810
- if element in ["K", "S"]:
811
- fert_name = weight_data["fert"]
812
- main_element = weight_data["main_element"]
813
- required_ppm = self.target_profile[main_element] - self.actual_profile[main_element]
814
- if required_ppm > 0.1:
815
- self._apply_with_limit(fert_name, main_element, required_ppm)
816
-
817
- def _apply_with_limit(self, fert_name, main_element, required_ppm):
818
- """Применение удобрения с ограничением по перебору"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
819
  if required_ppm <= 0:
820
  return
821
 
822
  try:
823
  content = self.fertilizers[fert_name][main_element]
824
- max_allowed_ppm = self.target_profile[main_element] - self.actual_profile[main_element]
825
- grams = min((required_ppm * self.volume) / (content * 1000), (max_allowed_ppm * self.volume) / (content * 1000))
826
-
827
  if fert_name not in self.results:
828
  result = {
829
  'граммы': 0.0,
@@ -833,43 +850,29 @@ class NutrientCalculator:
833
  for element in self.fertilizers[fert_name]:
834
  result[f'внесет {self._label(element)}'] = 0.0
835
  self.results[fert_name] = result
836
-
837
  self.results[fert_name]['граммы'] += grams
838
  self.results[fert_name]['миллиграммы'] += int(grams * 1000)
839
-
840
  fert_ec = 0.0
841
  for element, percent in self.fertilizers[fert_name].items():
842
  added_ppm = (grams * percent * 1000) / self.volume
843
  self.results[fert_name][f'внесет {self._label(element)}'] += added_ppm
844
  self.actual_profile[element] += added_ppm
845
  fert_ec += added_ppm * EC_COEFFICIENTS.get(element, 0.0015)
846
-
847
  self.results[fert_name]['вклад в EC'] += fert_ec
848
  self.total_ec += fert_ec
849
  except KeyError as e:
850
  print(f"Ошибка: отсутствует элемент {str(e)} в удобрении {fert_name}")
851
  raise
852
 
853
- def _adjust_overages(self):
854
- """Корректировка перебора элементов"""
855
- for element in self.actual_profile:
856
- if self.actual_profile[element] > self.target_profile[element]:
857
- overage = self.actual_profile[element] - self.target_profile[element]
858
- self.actual_profile[element] -= overage
859
- print(f"Корректировка перебора: {element} уменьшен на {overage:.2f} ppm")
860
-
861
  def calculate_ec(self):
 
862
  return round(self.total_ec, 2)
863
 
864
- def print_initial_nitrogen_report(self):
865
- try:
866
- print("Исходный расчёт азота:")
867
- print(f" NO3-: {self.initial_n_profile['NO3-']} ppm")
868
- print(f" NH4+: {self.initial_n_profile['NH4+']} ppm")
869
- except Exception as e:
870
- print(f"Ошибка при выводе отчёта: {str(e)}")
871
- raise
872
  def print_report(self):
 
873
  try:
874
  print("\n" + "="*60)
875
  print("ПРОФИЛЬ ПИТАТЕЛЬНОГО РАСТВОРА (ИТОГО):")
@@ -877,10 +880,6 @@ class NutrientCalculator:
877
  table = [[el, round(self.actual_profile[el], 1)] for el in self.actual_profile]
878
  print(tabulate(table, headers=["Элемент", "ppm"]))
879
 
880
- print("\nИсходный расчёт азота:")
881
- for form, val in self.initial_n_profile.items():
882
- print(f" {form}: {round(val, 1)} ppm")
883
-
884
  print("\n" + "="*60)
885
  print(f"РАСЧЕТ ДЛЯ {self.volume} ЛИТРОВ РАСТВОРА")
886
  print("="*60)
@@ -916,6 +915,7 @@ class NutrientCalculator:
916
  print(f"Ошибка при выводе отчёта: {str(e)}")
917
  raise
918
 
 
919
  if __name__ == "__main__":
920
  try:
921
  calculator = NutrientCalculator(volume_liters=VOLUME_LITERS)
 
696
 
697
  from tabulate import tabulate
698
 
699
+ # Константы
700
+ TOTAL_NITROGEN = 125.000
701
+ NO3_RATIO = 8.25
702
+ NH4_RATIO = 1.00
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
+ 'P': 31.000, 'K': 210.000, 'Mg': 24.000,
715
+ 'Ca': 84.000, 'S': 56.439,
716
+ 'N (NO3-)': 0, 'N (NH4+)': 0
 
 
 
 
717
  }
718
 
719
+ # Содержание элементов в удобрениях
720
  NUTRIENT_CONTENT_IN_FERTILIZERS = {
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
+ "Калий сернокислый": {"K": 0.44874, "S": 0.18401}
 
 
 
 
 
 
727
  }
728
 
729
  class NutrientCalculator:
730
+ def __init__(self, volume_liters=1.0):
731
+ # Общие параметры
732
  self.volume = volume_liters
733
  self.results = {}
734
+ self.target_profile = BASE_PROFILE.copy()
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
+ self.element_compensation_weights = {
741
+ "POTASSIUM_SULFATE": {"weight": 0.18, "fert": "Калий сернокислый", "main_element": "K"},
742
+ "MAGNESIUM_SULFATE": {"weight": -0.08, "fert": "Сульфат магния", "main_element": "Mg"},
743
+ "MONOPOTASSIUM_PHOSPHATE": {"weight": 0.14, "fert": "Монофосфат калия", "main_element": "P"}
 
 
 
 
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 = {
 
763
  return labels.get(element, element)
764
 
765
  def calculate(self):
766
+ """Основной метод расчета"""
767
  try:
768
+ # 1. Вносим кальциевую селитру для Ca и частично для NO3
769
+ self._apply_calcium_nitrate()
770
 
771
+ # 2. Вносим аммонийный азот напрямую
772
+ self._apply("Аммоний азотнокислый", "N (NH4+)", self.target_profile['N (NH4+)'])
773
 
774
+ # 3. Компенсируем остаток NO3 через калийную селитру
775
+ self._compensate_no3()
776
 
777
+ # 4. Компенсируем остальные элементы через веса компенсации
778
+ self._compensate_element("Mg")
779
+ self._compensate_element("P")
780
+ self._compensate_element("S")
781
+ self._compensate_element("K")
782
 
783
  return self.results
784
  except Exception as e:
785
  print(f"Ошибка при расчёте: {str(e)}")
786
  raise
787
 
788
+ def _apply_calcium_nitrate(self):
789
+ """Специальный метод для внесения кальциевой селитры"""
790
+ # Вносим кальций
791
+ ca_needed = self.target_profile['Ca'] - self.actual_profile.get('Ca', 0)
792
+ if ca_needed > 0.1:
793
+ ca_share = self.calcium_nitrate_ratios['Ca']
794
+ ca_to_apply = ca_needed * ca_share
795
+ self._apply("Кальциевая селитра", "Ca", ca_to_apply)
796
+
797
+ # Вносим часть NO3 из кальциевой селитры
798
+ no3_needed = self.target_profile['N (NO3-)'] - self.actual_profile.get('N (NO3-)', 0)
799
+ if no3_needed > 0.1:
800
+ no3_share = self.calcium_nitrate_ratios['NO3']
801
+ no3_to_apply = no3_needed * no3_share
802
+ self._apply("Кальциевая селитра", "N (NO3-)", no3_to_apply)
803
+
804
+ def _compensate_no3(self):
805
+ """Компенсация остатка NO3 после внесения кальциевой селитры"""
806
+ no3_needed = self.target_profile['N (NO3-)'] - self.actual_profile.get('N (NO3-)', 0)
807
+ if no3_needed > 0.1:
808
+ self._apply("Калий азотнокислый", "N (NO3-)", no3_needed)
809
+
810
+ def _compensate_element(self, element):
811
+ """Общий метод компенсации для других элементов"""
812
+ needed = self.target_profile[element] - self.actual_profile.get(element, 0)
813
+ if abs(needed) < 0.1:
814
+ return
815
+
816
+ candidates = []
817
+ for weight_key, weight_data in self.element_compensation_weights.items():
818
+ fert_name = weight_data["fert"]
819
+ if element in self.fertilizers.get(fert_name, {}):
820
+ candidates.append({
821
+ 'name': fert_name,
822
+ 'weight': weight_data["weight"],
823
+ 'content': self.fertilizers[fert_name][element]
824
+ })
825
+
826
+ if not candidates:
827
+ raise ValueError(f"Нет удобрений для элемента {element}")
828
+
829
+ total_weight = sum(c['weight'] for c in candidates)
830
+ for candidate in candidates:
831
+ share = candidate['weight'] / total_weight
832
+ ppm_to_apply = needed * share
833
+ self._apply(candidate['name'], element, ppm_to_apply)
834
+
835
+ def _apply(self, fert_name, main_element, required_ppm):
836
+ """Применение удобрения для конкретного элемента"""
837
  if required_ppm <= 0:
838
  return
839
 
840
  try:
841
  content = self.fertilizers[fert_name][main_element]
842
+ grams = (required_ppm * self.volume) / (content * 1000)
843
+
 
844
  if fert_name not in self.results:
845
  result = {
846
  'граммы': 0.0,
 
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
  try:
877
  print("\n" + "="*60)
878
  print("ПРОФИЛЬ ПИТАТЕЛЬНОГО РАСТВОРА (ИТОГО):")
 
880
  table = [[el, round(self.actual_profile[el], 1)] for el in self.actual_profile]
881
  print(tabulate(table, headers=["Элемент", "ppm"]))
882
 
 
 
 
 
883
  print("\n" + "="*60)
884
  print(f"РАСЧЕТ ДЛЯ {self.volume} ЛИТРОВ РАСТВОРА")
885
  print("="*60)
 
915
  print(f"Ошибка при выводе отчёта: {str(e)}")
916
  raise
917
 
918
+
919
  if __name__ == "__main__":
920
  try:
921
  calculator = NutrientCalculator(volume_liters=VOLUME_LITERS)