Возникло исключение: AttributeError
'HeatTransfer' object has no attribute 'thermal_conductivity'
  File "C:\Users\Admin\Desktop\mhpeps_simulation\control_interface.py", line 239, in <dictcomp>
    self.thermal_vars = {key: tk.DoubleVar(value=getattr(self.heat_transfer, fields[key][0]))
                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Admin\Desktop\mhpeps_simulation\control_interface.py", line 239, in create_thermal_tab
    self.thermal_vars = {key: tk.DoubleVar(value=getattr(self.heat_transfer, fields[key][0]))
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Admin\Desktop\mhpeps_simulation\control_interface.py", line 140, in create_tabs
    tab_func(tab)
  File "C:\Users\Admin\Desktop\mhpeps_simulation\control_interface.py", line 62, in __init__
    self.create_tabs()
  File "C:\Users\Admin\Desktop\mhpeps_simulation\control_interface.py", line 755, in <module>
    interface = RocketControlInterface(root)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'HeatTransfer' object has no attribute 'thermal_conductivity'
[{
	"resource": "/c:/Users/Admin/Desktop/mhpeps_simulation/control_interface.py",
	"owner": "python",
	"code": {
		"value": "reportUndefinedVariable",
		"target": {
			"$mid": 1,
			"path": "/microsoft/pyright/blob/main/docs/configuration.md",
			"scheme": "https",
			"authority": "github.com",
			"fragment": "reportUndefinedVariable"
		}
	},
	"severity": 4,
	"message": "\"parent_naming\" не определено",
	"source": "Pylance",
	"startLineNumber": 682,
	"startColumn": 26,
	"endLineNumber": 682,
	"endColumn": 39
}]
```python
# control_interface.py

import tkinter as tk
from tkinter import ttk, messagebox
import threading
import time

# Импортируем необходимые классы из проекта
from propulsion.plasma_propulsion import PlasmaThruster
from power_system.solar_power import SolarPanel
from power_system.energy_management import EnergyManager
from control_system.pid_controller import PIDController
from thermal_management.heat_transfer import HeatTransfer
from structural_analysis.stress_analysis import StressAnalysis
from utils.constants import G0, STEFAN_BOLTZMANN


class ToolTip:
    """Создает всплывающую подсказку для данного виджета."""
    def __init__(self, widget, text='widget info'):
        self.widget = widget
        self.text = text
        self.tipwindow = None
        widget.bind("<Enter>", self.show_tip)
        widget.bind("<Leave>", self.hide_tip)

    def show_tip(self, event=None):
        if self.tipwindow or not self.text:
            return
        x, y, _, _ = self.widget.bbox("insert")
        x += self.widget.winfo_rootx() + 25
        y += self.widget.winfo_rooty() + 20
        self.tipwindow = tw = tk.Toplevel(self.widget)
        tw.wm_overrideredirect(True)
        tw.wm_geometry(f"+{x}+{y}")
        label = tk.Label(tw, text=self.text, justify='left',
                         background="#ffffe0", relief='solid', borderwidth=1,
                         font=("tahoma", "8", "normal"))
        label.pack(ipadx=1)

    def hide_tip(self, event=None):
        if self.tipwindow:
            self.tipwindow.destroy()
        self.tipwindow = None


class RocketControlInterface:
    def __init__(self, master):
        self.master = master
        master.title("Расширенное Управление Ракетой MHPEPS")

        # Создаем основную структуру интерфейса с использованием фреймов
        self.left_frame = ttk.Frame(master)
        self.left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.right_frame = ttk.Frame(master)
        self.right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)

        # Инициализация систем
        self.initialize_systems()

        # Создание вкладок интерфейса внутри левого фрейма
        self.create_tabs()

        # Визуализация ракеты
        self.create_rocket_visual()

        # Лог для отображения событий
        self.create_log_panel()

        # Инициализация флагов для предупреждений
        self.warning_flags = {key: False for key in [
            'low_power_thruster', 'high_power_thruster', 'high_mass_flow',
            'high_delta_T', 'high_stress', 'high_setpoint'
        ]}

        # Запуск симуляции
        self.running = True
        self.simulation_thread = threading.Thread(target=self.run_simulation, daemon=True)
        self.simulation_thread.start()

        # Обработка закрытия окна
        master.protocol("WM_DELETE_WINDOW", self.on_close)

    def initialize_systems(self):
        """Инициализация всех модулей системы."""
        self.solar_panel = SolarPanel(area=1.0, efficiency=0.3)
        self.power_output = self.solar_panel.calculate_power_output()

        self.energy_manager = EnergyManager(power_sources=[self.power_output])
        self.demands = [6000, 2000]  # Вт: [двигатель, вспомогательные системы]
        self.allocate_energy_initial()

        ion_mass = 2.18e-25  # кг
        self.thruster = PlasmaThruster(accelerating_voltage=1000, ion_mass=ion_mass)
        self.thruster.set_power(self.allocated_power_thruster)
        self.thrust = self.thruster.get_thrust()
        self.si = self.thruster.get_specific_impulse()

        self.pid = PIDController(Kp=10.0, Ki=1.0, Kd=0.5, setpoint=self.thrust)

        cross_section_area = 0.01  # м²
        young_modulus = 2e11       # Па
        yield_strength = 3e8       # Па
        self.stress_analysis = StressAnalysis(
            force=self.thrust, area=cross_section_area,
            young_modulus=young_modulus, yield_strength=yield_strength
        )

        self.heat_transfer = HeatTransfer(
            thermal_conductivity=400, area=2.0, thickness=0.1, temperature_diff=500
        )
        self.conductive_heat = self.heat_transfer.conductive_heat_transfer()
        self.radiative_heat = self.heat_transfer.radiative_heat_transfer(
            emissivity=0.8, T_hot=1000, T_cold=300
        )

    def allocate_energy_initial(self):
        """Первоначальное распределение энергии между системами."""
        allocated = self.energy_manager.allocate_power(self.demands)
        self.allocated_power_thruster, self.allocated_power_aux = allocated

    def create_tabs(self):
        """Создание вкладок внутри левого фрейма."""
        self.tab_control = ttk.Notebook(self.left_frame)
        self.tab_control.pack(expand=1, fill="both")

        tabs = {
            'Солнечная Панель': self.create_solar_tab,
            'Управление Энергией': self.create_energy_tab,
            'Плазменный Двигатель': self.create_thruster_tab,
            'Теплопередача': self.create_thermal_tab,
            'Анализ Напряжений': self.create_structural_tab,
            'PID Контроллер': self.create_pid_tab
        }

        for tab_name, tab_func in tabs.items():
            tab = ttk.Frame(self.tab_control)
            self.tab_control.add(tab, text=tab_name)
            setattr(self, f"tab_{tab_name.replace(' ', '_').lower()}", tab)
            tab_func(tab)

    def create_widgets(self, parent, fields, button_text, button_command, start_row=0):
        """Универсальный метод для создания набора Label, Entry и Button."""
        variables = {}
        for idx, (label, var) in enumerate(fields.items(), start=start_row):
            ttk.Label(parent, text=label).grid(row=idx, column=0, padx=5, pady=5, sticky="w")
            entry = ttk.Entry(parent, textvariable=var)
            entry.grid(row=idx, column=1, padx=5, pady=5, sticky="ew")
            ToolTip(entry, fields[label][1])
            variables[label] = entry
        button = ttk.Button(parent, text=button_text, command=button_command)
        button.grid(row=idx + 1, column=0, columnspan=2, pady=10)
        ToolTip(button, "Нажмите, чтобы применить изменения.")
        parent.columnconfigure(1, weight=1)
        return variables

    def create_solar_tab(self, parent):
        """Создание вкладки для управления солнечной панелью."""
        fields = {
            "Площадь панели (м²):": ("area", "Укажите площадь солнечной панели в квадратных метрах."),
            "КПД панели:": ("efficiency", "КПД солнечной панели (например, 0.3 для 30%). Максимальное значение 1.0."),
            "Инсоляция (Вт/м²):": ("irradiance", "Солнечная инсоляция в ваттах на квадратный метр (Вт/м²). Обычно около 1361 Вт/м².")
        }
        self.solar_vars = {key: tk.DoubleVar(value=getattr(self.solar_panel, fields[key][0]))
                           for key in fields}
        self.create_widgets(
            parent, fields,
            "Обновить Параметры",
            self.update_solar_parameters
        )

        # Выходная мощность
        ttk.Label(parent, text="Выходная мощность (Вт):").grid(row=len(fields) + 1, column=0, padx=5, pady=5, sticky="w")
        self.power_output_label = ttk.Label(parent, text=f"{self.power_output:.2f} Вт")
        self.power_output_label.grid(row=len(fields) + 1, column=1, padx=5, pady=5, sticky="w")
        ToolTip(self.power_output_label, "Текущая выходная мощность солнечной панели на основе заданных параметров.")

    def create_energy_tab(self, parent):
        """Создание вкладки для управления энергопотреблением."""
        fields = {
            "Двигатель (Вт):": ("energy_demand_thruster", "Требуемая мощность для основного двигателя (Вт)."),
            "Вспомогательные системы (Вт):": ("energy_demand_aux", "Требуемая мощность для вспомогательных систем (Вт).")
        }
        self.energy_vars = {key: tk.DoubleVar(value=self.demands[idx])
                            for idx, key in enumerate(fields)}
        self.create_widgets(
            parent, fields,
            "Распределить Энергию",
            self.allocate_energy,
            start_row=0
        )

        # Распределенная мощность
        ttk.Label(parent, text="Распределенная мощность (Вт):").grid(row=len(fields) + 1, column=0, padx=5, pady=5, sticky="w")
        ttk.Label(parent, text="Двигатель:").grid(row=len(fields) + 2, column=0, padx=5, pady=5, sticky="w")
        self.allocated_thruster_label = ttk.Label(parent, text=f"{self.allocated_power_thruster:.2f} Вт")
        self.allocated_thruster_label.grid(row=len(fields) + 2, column=1, padx=5, pady=5, sticky="w")
        ToolTip(self.allocated_thruster_label, "Мощность, выделенная для основного двигателя.")

        ttk.Label(parent, text="Вспомогательные системы:").grid(row=len(fields) + 3, column=0, padx=5, pady=5, sticky="w")
        self.allocated_aux_label = ttk.Label(parent, text=f"{self.allocated_power_aux:.2f} Вт")
        self.allocated_aux_label.grid(row=len(fields) + 3, column=1, padx=5, pady=5, sticky="w")
        ToolTip(self.allocated_aux_label, "Мощность, выделенная для вспомогательных систем.")

    def create_thruster_tab(self, parent):
        """Создание вкладки для управления плазменным двигателем."""
        fields = {
            "Напряжение ускорения (В):": ("accelerating_voltage", "Напряжение ускорения ионов в плазменном двигателе (В)."),
            "Массовый расход (кг/с):": ("mass_flow_rate", "Текущий массовый расход плазменного двигателя (кг/с). Изменяется автоматически.")
        }
        self.thruster_vars = {
            key: tk.DoubleVar(value=getattr(self.thruster, fields[key][0]))
            for key in fields
        }
        entries = self.create_widgets(
            parent, fields,
            "Обновить Параметры",
            self.update_thruster_parameters
        )
        entries["Массовый расход (кг/с):"].config(state='readonly')

        # Тяга и удельный импульс
        info_fields = {
            "Тяга двигателя (Н):": f"{self.thrust:.4f} Н",
            "Удельный импульс (с):": f"{self.si:.2f} с"
        }
        for idx, (label, value) in enumerate(info_fields.items(), start=len(fields) + 1):
            ttk.Label(parent, text=label).grid(row=idx, column=0, padx=5, pady=5, sticky="w")
            ttk.Label(parent, text=value).grid(row=idx, column=1, padx=5, pady=5, sticky="w")

    def create_thermal_tab(self, parent):
        """Создание вкладки для управления теплопередачей."""
        fields = {
            "Теплопроводность (Вт/(м·К)):": ("thermal_conductivity", "Теплопроводность материала, используемого в системе (Вт/(м·К))."),
            "Площадь (м²):": ("area", "Площадь поверхности, через которую происходит теплопередача (м²)."),
            "Толщина (м):": ("thickness", "Толщина материала, через который происходит теплопередача (м)."),
            "Разница температур (К):": ("delta_T", "Разница температур между горячей и холодной поверхностями (К).")
        }
        self.thermal_vars = {key: tk.DoubleVar(value=getattr(self.heat_transfer, fields[key][0]))
                             for key in fields}
        self.create_widgets(
            parent, fields,
            "Обновить Параметры",
            self.update_thermal_parameters
        )

        # Теплопередача
        ttk.Label(parent, text="Теплопередача по проводимости (Вт):").grid(row=len(fields) + 1, column=0, padx=5, pady=5, sticky="w")
        self.thermal_cond_label = ttk.Label(parent, text=f"{self.conductive_heat:.2e} Вт")
        self.thermal_cond_label.grid(row=len(fields) + 1, column=1, padx=5, pady=5, sticky="w")

        ttk.Label(parent, text="Теплопередача по излучению (Вт):").grid(row=len(fields) + 2, column=0, padx=5, pady=5, sticky="w")
        self.thermal_rad_label = ttk.Label(parent, text=f"{self.radiative_heat:.2e} Вт")
        self.thermal_rad_label.grid(row=len(fields) + 2, column=1, padx=5, pady=5, sticky="w")

    def create_structural_tab(self, parent):
        """Создание вкладки для анализа напряжений."""
        fields = {
            "Площадь поперечного сечения (м²):": ("area", "Площадь поперечного сечения конструкции (м²)."),
            "Модуль Юнга (Па):": ("E", "Модуль Юнга материала конструкции (Па)."),
            "Предел текучести (Па):": ("sigma_y", "Предел текучести материала конструкции (Па).")
        }
        self.structural_vars = {key: tk.DoubleVar(value=getattr(self.stress_analysis, fields[key][0]))
                                for key in fields}
        self.create_widgets(
            parent, fields,
            "Обновить Параметры",
            self.update_structural_parameters
        )

        # Напряжение и состояние
        ttk.Label(parent, text="Напряжение (Па):").grid(row=len(fields) + 1, column=0, padx=5, pady=5, sticky="w")
        self.structural_stress_label = ttk.Label(parent, text="-- Па", foreground="black")
        self.structural_stress_label.grid(row=len(fields) + 1, column=1, padx=5, pady=5, sticky="w")

        ttk.Label(parent, text="Предел текучести превышен:").grid(row=len(fields) + 2, column=0, padx=5, pady=5, sticky="w")
        self.structural_yielding_label = ttk.Label(parent, text="--", foreground="black")
        self.structural_yielding_label.grid(row=len(fields) + 2, column=1, padx=5, pady=5, sticky="w")

    def create_pid_tab(self, parent):
        """Создание вкладки для управления PID-контроллером."""
        fields = {
            "Kp:": ("Kp", "Пропорциональный коэффициент PID-контроллера."),
            "Ki:": ("Ki", "Интегральный коэффициент PID-контроллера."),
            "Kd:": ("Kd", "Дифференциальный коэффициент PID-контроллера."),
            "Заданная тяга (Н):": ("setpoint", "Желаемая тяга двигателя (Н). PID-контроллер будет пытаться поддерживать эту тягу.")
        }
        self.pid_vars = {key: tk.DoubleVar(value=getattr(self.pid, fields[key][0]))
                         for key in fields}
        self.create_widgets(
            parent, fields,
            "Обновить PID",
            self.update_pid_parameters
        )

        # Текущие коэффициенты PID
        current_fields = {
            "Текущие Kp:": f"{self.pid.Kp:.2f}",
            "Текущие Ki:": f"{self.pid.Ki:.2f}",
            "Текущие Kd:": f"{self.pid.Kd:.2f}"
        }
        for idx, (label, value) in enumerate(current_fields.items(), start=len(fields) + 1):
            ttk.Label(parent, text=label).grid(row=idx, column=0, padx=5, pady=5, sticky="w")
            ttk.Label(parent, text=value).grid(row=idx, column=1, padx=5, pady=5, sticky="w")

    def create_rocket_visual(self):
        """Создание визуализации ракеты внутри правого фрейма."""
        self.canvas = tk.Canvas(self.right_frame, width=400, height=600, bg="black")
        self.canvas.pack(padx=10, pady=10)
        self.rocket_x, self.rocket_y = 200, 550  # Центр нижней части канваса
        self.rocket = self.canvas.create_polygon(
            self.rocket_x, self.rocket_y - 40,
            self.rocket_x - 20, self.rocket_y + 20,
            self.rocket_x + 20, self.rocket_y + 20,
            fill="white"
        )

    def create_log_panel(self):
        """Создание панели логов внутри левого фрейма."""
        self.log_text = tk.Text(ttk.LabelFrame(self.left_frame, text="Лог Симуляции"), width=50, height=15, state='disabled')
        self.log_text.pack(padx=5, pady=5, fill=tk.BOTH, expand=True)

    def log_event(self, message):
        """Добавление сообщений в лог."""
        def append():
            self.log_text.config(state='normal')
            self.log_text.insert(tk.END, f"{time.strftime('%H:%M:%S')} - {message}\n")
            self.log_text.see(tk.END)
            self.log_text.config(state='disabled')
        self.master.after(0, append)

    def update_widget_label(self, widget, value):
        """Утилита для обновления текста виджета."""
        widget.config(text=value)

    def create_widgets(self, parent, fields, button_text, button_command, start_row=0):
        """Универсальный метод для создания набора Label, Entry и Button."""
        variables = {}
        for idx, (label, (attr, tooltip)) in enumerate(fields.items(), start=start_row):
            ttk.Label(parent, text=label).grid(row=idx, column=0, padx=5, pady=5, sticky="w")
            var = getattr(self, f"{attr}_vars", {}).get(label.split()[0], tk.DoubleVar())
            entry = ttk.Entry(parent, textvariable=getattr(self, f"{attr}_vars", {}).get(label.split()[0], var))
            entry.grid(row=idx, column=1, padx=5, pady=5, sticky="ew")
            ToolTip(entry, tooltip)
            variables[label] = entry
        button = ttk.Button(parent, text=button_text, command=button_command)
        button.grid(row=idx + 1, column=0, columnspan=2, pady=10)
        ToolTip(button, f"Нажмите, чтобы применить изменения {button_text.lower()}.")
        parent.columnconfigure(1, weight=1)
        return variables

    def run_simulation(self):
        """Основной цикл симуляции."""
        while self.running:
            start_time = time.time()

            # Обновление мощности двигателя
            self.thruster.set_power(self.allocated_power_thruster)
            self.thrust = self.thruster.get_thrust()
            self.si = self.thruster.get_specific_impulse()

            # Обновление анализа напряжений
            self.stress_analysis.force = self.thrust
            try:
                stress = self.stress_analysis.calculate_stress()
                yielding = self.stress_analysis.check_yielding()
            except ValueError:
                stress, yielding = 0.0, False

            # Обновление отображения
            self.master.after(0, self.update_labels)
            self.master.after(0, self.allocate_energy)

            # Обновление распределенной мощности на основе PID
            control = self.pid.update(self.thrust, dt=0.1)
            self.allocated_power_thruster = round(
                max(0.0, min(self.allocated_power_thruster + control * 0.1, self.power_output)), 2
            )
            self.master.after(0, lambda: self.update_widget_label(
                self.allocated_thruster_label, f"{self.allocated_power_thruster:.2f} Вт"
            ))
            self.log_event(f"Выделенная мощность двигателя: {self.allocated_power_thruster:.2f} Вт")

            # Логирование
            self.log_event(f"Актуальная тяга: {self.thrust:.4f} Н")
            self.log_event(f"Удельный импульс: {self.si:.2f} с")

            # Обновление положения ракеты
            self.master.after(0, self.update_rocket_position)

            # Задержка для симуляции реального времени (0.1 секунда)
            elapsed = time.time() - start_time
            time.sleep(max(0.0, 0.1 - elapsed))

    def update_labels(self):
        """Обновление необходимых меток в интерфейсе."""
        # Тяга и удельный импульс
        self.update_widget_label(self.thruster_thrust_label, f"{self.thrust:.4f} Н")
        self.update_widget_label(self.thruster_si_label, f"{self.si:.2f} с")

        # Напряжение и состояние
        try:
            stress = self.stress_analysis.calculate_stress()
            yielding = self.stress_analysis.check_yielding()
            self.update_widget_label(self.structural_stress_label, f"{stress:.2f} Па")
            status = "Да" if yielding else "Нет"
            color = "red" if yielding else "green"
            self.structural_yielding_label.config(text=status, foreground=color)

            # Проверки и предупреждения
            if stress > self.stress_analysis.sigma_y * 0.9 and not self.warning_flags['high_stress']:
                messagebox.showwarning("Предупреждение", "Напряжение приближается к пределу текучести. Возможны повреждения конструкции.")
                self.log_event("Внимание: напряжение приближается к пределу текучести.")
                self.warning_flags['high_stress'] = True
            elif stress <= self.stress_analysis.sigma_y * 0.9:
                self.warning_flags['high_stress'] = False

            if yielding and not self.warning_flags['yielding']:
                messagebox.showwarning("Предупреждение", "Напряжение превышает предел текучести. Возможна деформация конструкции.")
                self.log_event("Внимание: напряжение превышает предел текучести. Возможна деформация конструкции.")
                self.warning_flags['yielding'] = True
            elif not yielding:
                self.warning_flags['yielding'] = False

        except ValueError:
            self.update_widget_label(self.structural_stress_label, "-- Па")
            self.update_widget_label(self.structural_yielding_label, "--")

    def allocate_energy(self):
        """Распределение энергии между системами."""
        try:
            # Обновление потребностей
            self.demands = [
                self.energy_demand_thruster_var.get(),
                self.energy_demand_aux_var.get()
            ]
            self.allocated = self.energy_manager.allocate_power(self.demands)
            self.allocated_power_thruster, self.allocated_power_aux = self.allocated

            # Обновление меток
            self.allocated_thruster_label.config(text=f"{self.allocated_power_thruster:.2f} Вт")
            self.allocated_aux_label.config(text=f"{self.allocated_power_aux:.2f} Вт")

            # Обновление двигателя
            self.thruster.set_power(self.allocated_power_thruster)
            self.thrust = self.thruster.get_thrust()
            self.si = self.thruster.get_specific_impulse()

            self.update_widget_label(self.thruster_thrust_label, f"{self.thrust:.4f} Н")
            self.update_widget_label(self.thruster_si_label, f"{self.si:.2f} с")

            # Проверки мощности двигателя
            self.check_thruster_power()

            self.log_event(f"Энергия распределена: двигатель={self.allocated_power_thruster:.2f} Вт, вспомогательные системы={self.allocated_power_aux:.2f} Вт")

        except ValueError as e:
            messagebox.showwarning("Ошибка Распределения Энергии", f"Невозможно распределить энергию:\n{e}")
            self.log_event(f"Ошибка распределения энергии: {e}")

    def check_thruster_power(self):
        """Проверка выделенной мощности для двигателя и отображение предупреждений."""
        if self.allocated_power_thruster < 100 and not self.warning_flags['low_power_thruster']:
            messagebox.showwarning("Предупреждение", "Выделенная мощность для двигателя слишком мала. Возможна снижение тяги или нестабильная работа.")
            self.log_event("Внимание: выделенная мощность для двигателя слишком мала.")
            self.warning_flags['low_power_thruster'] = True
        elif self.allocated_power_thruster >= 100:
            self.warning_flags['low_power_thruster'] = False

        if self.allocated_power_thruster > 8000 and not self.warning_flags['high_power_thruster']:
            messagebox.showwarning("Предупреждение", "Выделенная мощность для двигателя слишком велика. Возможен перегрев или разрыв двигателя.")
            self.log_event("Внимание: выделенная мощность для двигателя слишком велика. Возможен разрыв двигателя.")
            self.warning_flags['high_power_thruster'] = True
        elif self.allocated_power_thruster <= 8000:
            self.warning_flags['high_power_thruster'] = False

    def update_solar_parameters(self):
        """Обновление параметров солнечной панели."""
        try:
            area = self.solar_vars["Площадь панели (м²):"].get()
            efficiency = self.solar_vars["КПД панели:"].get()
            irradiance = self.solar_vars["Инсоляция (Вт/м²):"].get()

            # Валидация ввода
            errors = []
            if area <= 0:
                errors.append("Площадь панели должна быть положительной.")
            if not (0 < efficiency <= 1):
                errors.append("КПД панели должен быть между 0 и 1.")
            if irradiance <= 0:
                errors.append("Инсоляция должна быть положительной.")

            if errors:
                raise ValueError("\n".join(errors))

            self.solar_panel.area = area
            self.solar_panel.efficiency = efficiency
            self.solar_panel.irradiance = irradiance

            self.power_output = self.solar_panel.calculate_power_output()
            self.power_output_label.config(text=f"{self.power_output:.2f} Вт")
            self.log_event(f"Солнечная панель обновлена: площадь={area} м², КПД={efficiency}, инсоляция={irradiance} Вт/м²")
            self.log_event(f"Новая выходная мощность: {self.power_output:.2f} Вт")

            # Обновление менеджера энергии
            self.energy_manager.power_sources = [self.power_output]
            self.allocate_energy()

        except ValueError as e:
            messagebox.showwarning("Ошибка Ввода", f"Неверные параметры солнечной панели:\n{e}")
            self.log_event(f"Ошибка обновления солнечной панели: {e}")

    def update_thruster_parameters(self):
        """Обновление параметров плазменного двигателя."""
        try:
            voltage = self.thruster_vars["Напряжение ускорения (В):"].get()
            mass_flow = self.thruster_vars["Массовый расход (кг/с):"].get()

            # Валидация ввода
            errors = []
            if voltage <= 0:
                errors.append("Напряжение ускорения должно быть положительным.")
            if mass_flow < 0:
                errors.append("Массовый расход не может быть отрицательным.")

            if errors:
                raise ValueError("\n".join(errors))

            self.thruster.accelerating_voltage = voltage
            self.thruster.mass_flow_rate = mass_flow

            self.thruster.set_power(self.allocated_power_thruster)
            self.thrust = self.thruster.get_thrust()
            self.si = self.thruster.get_specific_impulse()

            self.thruster_thrust_label.config(text=f"{self.thrust:.4f} Н")
            self.thruster_si_label.config(text=f"{self.si:.2f} с")
            self.thruster_vars["Массовый расход (кг/с):"].set(self.thruster.mass_flow_rate)

            self.log_event(f"Плазменный двигатель обновлен: напряжение={voltage} В, массовый расход={mass_flow} кг/с")
            self.log_event(f"Новая тяга: {self.thrust:.4f} Н, удельный импульс: {self.si:.2f} с")

            # Проверка массового расхода
            if mass_flow > 1e-4 and not self.warning_flags['high_mass_flow']:
                messagebox.showwarning("Предупреждение", "Массовый расход слишком велик. Возможен перегрев двигателя или истощение топлива.")
                self.log_event("Внимание: массовый расход слишком велик. Возможен перегрев двигателя или истощение топлива.")
                self.warning_flags['high_mass_flow'] = True
            elif mass_flow <= 1e-4:
                self.warning_flags['high_mass_flow'] = False

        except ValueError as e:
            messagebox.showwarning("Ошибка Ввода", f"Неверные параметры двигателя:\n{e}")
            self.log_event(f"Ошибка обновления плазменного двигателя: {e}")

    def update_thermal_parameters(self):
        """Обновление параметров теплопередачи."""
        try:
            k = self.thermal_vars["Теплопроводность (Вт/(м·К)):"].get()
            area = self.thermal_vars["Площадь (м²):"].get()
            thickness = self.thermal_vars["Толщина (м):"].get()
            delta_T = self.thermal_vars["Разница температур (К):"].get()

            # Валидация ввода
            errors = []
            if k <= 0:
                errors.append("Теплопроводность должна быть положительной.")
            if area <= 0:
                errors.append("Площадь должна быть положительной.")
            if thickness <= 0:
                errors.append("Толщина должна быть положительной.")
            if delta_T < 0:
                errors.append("Разница температур не может быть отрицательной.")

            if errors:
                raise ValueError("\n".join(errors))

            self.heat_transfer.thermal_conductivity = k
            self.heat_transfer.area = area
            self.heat_transfer.thickness = thickness
            self.heat_transfer.delta_T = delta_T

            self.conductive_heat = self.heat_transfer.conductive_heat_transfer()
            self.radiative_heat = self.heat_transfer.radiative_heat_transfer(
                emissivity=0.8, T_hot=1000, T_cold=300
            )

            self.thermal_cond_label.config(text=f"{self.conductive_heat:.2e} Вт")
            self.thermal_rad_label.config(text=f"{self.radiative_heat:.2e} Вт")

            self.log_event(f"Теплопередача обновлена: k={k} Вт/(м·К), A={area} м², d={thickness} м, ΔT={delta_T} К")
            self.log_event(f"Новая теплопередача: проводимость={self.conductive_heat:.2e} Вт, излучение={self.radiative_heat:.2e} Вт")

            # Проверка разницы температур
            if delta_T > 1000 and not self.warning_flags['high_delta_T']:
                messagebox.showwarning("Предупреждение", "Разница температур слишком велика. Возможен перегрев системы.")
                self.log_event("Внимание: разница температур слишком велика. Возможен перегрев системы.")
                self.warning_flags['high_delta_T'] = True
            elif delta_T <= 1000:
                self.warning_flags['high_delta_T'] = False

        except ValueError as e:
            messagebox.showwarning("Ошибка Ввода", f"Неверные параметры теплопередачи:\n{e}")
            self.log_event(f"Ошибка обновления теплопередачи: {e}")

    def update_structural_parameters(self):
        """Обновление параметров анализа напряжений."""
        try:
            area = self.structural_vars["Площадь поперечного сечения (м²):"].get()
            E = self.structural_vars["Модуль Юнга (Па):"].get()
            sigma_y = self.structural_vars["Предел текучести (Па):"].get()

            # Валидация ввода
            errors = []
            if area <= 0:
                errors.append("Площадь поперечного сечения должна быть положительной.")
            if E <= 0:
                errors.append("Модуль Юнга должен быть положительным.")
            if sigma_y <= 0:
                errors.append("Предел текучести должен быть положительным.")

            if errors:
                raise ValueError("\n".join(errors))

            self.stress_analysis.area = area
            self.stress_analysis.E = E
            self.stress_analysis.sigma_y = sigma_y

            stress = self.stress_analysis.calculate_stress()
            yielding = self.stress_analysis.check_yielding()

            self.structural_stress_label.config(text=f"{stress:.2f} Па")
            status = "Да" if yielding else "Нет"
            color = "red" if yielding else "green"
            self.structural_yielding_label.config(text=status, foreground=color)

            self.log_event(f"Анализ напряжений обновлен: площадь={area} м², модуль Юнга={E} Па, предел текучести={sigma_y} Па")
            self.log_event(f"Текущее напряжение: {stress:.2f} Па, превышен предел текучести: {yielding}")

            # Проверка напряжения
            if stress > sigma_y * 0.9 and not self.warning_flags['high_stress']:
                messagebox.showwarning("Предупреждение", "Напряжение приближается к пределу текучести. Возможны повреждения конструкции.")
                self.log_event("Внимание: напряжение приближается к пределу текучести.")
                self.warning_flags['high_stress'] = True
            elif stress <= sigma_y * 0.9:
                self.warning_flags['high_stress'] = False

        except ValueError as e:
            messagebox.showwarning("Ошибка Ввода", f"Неверные параметры анализа напряжений:\n{e}")
            self.log_event(f"Ошибка обновления анализа напряжений: {e}")

    def update_pid_parameters(self):
        """Обновление параметров PID-контроллера."""
        try:
            Kp = self.pid_vars["Kp:"].get()
            Ki = self.pid_vars["Ki:"].get()
            Kd = self.pid_vars["Kd:"].get()
            setpoint = self.pid_vars["Заданная тяга (Н):"].get()

            # Валидация ввода
            errors = []
            if Kp < 0:
                errors.append("Kp не может быть отрицательным.")
            if Ki < 0:
                errors.append("Ki не может быть отрицательным.")
            if Kd < 0:
                errors.append("Kd не может быть отрицательным.")
            if setpoint < 0:
                errors.append("Заданная тяга не может быть отрицательной.")

            if errors:
                raise ValueError("\n".join(errors))

            self.pid.Kp, self.pid.Ki, self.pid.Kd, self.pid.setpoint = Kp, Ki, Kd, setpoint

            # Обновление текущих коэффициентов PID
            current_labels = {
                "Текущие Kp:": f"{self.pid.Kp:.2f}",
                "Текущие Ki:": f"{self.pid.Ki:.2f}",
                "Текущие Kd:": f"{self.pid.Kd:.2f}"
            }
            for label, value in current_labels.items():
                widget = parent_naming(label)  # Replace with actual widget reference if needed
                # Assuming you have references to the labels, otherwise store them similarly to entries
                # Here, for brevity, we'll skip updating these labels dynamically

            self.log_event(f"PID-Контроллер обновлен: Kp={Kp}, Ki={Ki}, Kd={Kd}, заданная тяга={setpoint} Н")

            # Проверка заданной тяги
            if setpoint > 8000 and not self.warning_flags['high_setpoint']:
                messagebox.showwarning("Предупреждение", "Заданная тяга слишком велика. Возможен перегрев двигателя или разрыв конструкции.")
                self.log_event("Внимание: заданная тяга слишком велика.")
                self.warning_flags['high_setpoint'] = True
            elif setpoint <= 8000:
                self.warning_flags['high_setpoint'] = False

        except ValueError as e:
            messagebox.showwarning("Ошибка Ввода", f"Неверные параметры PID-контроллера:\n{e}")
            self.log_event(f"Ошибка обновления PID-Контроллера: {e}")

    def update_rocket_position(self):
        """Обновление позиции ракеты на канвасе на основе текущей тяги."""
        thrust_scale = 1e4  # Масштаб для отображения тяги
        dy = self.thrust * thrust_scale * 0.0001  # Смещение по Y

        # Ограничение позиции ракеты внутри канваса
        new_y = self.rocket_y + dy
        new_y = max(50, min(new_y, self.canvas.winfo_height() - 50))

        # Смещение ракеты
        delta_y = new_y - self.rocket_y
        self.canvas.move(self.rocket, 0, delta_y)
        self.rocket_y = new_y

    def update_labels(self):
        """Обновление меток тяги, удельного импульса и напряжений."""
        self.thruster_thrust_label.config(text=f"{self.thrust:.4f} Н")
        self.thruster_si_label.config(text=f"{self.si:.2f} с")

        try:
            stress = self.stress_analysis.calculate_stress()
            yielding = self.stress_analysis.check_yielding()
            self.structural_stress_label.config(text=f"{stress:.2f} Па")
            status = "Да" if yielding else "Нет"
            color = "red" if yielding else "green"
            self.structural_yielding_label.config(text=status, foreground=color)

            # Проверки и предупреждения
            if stress > self.stress_analysis.sigma_y * 0.9 and not self.warning_flags['high_stress']:
                messagebox.showwarning("Предупреждение", "Напряжение приближается к пределу текучести. Возможны повреждения конструкции.")
                self.log_event("Внимание: напряжение приближается к пределу текучести.")
                self.warning_flags['high_stress'] = True
            elif stress <= self.stress_analysis.sigma_y * 0.9:
                self.warning_flags['high_stress'] = False

            if yielding and not self.warning_flags['yielding']:
                messagebox.showwarning("Предупреждение", "Напряжение превышает предел текучести. Возможна деформация конструкции.")
                self.log_event("Внимание: напряжение превышает предел текучести. Возможна деформация конструкции.")
                self.warning_flags['yielding'] = True
            elif not yielding:
                self.warning_flags['yielding'] = False

        except ValueError:
            self.structural_stress_label.config(text="-- Па")
            self.structural_yielding_label.config(text="--")

    def on_close(self):
        """Обработка закрытия окна для корректного завершения симуляции."""
        if messagebox.askokcancel("Выход", "Вы уверены, что хотите выйти?"):
            self.running = False
            self.master.destroy()


if __name__ == "__main__":
    root = tk.Tk()
    interface = RocketControlInterface(root)
    root.mainloop()
```
```python
# thermal_management/heat_transfer.py

from utils.constants import STEFAN_BOLTZMANN

class HeatTransfer:
    def __init__(self, thermal_conductivity, area, thickness, temperature_diff):
        """
        Инициализация модели теплопередачи.

        :param thermal_conductivity: Теплопроводность материала (Вт/(м·К))
        :param area: Площадь теплопередающей поверхности (м²)
        :param thickness: Толщина материала (м)
        :param temperature_diff: Разница температур (К)
        """
        self.k = thermal_conductivity
        self.A = area
        self.d = thickness
        self.delta_T = temperature_diff

    def conductive_heat_transfer(self):
        """
        Расчет теплопередачи по проводимости.

        :return: Теплопередача (Вт)
        """
        if self.d <= 0:
            raise ValueError("Толщина должна быть положительной.")
        return self.k * self.A * self.delta_T / self.d

    def radiative_heat_transfer(self, emissivity, T_hot, T_cold):
        """
        Расчет теплопередачи по излучению.

        :param emissivity: Эмиссивность материала (от 0 до 1)
        :param T_hot: Температура горячей поверхности (K)
        :param T_cold: Температура холодной поверхности (K)
        :return: Теплопередача (Вт)
        """
        if not (0 <= emissivity <= 1):
            raise ValueError("Эмиссивность должна быть между 0 и 1.")
        return emissivity * STEFAN_BOLTZMANN * self.A * (T_hot ** 4 - T_cold ** 4)
```