DmitrMakeev commited on
Commit
d5d255b
·
verified ·
1 Parent(s): 443e57e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +43 -140
app.py CHANGED
@@ -793,25 +793,16 @@ class NutrientCalculator:
793
  def __init__(self, volume_liters=1.0):
794
  self.volume = volume_liters
795
  self.results = {}
796
- self.target_profile = BASE_PROFILE.copy()
797
- self.actual_profile = {k: 0.0 for k in BASE_PROFILE}
798
- self.fertilizers = NUTRIENT_CONTENT_IN_FERTILIZERS
799
  self.total_ec = 0.0
800
 
801
  # Инициализация весов компенсации
802
  self.compensation_weights = {
803
- "Калий азотнокислый": {"weight": 0.5, "main_elements": ["K", "N (NO3-)"]},
804
- "Кальциевая селитра": {"weight": 0.3, "main_elements": ["Ca", "N (NO3-)"]},
805
- "Калий сернокислый": {"weight": 0.2, "main_elements": ["K", "S"]}
806
- }
807
-
808
- # Расчёт азота
809
- total_parts = NO3_RATIO + NH4_RATIO
810
- self.target_profile['N (NO3-)'] = TOTAL_NITROGEN * (NO3_RATIO / total_parts)
811
- self.target_profile['N (NH4+)'] = TOTAL_NITROGEN * (NH4_RATIO / total_parts)
812
- self.initial_n_profile = {
813
- "NO3-": self.target_profile['N (NO3-)'],
814
- "NH4+": self.target_profile['N (NH4+)']
815
  }
816
 
817
  def _label(self, element):
@@ -831,7 +822,7 @@ class NutrientCalculator:
831
  raise KeyError(f"Элемент {main_element} отсутствует в удобрении {fert_name}")
832
 
833
  grams = (required_ppm * self.volume) / (content * 1000)
834
-
835
  if fert_name not in self.results:
836
  result = {
837
  'граммы': 0.0,
@@ -841,17 +832,17 @@ class NutrientCalculator:
841
  for element in self.fertilizers[fert_name]:
842
  result[f'внесет {self._label(element)}'] = 0.0
843
  self.results[fert_name] = result
844
-
845
  self.results[fert_name]['граммы'] += grams
846
  self.results[fert_name]['миллиграммы'] = int(grams * 1000)
847
-
848
  fert_ec = 0.0
849
  for element, percent in self.fertilizers[fert_name].items():
850
  added_ppm = (grams * percent * 1000) / self.volume
851
  self.results[fert_name][f'внесет {self._label(element)}'] += added_ppm
852
- self.actual_profile[element] += added_ppm
853
- fert_ec += added_ppm * EC_COEFFICIENTS.get(element, 0.0015)
854
-
855
  self.results[fert_name]['вклад в EC'] += fert_ec
856
  self.total_ec += fert_ec
857
  except KeyError as e:
@@ -859,30 +850,26 @@ class NutrientCalculator:
859
  raise
860
 
861
  def _compensate_element(self, element):
862
- """Улучшенная компенсация с приоритетами"""
863
- needed = self.target_profile[element] - self.actual_profile[element]
864
  if needed <= 0:
865
  return
866
 
867
- # Находим все удобрения, содержащие нужный элемент
868
  candidates = []
869
- for fert_name, fert_data in self.fertilizers.items():
870
- if element in fert_data:
871
- weight = self.compensation_weights.get(fert_name, {}).get("weight", 0.1)
 
 
872
  candidates.append({
873
  'name': fert_name,
874
- 'weight': weight,
875
- 'content': fert_data[element]
876
  })
877
 
878
  if not candidates:
879
  raise ValueError(f"Нет удобрений для элемента {element}")
880
 
881
- # Сортируем по весу (убывание)
882
- candidates.sort(key=lambda x: x['weight'], reverse=True)
883
  total_weight = sum(c['weight'] for c in candidates)
884
-
885
- # Вносим пропорционально весам
886
  for candidate in candidates:
887
  share = candidate['weight'] / total_weight
888
  ppm_to_apply = needed * share
@@ -890,130 +877,46 @@ class NutrientCalculator:
890
 
891
  def calculate(self):
892
  try:
893
- # 1. Вносим магний
894
  self._apply("Сульфат магния", "Mg", self.target_profile['Mg'])
895
-
896
- # 2. Вносим кальций через компенсацию
897
  self._compensate_element("Ca")
898
-
899
- # 3. Вносим фосфор
900
  self._apply("Монофосфат калия", "P", self.target_profile['P'])
901
-
902
- # 4. Вносим аммонийный азот
903
  self._apply("Аммоний азотнокислый", "N (NH4+)", self.target_profile['N (NH4+)'])
904
-
905
- # 5. Компенсируем нитратный азот
906
  self._compensate_element("N (NO3-)")
907
-
908
- # 6. Компенсируем серу
909
  self._compensate_element("S")
910
-
911
- # 7. Компенсируем калий
912
  self._compensate_element("K")
913
-
914
  return self.results
915
  except Exception as e:
916
  print(f"Ошибка при расчёте: {str(e)}")
917
  raise
918
 
919
- def calculate_ec(self):
920
- return round(self.total_ec, 2)
921
-
922
- def print_report(self):
923
- try:
924
- print("\n" + "="*60)
925
- print("ПРОФИЛЬ ПИТАТЕЛЬНОГО РАСТВОРА (ИТОГО):")
926
- print("="*60)
927
- table = [[el, round(self.actual_profile[el], 1)] for el in self.actual_profile]
928
- print(tabulate(table, headers=["Элемент", "ppm"]))
929
-
930
- print("\nИсходный расчёт азота:")
931
- for form, val in self.initial_n_profile.items():
932
- print(f" {form}: {round(val, 1)} ppm")
933
-
934
- print("\n" + "="*60)
935
- print(f"РАСЧЕТ ДЛЯ {self.volume} ЛИТРОВ РАСТВОРА")
936
- print("="*60)
937
- print(f"Общая концентрация: {round(sum(self.actual_profile.values()), 1)} ppm")
938
- print(f"EC: {self.calculate_ec()} mS/cm")
939
-
940
- print("\nРЕКОМЕНДУЕМЫЕ УДОБРЕНИЯ:")
941
- fert_table = []
942
- for fert, data in self.results.items():
943
- adds = [f"+{k}: {v:.1f} ppm" for k, v in data.items() if k.startswith('внесет')]
944
- fert_table.append([
945
- fert,
946
- round(data['граммы'], 3),
947
- data['миллиграммы'],
948
- round(data['вклад в EC'], 3),
949
- "\n".join(adds)
950
- ])
951
- print(tabulate(fert_table,
952
- headers=["Удобрение", "Граммы", "Миллиграммы", "EC (мСм/см)", "Добавит"]))
953
-
954
- print("\nОСТАТОЧНЫЙ ДЕФИЦИТ:")
955
- deficit = {
956
- k: round(self.target_profile[k] - self.actual_profile[k], 1)
957
- for k in self.target_profile
958
- if abs(self.target_profile[k] - self.actual_profile[k]) > 0.1
959
- }
960
- if deficit:
961
- for el, val in deficit.items():
962
- print(f" {el}: {val} ppm")
963
- else:
964
- print(" Все элементы покрыты полностью")
965
- except Exception as e:
966
- print(f"Ошибка при выводе отчёта: {str(e)}")
967
- raise
968
-
969
- if __name__ == "__main__":
970
- # Константы (замените на свои значения)
971
- TOTAL_NITROGEN = 125.0
972
- NO3_RATIO = 8.25
973
- NH4_RATIO = 1.0
974
- VOLUME_LITERS = 100
975
-
976
- # Убедитесь, что эти словари определены
977
- BASE_PROFILE = {
978
- 'P': 31.0, 'K': 210.0, 'Mg': 24.0,
979
- 'Ca': 84.0, 'S': 56.439,
980
- 'N (NO3-)': 0.0, 'N (NH4+)': 0.0
981
- }
982
-
983
- NUTRIENT_CONTENT_IN_FERTILIZERS = {
984
- "Кальциевая селитра": {"N (NO3-)": 0.11863, "Ca": 0.16972},
985
- "Калий азотнокислый": {"N (NO3-)": 0.136, "K": 0.382},
986
- "Калий сернокислый": {"K": 0.44874, "S": 0.18401},
987
- "Аммоний азотнокислый": {"N (NO3-)": 0.17499, "N (NH4+)": 0.17499},
988
- "Сульфат магния": {"Mg": 0.09861, "S": 0.13010},
989
- "Монофосфат калия": {"P": 0.218, "K": 0.275}
990
- }
991
-
992
- EC_COEFFICIENTS = {
993
- 'P': 0.0012, 'K': 0.0018, 'Mg': 0.0015,
994
- 'Ca': 0.0016, 'S': 0.0014,
995
- 'N (NO3-)': 0.0017, 'N (NH4+)': 0.0019
996
- }
997
-
998
- try:
999
- calculator = NutrientCalculator(volume_liters=VOLUME_LITERS)
1000
- calculator.calculate()
1001
- calculator.print_report()
1002
- except Exception as e:
1003
- print(f"Критическая ошибка: {str(e)}")
1004
 
 
1005
  @app.route('/calculation', methods=['POST'])
1006
  def handle_calculation():
1007
  try:
1008
  data = request.get_json()
1009
-
1010
  # Проверка обязательных полей
1011
  if not data or 'fertilizerConstants' not in data or 'profileSettings' not in data:
1012
  return jsonify({'error': 'Неверный формат данных'}), 400
1013
-
1014
  # Инициализация калькулятора
1015
  calculator = NutrientCalculator(volume_liters=float(data['profileSettings'].get('liters', 100)))
1016
-
1017
  # Настройка удобрений из запроса
1018
  calculator.fertilizers = {
1019
  "Кальциевая селитра": {
@@ -1041,7 +944,7 @@ def handle_calculation():
1041
  "S": float(data['fertilizerConstants']["Калий сернокислый"].get("S", 0.18401))
1042
  }
1043
  }
1044
-
1045
  # Настройка целевого профиля
1046
  calculator.target_profile = {
1047
  'P': float(data['profileSettings'].get('P', 31.0)),
@@ -1052,19 +955,19 @@ def handle_calculation():
1052
  'N (NO3-)': 0.0,
1053
  'N (NH4+)': 0.0
1054
  }
1055
-
1056
  # Установка параметров азота
1057
  total_n = float(data['profileSettings'].get('TOTAL_NITROGEN', 125.0))
1058
  no3_ratio = float(data['profileSettings'].get('NO3_RATIO', 8.25))
1059
  nh4_ratio = 1.0
1060
-
1061
  calculator.target_profile['N (NO3-)'] = total_n * (no3_ratio / (no3_ratio + nh4_ratio))
1062
  calculator.target_profile['N (NH4+)'] = total_n * (nh4_ratio / (no3_ratio + nh4_ratio))
1063
-
1064
  # Выполнение расчета
1065
  results = calculator.calculate()
1066
  return jsonify(results)
1067
-
1068
  except Exception as e:
1069
  return jsonify({'error': str(e)}), 500
1070
 
 
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):
 
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
  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:
 
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
 
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
  "Кальциевая селитра": {
 
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)),
 
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
  return jsonify(results)
970
+
971
  except Exception as e:
972
  return jsonify({'error': str(e)}), 500
973