DmitrMakeev commited on
Commit
be13947
·
verified ·
1 Parent(s): a151a19

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +149 -209
app.py CHANGED
@@ -693,237 +693,177 @@ def nutri_call():
693
 
694
 
695
 
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 = {
760
- 'N (NO3-)': 'NO3',
761
- 'N (NH4+)': 'NH4'
762
- }
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,
847
- 'миллиграммы': 0,
848
- 'вклад в EC': 0.0
849
- }
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("ПРОФИЛЬ ПИТАТЕЛЬНОГО РАСТВОРА (ИТОГО):")
879
- print("="*60)
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)
886
- print(f"Общая концентрация: {round(sum(self.actual_profile.values()), 1)} ppm")
887
- print(f"EC: {self.calculate_ec()} mS/cm")
888
-
889
- print("\nРЕКОМЕНДУЕМЫЕ УДОБРЕНИЯ:")
890
- fert_table = []
891
- for fert, data in self.results.items():
892
- adds = [f"+{k}: {v:.1f} ppm" for k, v in data.items() if k.startswith('внесет')]
893
- fert_table.append([
894
- fert,
895
- round(data['граммы'], 3),
896
- data['миллиграммы'],
897
- round(data['вклад в EC'], 3),
898
- "\n".join(adds)
899
- ])
900
- print(tabulate(fert_table,
901
- headers=["Удобрение", "Граммы", "Миллиграммы", "EC (мСм/см)", "Добавит"]))
902
-
903
  print("\nОСТАТОЧНЫЙ ДЕФИЦИТ:")
904
- deficit = {
905
- k: round(self.target_profile[k] - self.actual_profile[k], 1)
906
- for k in self.target_profile
907
- if abs(self.target_profile[k] - self.actual_profile[k]) > 0.1
908
- }
909
- if deficit:
910
- for el, val in deficit.items():
911
- print(f" {el}: {val} ppm")
912
- else:
913
- print(" Все элементы покрыты полностью")
914
- except Exception as e:
915
- print(f"Ошибка при выводе отчёта: {str(e)}")
916
- raise
917
-
918
 
 
919
  if __name__ == "__main__":
920
- try:
921
- calculator = NutrientCalculator(volume_liters=VOLUME_LITERS)
922
- calculator.calculate()
923
- calculator.print_report() # Правильный вызов метода класса
924
- except Exception as e:
925
- print(f"Критическая ошибка: {str(e)}")
926
-
927
 
928
 
929
 
 
693
 
694
 
695
 
 
696
  from tabulate import tabulate
697
+ import numpy as np
698
 
699
+ # Глобальные параметры
700
+ TOTAL_NITROGEN = 120.0
701
+ NO3_RATIO = 8.0
702
+ NH4_RATIO = 1.0
703
  VOLUME_LITERS = 100
704
 
705
+ # Базовый профиль
 
 
 
 
 
 
 
706
  BASE_PROFILE = {
707
+ "P": 50, "K": 210, "Mg": 120,
708
+ "Ca": 150, "S": 50,
709
+ "N (NO3-)": 0, "N (NH4+)": 0
710
  }
711
 
712
+ # Состав удобрений (в долях)
713
+ NUTRIENT_CONTENT = {
714
  "Кальциевая селитра": {"N (NO3-)": 0.11863, "Ca": 0.16972},
715
  "Калий азотнокислый": {"N (NO3-)": 0.136, "K": 0.382},
716
+ "Калий сернокислый": {"K": 0.44874, "S": 0.18401},
717
  "Аммоний азотнокислый": {"N (NO3-)": 0.17499, "N (NH4+)": 0.17499},
718
  "Сульфат магния": {"Mg": 0.09861, "S": 0.13010},
719
  "Монофосфат калия": {"P": 0.218, "K": 0.275},
720
+ "Сульфат кальция": {"Ca": 0.23, "S": 0.186}
721
+ }
722
+
723
+ # Коэффициенты EC
724
+ EC_COEFF = {
725
+ 'P': 0.0012, 'K': 0.0018, 'Mg': 0.0015,
726
+ 'Ca': 0.0016, 'S': 0.0014,
727
+ 'N (NO3-)': 0.0017, 'N (NH4+)': 0.0019
728
  }
729
 
730
  class NutrientCalculator:
731
+ def __init__(self, volume=1.0):
732
+ self.volume = volume
733
+ self.target = BASE_PROFILE.copy()
734
+ self._init_nitrogen()
735
  self.results = {}
736
+ self.actual = {k: 0.0 for k in self.target}
 
 
737
  self.total_ec = 0.0
738
+
739
+ def _init_nitrogen(self):
740
+ total = NO3_RATIO + NH4_RATIO
741
+ self.target['N (NO3-)'] = TOTAL_NITROGEN * (NO3_RATIO / total)
742
+ self.target['N (NH4+)'] = TOTAL_NITROGEN * (NH4_RATIO / total)
743
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
744
  def calculate(self):
745
+ # 1. Вносим кальций (приоритет Ca(NO3)2)
746
+ ca_needed = self.target['Ca'] - self.actual['Ca']
747
+ if ca_needed > 0:
748
+ self._apply_fert("Кальциевая селитра", "Ca", ca_needed)
749
+
750
+ # 2. Вносим NH4
751
+ nh4_needed = self.target['N (NH4+)'] - self.actual['N (NH4+)']
752
+ if nh4_needed > 0:
753
+ self._apply_fert("Аммоний азотнокислый", "N (NH4+)", nh4_needed)
754
+
755
+ # 3. Компенсируем NO3
756
+ no3_needed = self.target['N (NO3-)'] - self.actual['N (NO3-)']
757
+ if no3_needed > 0:
758
+ self._apply_fert("Калий азотнокислый", "N (NO3-)", no3_needed)
759
+
760
+ # 4. Вносим фосфор
761
+ p_needed = self.target['P'] - self.actual['P']
762
+ if p_needed > 0:
763
+ self._apply_fert("Монофосфат калия", "P", p_needed)
764
+
765
+ # 5. Компенсируем магний
766
+ mg_needed = self.target['Mg'] - self.actual['Mg']
767
+ if mg_needed > 0:
768
+ self._apply_fert("Сульфат магния", "Mg", mg_needed)
769
+
770
+ # 6. Корректируем калий и серу
771
+ self._balance_k_s()
772
+
773
+ return self._prepare_results()
774
+
775
+ def _apply_fert(self, name, element, needed_ppm):
776
+ content = NUTRIENT_CONTENT[name][element]
777
+ grams = (needed_ppm * self.volume) / (content * 1000)
778
+
779
+ if name not in self.results:
780
+ self.results[name] = {'граммы': 0, 'вклад': {}}
781
+
782
+ self.results[name]['граммы'] += grams
783
+
784
+ for el, val in NUTRIENT_CONTENT[name].items():
785
+ added = grams * val * 1000 / self.volume
786
+ self.actual[el] += added
787
+ self.total_ec += added * EC_COEFF.get(el, 0)
788
+
789
+ if el not in self.results[name]['вклад']:
790
+ self.results[name]['вклад'][el] = 0
791
+ self.results[name]['вклад'][el] += added
792
+
793
+ def _balance_k_s(self):
794
+ k_deficit = self.target['K'] - self.actual['K']
795
+ s_deficit = self.target['S'] - self.actual['S']
796
+
797
+ # Выбираем удобрение в зависимости от дефицита
798
+ if k_deficit > 0 and s_deficit > 0:
799
+ # Используем K2SO4 для одновременного восполнения
800
+ self._apply_fert("Калий сернокислый", "K", min(k_deficit, s_deficit*0.44874/0.18401))
801
+ elif k_deficit > 0:
802
+ self._apply_fert("Калий азотнокислый", "K", k_deficit)
803
+
804
+ def _prepare_results(self):
805
+ # Расчет дефицитов
806
+ deficits = {k: self.target[k] - self.actual[k]
807
+ for k in self.target if abs(self.target[k] - self.actual[k]) > 0.1}
808
+
809
+ return {
810
+ "actual_profile": self.actual,
811
+ "fertilizers": self._format_fertilizers(),
812
+ "total_ec": round(self.total_ec, 2),
813
+ "total_ppm": round(sum(self.actual.values()), 2),
814
+ "deficits": deficits
815
+ }
816
+
817
+ def _format_fertilizers(self):
818
+ formatted = {}
819
+ for name, data in self.results.items():
820
+ formatted[name] = {
821
+ 'граммы': round(data['граммы'], 3),
822
+ 'миллиграммы': int(data['граммы'] * 1000),
823
+ 'вклад в EC': round(sum(v * EC_COEFF.get(k, 0)
824
+ for k, v in data['вклад'].items()), 3),
825
+ 'добавит': [f"{k}: {round(v, 1)} ppm" for k, v in data['вклад'].items()]
826
+ }
827
+ return formatted
828
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
829
  def print_report(self):
830
+ print("\n" + "="*60)
831
+ print("ПРОФИЛЬ ПИТАТЕЛЬНОГО РАСТВОРА (ИТОГО):")
832
+ print("="*60)
833
+ print(tabulate([[k, round(v, 1)] for k, v in self.actual.items()],
834
+ headers=["Элемент", "ppm"]))
835
+
836
+ print("\n" + "="*60)
837
+ print(f"РАСЧЕТ ДЛЯ {self.volume} ЛИТРОВ")
838
+ print("="*60)
839
+ print(f"Общая концентрация: {round(sum(self.actual.values()), 1)} ppm")
840
+ print(f"EC: {round(self.total_ec, 2)} mS/cm")
841
+
842
+ print("\nРЕКОМЕНДУЕМЫЕ УДОБРЕНИЯ:")
843
+ fert_table = []
844
+ for name, data in self._format_fertilizers().items():
845
+ fert_table.append([
846
+ name,
847
+ data['граммы'],
848
+ data['миллиграммы'],
849
+ data['вклад в EC'],
850
+ "\n".join(data['добавит'])
851
+ ])
852
+ print(tabulate(fert_table,
853
+ headers=["Удобрение", "Граммы", "Миллиграммы", "EC", "Добавит"]))
854
+
855
+ if self._prepare_results()['deficits']:
 
 
856
  print("\nОСТАТОЧНЫЙ ДЕФИЦИТ:")
857
+ for el, val in self._prepare_results()['deficits'].items():
858
+ print(f" {el}: {round(val, 1)} ppm")
859
+ else:
860
+ print("\nВсе элементы покрыты полностью")
 
 
 
 
 
 
 
 
 
 
861
 
862
+ # Пример использования
863
  if __name__ == "__main__":
864
+ calc = NutrientCalculator(VOLUME_LITERS)
865
+ results = calc.calculate()
866
+ calc.print_report()
 
 
 
 
867
 
868
 
869