DmitrMakeev commited on
Commit
1e5a7e5
·
verified ·
1 Parent(s): 12e6413

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +144 -133
app.py CHANGED
@@ -766,6 +766,30 @@ NO3_RATIO = 8.25
766
  NH4_RATIO = 1.00
767
  VOLUME_LITERS = 100
768
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
769
  # Коэффициенты электропроводности
770
  EC_COEFFICIENTS = {
771
  'P': 0.0012, 'K': 0.0018, 'Mg': 0.0015,
@@ -793,36 +817,60 @@ class NutrientCalculator:
793
  def __init__(self, volume_liters=1.0):
794
  self.volume = volume_liters
795
  self.results = {}
796
- self.target_profile = {}
797
- self.actual_profile = {}
798
- self.fertilizers = {}
799
  self.total_ec = 0.0
800
 
801
- # Инициализация весов компенсации
802
- self.compensation_weights = {
803
- "POTASSIUM_NITRATE": {"weight": 0.5, "fert": "Калий азотнокислый", "main_element": "K"},
804
- "CALCIUM_NITRATE": {"weight": 0.3, "fert": "Кальциевая селитра", "main_element": "Ca"},
805
- "POTASSIUM_SULFATE": {"weight": 0.2, "fert": "Калий сернокислый", "main_element": "K"}
 
 
806
  }
807
 
808
  def _label(self, element):
 
809
  labels = {
810
  'N (NO3-)': 'NO3',
811
  'N (NH4+)': 'NH4'
812
  }
813
  return labels.get(element, element)
814
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
815
  def _apply(self, fert_name, main_element, required_ppm):
816
  if required_ppm <= 0:
817
  return
818
-
819
  try:
820
- content = self.fertilizers[fert_name].get(main_element, 0)
821
- if content == 0:
822
- raise KeyError(f"Элемент {main_element} отсутствует в удобрении {fert_name}")
823
-
824
  grams = (required_ppm * self.volume) / (content * 1000)
825
-
826
  if fert_name not in self.results:
827
  result = {
828
  'граммы': 0.0,
@@ -832,146 +880,109 @@ class NutrientCalculator:
832
  for element in self.fertilizers[fert_name]:
833
  result[f'внесет {self._label(element)}'] = 0.0
834
  self.results[fert_name] = result
835
-
836
  self.results[fert_name]['граммы'] += grams
837
- self.results[fert_name]['миллиграммы'] = int(grams * 1000)
838
-
839
  fert_ec = 0.0
840
  for element, percent in self.fertilizers[fert_name].items():
841
  added_ppm = (grams * percent * 1000) / self.volume
842
  self.results[fert_name][f'внесет {self._label(element)}'] += added_ppm
843
- self.actual_profile[element] = self.actual_profile.get(element, 0) + added_ppm
844
- fert_ec += added_ppm * 0.0015 # Примерный коэффициент EC
845
-
846
  self.results[fert_name]['вклад в EC'] += fert_ec
847
  self.total_ec += fert_ec
848
  except KeyError as e:
849
- print(f"Ошибка: {str(e)}")
850
  raise
851
 
852
- def _compensate_element(self, element):
853
- needed = self.target_profile[element] - self.actual_profile.get(element, 0)
854
- if needed <= 0:
 
 
 
855
  return
856
-
857
- candidates = []
858
- for weight_key, weight_data in self.compensation_weights.items():
859
- fert_name = weight_data["fert"]
860
- main_element = weight_data["main_element"]
861
-
862
- if element in self.fertilizers.get(fert_name, {}):
863
- candidates.append({
864
- 'name': fert_name,
865
- 'weight': weight_data["weight"],
866
- 'content': self.fertilizers[fert_name][element]
867
- })
868
-
869
- if not candidates:
870
- raise ValueError(f"Нет удобрений для элемента {element}")
871
-
872
- total_weight = sum(c['weight'] for c in candidates)
873
- for candidate in candidates:
874
- share = candidate['weight'] / total_weight
875
- ppm_to_apply = needed * share
876
- self._apply(candidate['name'], element, ppm_to_apply)
877
-
878
- def calculate(self):
879
  try:
880
- # Вносим магний
881
- self._apply("Сульфат магния", "Mg", self.target_profile['Mg'])
882
-
883
- # Вносим кальций через компенсацию
884
- self._compensate_element("Ca")
885
-
886
- # Вносим фосфор
887
- self._apply("Монофосфат калия", "P", self.target_profile['P'])
888
-
889
- # Вносим аммонийный азот
890
- self._apply("Аммоний азотнокислый", "N (NH4+)", self.target_profile['N (NH4+)'])
891
-
892
- # Компенсируем нитратный азот
893
- self._compensate_element("N (NO3-)")
894
-
895
- # Компенсируем серу
896
- self._compensate_element("S")
897
-
898
- # Компенсируем калий
899
- self._compensate_element("K")
900
-
901
- return self.results
902
  except Exception as e:
903
- print(f"Ошибка при расчёте: {str(e)}")
904
  raise
905
 
 
 
906
 
907
- # Роут для обработки расчетов
908
- @app.route('/calculation', methods=['POST'])
909
- def handle_calculation():
910
- try:
911
- data = request.get_json()
912
-
913
- # Проверка обязательных полей
914
- if not data or 'fertilizerConstants' not in data or 'profileSettings' not in data:
915
- return jsonify({'error': 'Неверный формат данных'}), 400
916
-
917
- # Инициализация калькулятора
918
- calculator = NutrientCalculator(volume_liters=float(data['profileSettings'].get('liters', 100)))
919
-
920
- # Настройка удобрений из запроса
921
- calculator.fertilizers = {
922
- "Кальциевая селитра": {
923
- "N (NO3-)": float(data['fertilizerConstants']["Кальциевая селитра"].get("N (NO3-)", 0.11863)),
924
- "Ca": float(data['fertilizerConstants']["Кальциевая селитра"].get("Ca", 0.16972))
925
- },
926
- "Калий азотнокислый": {
927
- "N (NO3-)": float(data['fertilizerConstants']["Калий азотнокислый"].get("N (NO3-)", 0.136)),
928
- "K": float(data['fertilizerConstants']["Калий азотнокислый"].get("K", 0.382))
929
- },
930
- "Аммоний азотнокислый": {
931
- "N (NO3-)": float(data['fertilizerConstants']["Аммоний азотнокислый"].get("N (NO3-)", 0.17499)),
932
- "N (NH4+)": float(data['fertilizerConstants']["Аммоний азотнокислый"].get("N (NH4+)", 0.17499))
933
- },
934
- "Сульфат магния": {
935
- "Mg": float(data['fertilizerConstants']["Сульфат магния"].get("Mg", 0.09861)),
936
- "S": float(data['fertilizerConstants']["Сульфат магния"].get("S", 0.13010))
937
- },
938
- "Монофосфат калия": {
939
- "P": float(data['fertilizerConstants']["Монофосфат калия"].get("P", 0.218)),
940
- "K": float(data['fertilizerConstants']["Монофосфат калия"].get("K", 0.275))
941
- },
942
- "Калий сернокислый": {
943
- "K": float(data['fertilizerConstants']["Калий сернокислый"].get("K", 0.44874)),
944
- "S": float(data['fertilizerConstants']["Калий сернокислый"].get("S", 0.18401))
945
  }
946
- }
947
-
948
- # Настройка целевого профиля
949
- calculator.target_profile = {
950
- 'P': float(data['profileSettings'].get('P', 31.0)),
951
- 'K': float(data['profileSettings'].get('K', 210.0)),
952
- 'Mg': float(data['profileSettings'].get('Mg', 24.0)),
953
- 'Ca': float(data['profileSettings'].get('Ca', 84.0)),
954
- 'S': float(data['profileSettings'].get('S', 56.439)),
955
- 'N (NO3-)': 0.0,
956
- 'N (NH4+)': 0.0
957
- }
958
-
959
- # Установка параметров азота
960
- total_n = float(data['profileSettings'].get('TOTAL_NITROGEN', 125.0))
961
- no3_ratio = float(data['profileSettings'].get('NO3_RATIO', 8.25))
962
- nh4_ratio = 1.0
963
 
964
- calculator.target_profile['N (NO3-)'] = total_n * (no3_ratio / (no3_ratio + nh4_ratio))
965
- calculator.target_profile['N (NH4+)'] = total_n * (nh4_ratio / (no3_ratio + nh4_ratio))
 
 
 
 
 
966
 
967
- # Выполнение расчета
968
- results = calculator.calculate()
969
 
970
- # Возвращение результатов в нужном формате
971
- return jsonify({"results": results})
972
 
973
- except Exception as e:
974
- return jsonify({'error': str(e)}), 500
975
 
976
 
977
 
 
766
  NH4_RATIO = 1.00
767
  VOLUME_LITERS = 100
768
 
769
+ # Коэффициенты электропроводности
770
+ EC_COEFFICIENTS = {
771
+ 'P': 0.0012, 'K': 0.0018, 'Mg': 0.0015,
772
+ 'Ca': 0.0016, 'S': 0.0014,
773
+ 'N (NO3-)': 0.0017, 'N (NH4+)': 0.0019
774
+ }
775
+
776
+ # Целевые значения
777
+ BASE_PROFILE = {
778
+ 'P': 31.000, 'K': 210.000, 'Mg': 24.000,
779
+ 'Ca': 84.000, 'S': 56.439,
780
+ 'N (NO3-)': 0, 'N (NH4+)': 0
781
+ }
782
+
783
+ NUTRIENT_CONTENT_IN_FERTILIZERS = {
784
+ "Кальциевая селитра": {"N (NO3-)": 0.11863, "Ca": 0.16972},
785
+ "Калий азотнокислый": {"N (NO3-)": 0.136, "K": 0.382},
786
+ "Калий сернокислый": {"K": 0.44874, "S": 0.18401},
787
+ "Аммоний азотнокислый": {"N (NO3-)": 0.17499, "N (NH4+)": 0.17499},
788
+ "Сульфат магния": {"Mg": 0.09861, "S": 0.13010},
789
+ "Монофосфат калия": {"P": 0.218, "K": 0.275}
790
+ }
791
+
792
+
793
  # Коэффициенты электропроводности
794
  EC_COEFFICIENTS = {
795
  'P': 0.0012, 'K': 0.0018, 'Mg': 0.0015,
 
817
  def __init__(self, volume_liters=1.0):
818
  self.volume = volume_liters
819
  self.results = {}
820
+ self.target_profile = BASE_PROFILE.copy()
821
+ self.actual_profile = {k: 0.0 for k in BASE_PROFILE}
822
+ self.fertilizers = NUTRIENT_CONTENT_IN_FERTILIZERS
823
  self.total_ec = 0.0
824
 
825
+ # Расчёт азота
826
+ total_parts = NO3_RATIO + NH4_RATIO
827
+ self.target_profile['N (NO3-)'] = TOTAL_NITROGEN * (NO3_RATIO / total_parts)
828
+ self.target_profile['N (NH4+)'] = TOTAL_NITROGEN * (NH4_RATIO / total_parts)
829
+ self.initial_n_profile = {
830
+ "NO3-": self.target_profile['N (NO3-)'],
831
+ "NH4+": self.target_profile['N (NH4+)']
832
  }
833
 
834
  def _label(self, element):
835
+ """Форматирование названий элементов для вывода"""
836
  labels = {
837
  'N (NO3-)': 'NO3',
838
  'N (NH4+)': 'NH4'
839
  }
840
  return labels.get(element, element)
841
 
842
+ def calculate(self):
843
+ try:
844
+ self._apply("Сульфат магния", "Mg", self.target_profile['Mg'])
845
+ self._apply("Кальциевая селитра", "Ca", self.target_profile['Ca'])
846
+ self._apply("Монофосфат калия", "P", self.target_profile['P'])
847
+ self._apply("Аммоний азотнокислый", "N (NH4+)", self.target_profile['N (NH4+)'])
848
+
849
+ current_no3 = self.actual_profile['N (NO3-)']
850
+ no3_needed = self.target_profile['N (NO3-)'] - current_no3
851
+
852
+ if no3_needed > 0.1:
853
+ self._apply("Калий азотнокислый", "N (NO3-)", no3_needed)
854
+
855
+ self._apply_k_sulfate()
856
+
857
+ k_deficit = self.target_profile['K'] - self.actual_profile['K']
858
+ if k_deficit > 0.1:
859
+ self._apply("Калий азотнокислый", "K", k_deficit)
860
+
861
+ return self.results
862
+ except Exception as e:
863
+ print(f"Ошибка при расчёте: {str(e)}")
864
+ raise
865
+
866
  def _apply(self, fert_name, main_element, required_ppm):
867
  if required_ppm <= 0:
868
  return
869
+
870
  try:
871
+ content = self.fertilizers[fert_name][main_element]
 
 
 
872
  grams = (required_ppm * self.volume) / (content * 1000)
873
+
874
  if fert_name not in self.results:
875
  result = {
876
  'граммы': 0.0,
 
880
  for element in self.fertilizers[fert_name]:
881
  result[f'внесет {self._label(element)}'] = 0.0
882
  self.results[fert_name] = result
883
+
884
  self.results[fert_name]['граммы'] += grams
885
+ self.results[fert_name]['миллиграммы'] += int(grams * 1000)
886
+
887
  fert_ec = 0.0
888
  for element, percent in self.fertilizers[fert_name].items():
889
  added_ppm = (grams * percent * 1000) / self.volume
890
  self.results[fert_name][f'внесет {self._label(element)}'] += added_ppm
891
+ self.actual_profile[element] += added_ppm
892
+ fert_ec += added_ppm * EC_COEFFICIENTS.get(element, 0.0015)
893
+
894
  self.results[fert_name]['вклад в EC'] += fert_ec
895
  self.total_ec += fert_ec
896
  except KeyError as e:
897
+ print(f"Ошибка: отсутствует элемент {str(e)} в удобрении {fert_name}")
898
  raise
899
 
900
+ def _apply_k_sulfate(self):
901
+ fert = "Калий сернокислый"
902
+ k_def = self.target_profile['K'] - self.actual_profile['K']
903
+ s_def = self.target_profile['S'] - self.actual_profile['S']
904
+
905
+ if k_def <= 0 and s_def <= 0:
906
  return
907
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
908
  try:
909
+ if s_def > 0.1:
910
+ s_content = self.fertilizers[fert]["S"]
911
+ grams_s = (s_def * self.volume) / (s_content * 1000)
912
+
913
+ k_content = self.fertilizers[fert]["K"]
914
+ k_from_s = (grams_s * k_content * 1000) / self.volume
915
+
916
+ if k_from_s > k_def and k_def > 0.1:
917
+ grams = (k_def * self.volume) / (k_content * 1000)
918
+ else:
919
+ grams = grams_s
920
+
921
+ self._apply(fert, "S", s_def)
 
 
 
 
 
 
 
 
 
922
  except Exception as e:
923
+ print(f"Ошибка при расчёте сульфата калия: {str(e)}")
924
  raise
925
 
926
+ def calculate_ec(self):
927
+ return round(self.total_ec, 2)
928
 
929
+ def print_report(self):
930
+ try:
931
+ print("\n" + "="*60)
932
+ print("ПРОФИЛЬ ПИТАТЕЛЬНОГО РАСТВОРА (ИТОГО):")
933
+ print("="*60)
934
+ table = [[el, round(self.actual_profile[el], 1)] for el in self.actual_profile]
935
+ print(tabulate(table, headers=["Элемент", "ppm"]))
936
+
937
+ print("\nИсходный расчёт азота:")
938
+ for form, val in self.initial_n_profile.items():
939
+ print(f" {form}: {round(val, 1)} ppm")
940
+
941
+ print("\n" + "="*60)
942
+ print(f"РАСЧЕТ ДЛЯ {self.volume} ЛИТРОВ РАСТВОРА")
943
+ print("="*60)
944
+ print(f"Общая концентрация: {round(sum(self.actual_profile.values()), 1)} ppm")
945
+ print(f"EC: {self.calculate_ec()} mS/cm")
946
+
947
+ print("\nРЕКОМЕНДУЕМЫЕ УДОБРЕНИЯ:")
948
+ fert_table = []
949
+ for fert, data in self.results.items():
950
+ adds = [f"+{k}: {v:.1f} ppm" for k, v in data.items() if k.startswith('внесет')]
951
+ fert_table.append([
952
+ fert,
953
+ round(data['граммы'], 3),
954
+ data['миллиграммы'],
955
+ round(data['вклад в EC'], 3),
956
+ "\n".join(adds)
957
+ ])
958
+ print(tabulate(fert_table,
959
+ headers=["Удобрение", "Граммы", "Миллиграммы", "EC (мСм/см)", "Добавит"]))
960
+
961
+ print("\nОСТАТОЧНЫЙ ДЕФИЦИТ:")
962
+ deficit = {
963
+ k: round(self.target_profile[k] - self.actual_profile[k], 1)
964
+ for k in self.target_profile
965
+ if abs(self.target_profile[k] - self.actual_profile[k]) > 0.1
 
966
  }
967
+ if deficit:
968
+ for el, val in deficit.items():
969
+ print(f" {el}: {val} ppm")
970
+ else:
971
+ print(" Все элементы покрыты полностью")
972
+ except Exception as e:
973
+ print(f"Ошибка при выводе отчёта: {str(e)}")
974
+ raise
 
 
 
 
 
 
 
 
 
975
 
976
+ if __name__ == "__main__":
977
+ try:
978
+ calculator = NutrientCalculator(volume_liters=VOLUME_LITERS)
979
+ calculator.calculate()
980
+ calculator.print_report() # Правильный вызов метода класса
981
+ except Exception as e:
982
+ print(f"Критическая ошибка: {str(e)}")
983
 
 
 
984
 
 
 
985
 
 
 
986
 
987
 
988