DmitrMakeev commited on
Commit
426c9a2
·
verified ·
1 Parent(s): 9eede58

Update app.py

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