DmitrMakeev commited on
Commit
4e0bd06
·
verified ·
1 Parent(s): b0f9081

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +180 -41
app.py CHANGED
@@ -690,6 +690,39 @@ def nutri_call():
690
 
691
 
692
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
693
  from tabulate import tabulate
694
 
695
  # Константы
@@ -722,15 +755,15 @@ NUTRIENT_CONTENT_IN_FERTILIZERS = {
722
  }
723
 
724
  class NutrientCalculator:
725
- def __init__(self, volume_liters: float = 1.0):
726
  self.volume = volume_liters
727
- self.results: Dict[str, Dict[str, Any]] = {}
728
  self.target_profile = BASE_PROFILE.copy()
729
  self.actual_profile = {k: 0.0 for k in BASE_PROFILE}
730
  self.fertilizers = NUTRIENT_CONTENT_IN_FERTILIZERS
731
  self.total_ec = 0.0
732
 
733
- # Расчет азота
734
  total_parts = NO3_RATIO + NH4_RATIO
735
  self.target_profile['N (NO3-)'] = TOTAL_NITROGEN * (NO3_RATIO / total_parts)
736
  self.target_profile['N (NH4+)'] = TOTAL_NITROGEN * (NH4_RATIO / total_parts)
@@ -739,14 +772,7 @@ class NutrientCalculator:
739
  "NH4+": self.target_profile['N (NH4+)']
740
  }
741
 
742
- # Настройки компенсации по умолчанию
743
- self.compensation_weights = {
744
- 'KNO3': 0.5, # Вес калийной селитры (0-1)
745
- 'CaNO3': 0.3, # Вес кальциевой селитры (0-1)
746
- 'K2SO4': 0.2 # Вес сульфата калия (0-1)
747
- }
748
-
749
- def _label(self, element: str) -> str:
750
  """Форматирование названий элементов для вывода"""
751
  labels = {
752
  'N (NO3-)': 'NO3',
@@ -754,48 +780,161 @@ class NutrientCalculator:
754
  }
755
  return labels.get(element, element)
756
 
757
- def set_compensation_weights(self, kno3_weight: float, cano3_weight: float, k2so4_weight: float):
758
- """Установка весов для компенсации элементов"""
759
- total = kno3_weight + cano3_weight + k2so4_weight
760
- self.compensation_weights = {
761
- 'KNO3': kno3_weight / total,
762
- 'CaNO3': cano3_weight / total,
763
- 'K2SO4': k2so4_weight / total
764
- }
765
-
766
- def calculate(self) -> Dict[str, Any]:
767
- """Основной метод расчета с новой логикой"""
768
  try:
769
- # 1. Вносим Mg и S
770
  self._apply("Сульфат магния", "Mg", self.target_profile['Mg'])
 
 
 
771
 
772
- # 2. Балансируем азот с учетом компенсации
773
- self._balance_nitrogen_with_compensation()
774
 
775
- # 3. Вносим Ca (остаток)
776
- ca_needed = self.target_profile['Ca'] - self.actual_profile['Ca']
777
- if ca_needed > 0.1:
778
- self._apply("Кальциевая селитра", "Ca", ca_needed)
779
 
780
- # 4. Вносим P
781
- p_needed = self.target_profile['P'] - self.actual_profile['P']
782
- if p_needed > 0.1:
783
- self._apply("Монофосфат калия", "P", p_needed)
784
 
785
- # 5. Корректируем K через сульфат калия (если остался дефицит)
786
- k_needed = self.target_profile['K'] - self.actual_profile['K']
787
- if k_needed > 0.1:
788
- self._apply("Калий сернокислый", "K", k_needed)
789
 
790
  return self.results
791
-
792
  except Exception as e:
793
  print(f"Ошибка при расчёте: {str(e)}")
794
  raise
795
 
796
- # ... остальные методы класса NutrientCalculator ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
797
 
798
- def round_floats(obj: Union[float, Dict, List], ndigits: int = 3) -> Union[float, Dict, List]:
799
  """Рекурсивно округляет все float значения в структуре данных"""
800
  if isinstance(obj, float):
801
  return round(obj, ndigits)
@@ -898,7 +1037,7 @@ def handle_calculation():
898
  if 'fertilizers' in rounded_response:
899
  for fert in rounded_response['fertilizers'].values():
900
  if 'миллиграммы' in fert:
901
- fert['миллиграммы'] = int(round(fert['граммы'] * 1000))
902
 
903
  return jsonify(rounded_response)
904
 
 
690
 
691
 
692
 
693
+ from tabulate import tabulate
694
+
695
+ # Константы
696
+ TOTAL_NITROGEN = 125.000
697
+ NO3_RATIO = 8.25
698
+ NH4_RATIO = 1.00
699
+ VOLUME_LITERS = 100
700
+
701
+ # Коэффициенты электропроводности
702
+ EC_COEFFICIENTS = {
703
+ 'P': 0.0012, 'K': 0.0018, 'Mg': 0.0015,
704
+ 'Ca': 0.0016, 'S': 0.0014,
705
+ 'N (NO3-)': 0.0017, 'N (NH4+)': 0.0019
706
+ }
707
+
708
+ # Целевые значения
709
+ BASE_PROFILE = {
710
+ 'P': 31.000, 'K': 210.000, 'Mg': 24.000,
711
+ 'Ca': 84.000, 'S': 56.439,
712
+ 'N (NO3-)': 0, '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
+ }
723
+
724
+
725
+
726
  from tabulate import tabulate
727
 
728
  # Константы
 
755
  }
756
 
757
  class NutrientCalculator:
758
+ def __init__(self, volume_liters=1.0):
759
  self.volume = volume_liters
760
+ self.results = {}
761
  self.target_profile = BASE_PROFILE.copy()
762
  self.actual_profile = {k: 0.0 for k in BASE_PROFILE}
763
  self.fertilizers = NUTRIENT_CONTENT_IN_FERTILIZERS
764
  self.total_ec = 0.0
765
 
766
+ # Расчёт азота
767
  total_parts = NO3_RATIO + NH4_RATIO
768
  self.target_profile['N (NO3-)'] = TOTAL_NITROGEN * (NO3_RATIO / total_parts)
769
  self.target_profile['N (NH4+)'] = TOTAL_NITROGEN * (NH4_RATIO / total_parts)
 
772
  "NH4+": self.target_profile['N (NH4+)']
773
  }
774
 
775
+ def _label(self, element):
 
 
 
 
 
 
 
776
  """Форматирование названий элементов для вывода"""
777
  labels = {
778
  'N (NO3-)': 'NO3',
 
780
  }
781
  return labels.get(element, element)
782
 
783
+ def calculate(self):
 
 
 
 
 
 
 
 
 
 
784
  try:
 
785
  self._apply("Сульфат магния", "Mg", self.target_profile['Mg'])
786
+ self._apply("Кальциевая селитра", "Ca", self.target_profile['Ca'])
787
+ self._apply("Монофосфат калия", "P", self.target_profile['P'])
788
+ self._apply("Аммоний азотнокислый", "N (NH4+)", self.target_profile['N (NH4+)'])
789
 
790
+ current_no3 = self.actual_profile['N (NO3-)']
791
+ no3_needed = self.target_profile['N (NO3-)'] - current_no3
792
 
793
+ if no3_needed > 0.1:
794
+ self._apply("Калий азотнокислый", "N (NO3-)", no3_needed)
 
 
795
 
796
+ self._apply_k_sulfate()
 
 
 
797
 
798
+ k_deficit = self.target_profile['K'] - self.actual_profile['K']
799
+ if k_deficit > 0.1:
800
+ self._apply("Калий азотнокислый", "K", k_deficit)
 
801
 
802
  return self.results
 
803
  except Exception as e:
804
  print(f"Ошибка при расчёте: {str(e)}")
805
  raise
806
 
807
+ def _apply(self, fert_name, main_element, required_ppm):
808
+ if required_ppm <= 0:
809
+ return
810
+
811
+ try:
812
+ content = self.fertilizers[fert_name][main_element]
813
+ grams = (required_ppm * self.volume) / (content * 1000)
814
+
815
+ if fert_name not in self.results:
816
+ result = {
817
+ 'граммы': 0.0,
818
+ 'миллиграммы': 0,
819
+ 'вклад в EC': 0.0
820
+ }
821
+ for element in self.fertilizers[fert_name]:
822
+ result[f'внесет {self._label(element)}'] = 0.0
823
+ self.results[fert_name] = result
824
+
825
+ self.results[fert_name]['граммы'] += grams
826
+ self.results[fert_name]['миллиграммы'] += int(grams * 1000)
827
+
828
+ fert_ec = 0.0
829
+ for element, percent in self.fertilizers[fert_name].items():
830
+ added_ppm = (grams * percent * 1000) / self.volume
831
+ self.results[fert_name][f'внесет {self._label(element)}'] += added_ppm
832
+ self.actual_profile[element] += added_ppm
833
+ fert_ec += added_ppm * EC_COEFFICIENTS.get(element, 0.0015)
834
+
835
+ self.results[fert_name]['вклад в EC'] += fert_ec
836
+ self.total_ec += fert_ec
837
+ except KeyError as e:
838
+ print(f"Ошибка: отсутствует элемент {str(e)} в удобрении {fert_name}")
839
+ raise
840
+
841
+ def _apply_k_sulfate(self):
842
+ fert = "Калий сернокислый"
843
+ k_def = self.target_profile['K'] - self.actual_profile['K']
844
+ s_def = self.target_profile['S'] - self.actual_profile['S']
845
+
846
+ if k_def <= 0 and s_def <= 0:
847
+ return
848
+
849
+ try:
850
+ if s_def > 0.1:
851
+ s_content = self.fertilizers[fert]["S"]
852
+ grams_s = (s_def * self.volume) / (s_content * 1000)
853
+
854
+ k_content = self.fertilizers[fert]["K"]
855
+ k_from_s = (grams_s * k_content * 1000) / self.volume
856
+
857
+ if k_from_s > k_def and k_def > 0.1:
858
+ grams = (k_def * self.volume) / (k_content * 1000)
859
+ else:
860
+ grams = grams_s
861
+
862
+ self._apply(fert, "S", s_def)
863
+ except Exception as e:
864
+ print(f"Ошибка при расчёте сульфата калия: {str(e)}")
865
+ raise
866
+
867
+ def calculate_ec(self):
868
+ return round(self.total_ec, 2)
869
+
870
+ def print_report(self):
871
+ try:
872
+ print("\n" + "="*60)
873
+ print("ПРОФИЛЬ ПИТАТЕЛЬНОГО РАСТВОРА (ИТОГО):")
874
+ print("="*60)
875
+ table = [[el, round(self.actual_profile[el], 1)] for el in self.actual_profile]
876
+ print(tabulate(table, headers=["Элемент", "ppm"]))
877
+
878
+ print("\nИсходный расчёт азота:")
879
+ for form, val in self.initial_n_profile.items():
880
+ print(f" {form}: {round(val, 1)} ppm")
881
+
882
+ print("\n" + "="*60)
883
+ print(f"РАСЧЕТ ДЛЯ {self.volume} ЛИТРОВ РАСТВОРА")
884
+ print("="*60)
885
+ print(f"Общая концентрация: {round(sum(self.actual_profile.values()), 1)} ppm")
886
+ print(f"EC: {self.calculate_ec()} mS/cm")
887
+
888
+ print("\nРЕКОМЕНДУЕМЫЕ УДОБРЕНИЯ:")
889
+ fert_table = []
890
+ for fert, data in self.results.items():
891
+ adds = [f"+{k}: {v:.1f} ppm" for k, v in data.items() if k.startswith('внесет')]
892
+ fert_table.append([
893
+ fert,
894
+ round(data['граммы'], 3),
895
+ data['миллиграммы'],
896
+ round(data['вклад в EC'], 3),
897
+ "\n".join(adds)
898
+ ])
899
+ print(tabulate(fert_table,
900
+ headers=["Удобрение", "Граммы", "Миллиграммы", "EC (мСм/см)", "Добавит"]))
901
+
902
+ print("\nОСТАТОЧНЫЙ ДЕФИЦИТ:")
903
+ deficit = {
904
+ k: round(self.target_profile[k] - self.actual_profile[k], 1)
905
+ for k in self.target_profile
906
+ if abs(self.target_profile[k] - self.actual_profile[k]) > 0.1
907
+ }
908
+ if deficit:
909
+ for el, val in deficit.items():
910
+ print(f" {el}: {val} ppm")
911
+ else:
912
+ print(" ��се элементы покрыты полностью")
913
+ except Exception as e:
914
+ print(f"Ошибка при выводе отчёта: {str(e)}")
915
+ raise
916
+
917
+ if __name__ == "__main__":
918
+ try:
919
+ calculator = NutrientCalculator(volume_liters=VOLUME_LITERS)
920
+ calculator.calculate()
921
+ calculator.print_report() # Правильный вызов метода класса
922
+ except Exception as e:
923
+ print(f"Критическая ошибка: {str(e)}")
924
+
925
+
926
+
927
+
928
+
929
+
930
+
931
+
932
+
933
+
934
+
935
+ from flask import request, jsonify
936
 
937
+ def round_floats(obj, ndigits=3):
938
  """Рекурсивно округляет все float значения в структуре данных"""
939
  if isinstance(obj, float):
940
  return round(obj, ndigits)
 
1037
  if 'fertilizers' in rounded_response:
1038
  for fert in rounded_response['fertilizers'].values():
1039
  if 'миллиграммы' in fert:
1040
+ fert['миллиграммы'] = int(round(fert['миллиграммы']))
1041
 
1042
  return jsonify(rounded_response)
1043