migliora questo codice rendendolo più complesso e difficile import sys
import numpy as np
import random
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout,
    QHBoxLayout, QPushButton, QLabel, QSlider, QGridLayout,
    QFrame, QMessageBox
)
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QColor, QPainter, QBrush, QPen
import matplotlib
matplotlib.use('Qt5Agg')
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.figure import Figure

class ReattoreNucleare:
    def __init__(self):
        # Parametri di stato del reattore
        self.neutroni = 1e5
        self.combustibile = 1e5
        self.xeno = 0
        self.samario = 0
        self.acqua = 1e5
        self.tempo = 0
        self.delta_t = 0.1

        # Parametri fisici avanzati
        self.temperatura = 300  # Kelvin
        self.pressione = 100  # Atmosfere
        self.reattivita = 0.005
        self.barre_controllo = 50
        self.concentrazione_boro = 0
        self.flusso_acqua = 1000

        # Costanti
        self.coef_temp = -0.0001
        self.coef_boro = -0.0005
        self.coef_barre = -0.001
        self.coef_combustibile = -0.00001
        self.coef_samario = -0.0002

        # Log dei dati
        self.log_dati = []

        # Griglia del nocciolo
        self.griglia_dimensione = 10
        self.griglia = np.zeros((self.griglia_dimensione,
                                 self.griglia_dimensione))

    def step(self):
        # Calcolo della reattività totale
        reattivita_totale = self.reattivita
        reattivita_totale += self.coef_temp * (self.temperatura - 300)
        reattivita_totale += self.coef_boro * self.concentrazione_boro
        reattivita_totale += self.coef_barre * self.barre_controllo
        reattivita_totale += self.coef_samario * self.samario

        # Aggiornamento del combustibile
        combustibile_bruciato = self.neutroni * 1e-7 * self.delta_t
        self.combustibile -= combustibile_bruciato

        # Transmutazioni e produzione di nuovi isotopi fissili
        nuovi_isotopi = combustibile_bruciato * 0.1
        self.combustibile += nuovi_isotopi

        # Aggiornamento dei neutroni
        self.neutroni *= (1 + reattivita_totale) * (
            self.combustibile / 1e5)

        # Effetti su temperatura e pressione
        energia_rilasciata = combustibile_bruciato * 1e5
        self.temperatura += (energia_rilasciata * 0.1 - (
            self.temperatura - 300) * 0.05) * self.delta_t
        self.pressione += ((self.temperatura - 300) * 0.01 - (
            self.pressione - 100) * 0.05) * self.delta_t

        # Raffreddamento tramite flusso d'acqua
        self.temperatura -= self.flusso_acqua * 0.01 * self.delta_t

        # Aggiornamento dello xeno e del samario
        produzione_xeno = combustibile_bruciato * 0.1 * self.delta_t
        decadimento_xeno = -self.xeno * 0.01 * self.delta_t
        self.xeno += (produzione_xeno + decadimento_xeno)

        produzione_samario = self.xeno * 0.05 * self.delta_t
        self.samario += produzione_samario

        # Assorbimento neutroni
        neutroni_assorbiti_xeno = self.xeno * self.neutroni * 1e-8 * self.delta_t
        neutroni_assorbiti_samario = self.samario * self.neutroni * 1e-9 * self.delta_t
        neutroni_assorbiti_boro = self.concentrazione_boro * self.neutroni * 1e-9 * self.delta_t
        self.neutroni -= (neutroni_assorbiti_xeno + neutroni_assorbiti_samario + neutroni_assorbiti_boro)

        # Aggiornamento della griglia del nocciolo
        self.update_griglia()

        # Controllo dei limiti fisici
        self.neutroni = max(self.neutroni, 0)
        self.xeno = max(self.xeno, 0)
        self.samario = max(self.samario, 0)
        self.temperatura = max(self.temperatura, 0)
        self.pressione = max(self.pressione, 0)
        self.combustibile = max(self.combustibile, 0)

        # Incremento del tempo
        self.tempo += self.delta_t

        # Salvo i dati nel log
        self.log_dati.append({
            'tempo': self.tempo,
            'neutroni': self.neutroni,
            'xeno': self.xeno,
            'samario': self.samario,
            'temperatura': self.temperatura,
            'pressione': self.pressione,
            'reattivita': reattivita_totale,
            'combustibile': self.combustibile,
        })

    def update_griglia(self):
        # Aggiorna la griglia del nocciolo in base ai neutroni
        for i in range(self.griglia_dimensione):
            for j in range(self.griglia_dimensione):
                # Simula l'attività neutronica in ciascuna cella
                self.griglia[i, j] = random.uniform(
                    0, self.neutroni / (1e5 * self.griglia_dimensione ** 2))

class CanvasReattore(QWidget):
    def __init__(self, reattore):
        super().__init__()
        self.reattore = reattore
        self.setMinimumSize(400, 400)

    def paintEvent(self, event):
        qp = QPainter()
        qp.begin(self)
        self.drawGrid(qp)
        qp.end()

    def drawGrid(self, qp):
        size = self.size()
        rect_size = min(size.width(),
                        size.height()) // self.reattore.griglia_dimensione
        for i in range(self.reattore.griglia_dimensione):
            for j in range(self.reattore.griglia_dimensione):
                activity = self.reattore.griglia[i, j]
                temperature = self.reattore.temperatura
                color = QColor(0, 0, 255)
                color.setHsv(int(240 - activity * 240), 255, 255)
                qp.setBrush(QBrush(color, Qt.SolidPattern))
                qp.setPen(QPen(Qt.black, 1, Qt.SolidLine))
                x = j * rect_size
                y = i * rect_size
                qp.drawRect(x, y, rect_size, rect_size)

class GraficoCanvas(FigureCanvasQTAgg):
    def __init__(self, parent, width=5, height=4, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)
        self.axes = fig.add_subplot(111)
        super().__init__(fig)
        self.setParent(parent)
        fig.tight_layout()

class AppReattore(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Simulazione Completa Reattore Nucleare")
        self.setGeometry(100, 100, 1200, 800)

        self.reattore = ReattoreNucleare()

        # Timer per l'aggiornamento della simulazione
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_simulation)

        # Layout principale
        self.main_widget = QWidget()
        self.setCentralWidget(self.main_widget)
        main_layout = QHBoxLayout()
        self.main_widget.setLayout(main_layout)

        # Area dei controlli
        self.controls_widget = QWidget()
        controls_layout = QVBoxLayout()
        self.controls_widget.setLayout(controls_layout)
        main_layout.addWidget(self.controls_widget)

        # Area della visualizzazione
        self.visual_widget = QWidget()
        visual_layout = QVBoxLayout()
        self.visual_widget.setLayout(visual_layout)
        main_layout.addWidget(self.visual_widget)

        # Controlli
        self.create_controls(controls_layout)

        # Visualizzazione
        self.canvas_reattore = CanvasReattore(self.reattore)
        visual_layout.addWidget(self.canvas_reattore)

        # Grafico in tempo reale
        self.grafico = GraficoCanvas(self.visual_widget, width=5, height=3)
        visual_layout.addWidget(self.grafico)

        # Dati per il grafico
        self.times = []
        self.neutroni = []
        self.temperatura = []

    def create_controls(self, layout):
        # Pulsanti di controllo
        self.start_button = QPushButton("Avvia Simulazione")
        self.start_button.clicked.connect(self.start_simulation)
        layout.addWidget(self.start_button)

        self.stop_button = QPushButton("Ferma Simulazione")
        self.stop_button.clicked.connect(self.stop_simulation)
        self.stop_button.setEnabled(False)
        layout.addWidget(self.stop_button)

        self.reset_button = QPushButton("Reset")
        self.reset_button.clicked.connect(self.reset_simulation)
        layout.addWidget(self.reset_button)

        # Slider per le barre di controllo
        self.slider_barre = QSlider(Qt.Horizontal)
        self.slider_barre.setMinimum(0)
        self.slider_barre.setMaximum(100)
        self.slider_barre.setValue(self.reattore.barre_controllo)
        self.slider_barre.valueChanged.connect(self.update_barre)
        layout.addWidget(QLabel("Barre di Controllo (%)"))
        layout.addWidget(self.slider_barre)

        # Slider per la concentrazione di boro
        self.slider_boro = QSlider(Qt.Horizontal)
        self.slider_boro.setMinimum(0)
        self.slider_boro.setMaximum(1000)
        self.slider_boro.setValue(self.reattore.concentrazione_boro)
        self.slider_boro.valueChanged.connect(self.update_boro)
        layout.addWidget(QLabel("Concentrazione di Boro (ppm)"))
        layout.addWidget(self.slider_boro)

        # Slider per il flusso d'acqua
        self.slider_acqua = QSlider(Qt.Horizontal)
        self.slider_acqua.setMinimum(0)
        self.slider_acqua.setMaximum(2000)
        self.slider_acqua.setValue(self.reattore.flusso_acqua)
        self.slider_acqua.valueChanged.connect(self.update_acqua)
        layout.addWidget(QLabel("Flusso d'Acqua"))
        layout.addWidget(self.slider_acqua)

        # Indicatori di stato
        self.label_neutroni = QLabel("Neutroni: ")
        layout.addWidget(self.label_neutroni)

        self.label_combustibile = QLabel("Combustibile: ")
        layout.addWidget(self.label_combustibile)

        self.label_reattivita = QLabel("Reattività: ")
        layout.addWidget(self.label_reattivita)

        self.label_temperatura = QLabel("Temperatura (K): ")
        layout.addWidget(self.label_temperatura)

        self.label_pressione = QLabel("Pressione (atm): ")
        layout.addWidget(self.label_pressione)

    def update_barre(self, value):
        self.reattore.barre_controllo = value

    def update_boro(self, value):
        self.reattore.concentrazione_boro = value

    def update_acqua(self, value):
        self.reattore.flusso_acqua = value

    def start_simulation(self):
        self.timer.start(100)
        self.start_button.setEnabled(False)
        self.stop_button.setEnabled(True)

    def stop_simulation(self):
        self.timer.stop()
        self.start_button.setEnabled(True)
        self.stop_button.setEnabled(False)

    def reset_simulation(self):
        self.stop_simulation()
        self.reattore = ReattoreNucleare()
        self.canvas_reattore.reattore = self.reattore
        self.times = []
        self.neutroni = []
        self.temperatura = []
        self.grafico.axes.clear()
        self.grafico.draw()
        self.update_labels()

    def update_simulation(self):
        self.reattore.step()
        self.update_labels()
        self.canvas_reattore.update()

        # Aggiorna dati per il grafico
        self.times.append(self.reattore.tempo)
        self.neutroni.append(self.reattore.neutroni)
        self.temperatura.append(self.reattore.temperatura)

        # Aggiorna il grafico
        self.grafico.axes.clear()
        self.grafico.axes.plot(self.times, self.neutroni, label='Neutroni')
        self.grafico.axes.plot(self.times, self.temperatura, label='Temperatura')
        self.grafico.axes.legend()
        self.grafico.draw()

        # Controlla condizioni critiche
        if self.reattore.temperatura > 1000 or self.reattore.pressione > 200:
            self.sistema_sicurezza()

    def sistema_sicurezza(self):
        self.stop_simulation()
        # Attiva SCRAM (inserimento completo delle barre di controllo)
        self.slider_barre.setValue(100)
        self.reattore.barre_controllo = 100
        # Iniezione di boro di emergenza
        self.slider_boro.setValue(1000)
        self.reattore.concentrazione_boro = 1000
        QMessageBox.warning(self, "Allarme", "Condizioni critiche raggiunte!\n"
                                             "Attivazione dei sistemi di sicurezza.")

    def update_labels(self):
        self.label_neutroni.setText(f"Neutroni: {self.reattore.neutroni:.2e}")
        self.label_combustibile.setText(f"Combustibile: {self.reattore.combustibile:.2e}")
        self.label_reattivita.setText(f"Reattività: {self.reattore.reattivita:.6f}")
        self.label_temperatura.setText(f"Temperatura (K): {self.reattore.temperatura:.2f}")
        self.label_pressione.setText(f"Pressione (atm): {self.reattore.pressione:.2f}")

    def closeEvent(self, event):
        self.stop_simulation()
        event.accept()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = AppReattore()
    window.show()
    sys.exit(app.exec_())