| | import sys |
| | import io |
| | from contextlib import redirect_stdout |
| | from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, |
| | QHBoxLayout, QTabWidget, QTextEdit, QPushButton, |
| | QGroupBox, QLabel, QComboBox, QSpinBox, QDoubleSpinBox, |
| | QLineEdit, QFormLayout, QSplitter, QMessageBox) |
| | from PyQt5.QtCore import Qt |
| | from PyQt5.QtGui import QFont, QTextCursor |
| |
|
| | |
| | import sympy as sp |
| | from constructing_gradient_fields_case_1_and_2_optimized_final import ( |
| | GradientFieldFactory, NumericalExamples, ConstantComponentField, LinearComponentField |
| | ) |
| |
|
| | class GradientFieldApp(QMainWindow): |
| | def __init__(self): |
| | super().__init__() |
| | self.initUI() |
| | |
| | def initUI(self): |
| | self.setWindowTitle('Gradient Field Analyzer') |
| | self.setGeometry(100, 100, 1200, 800) |
| | |
| | |
| | central_widget = QWidget() |
| | self.setCentralWidget(central_widget) |
| | main_layout = QVBoxLayout(central_widget) |
| | |
| | |
| | title_label = QLabel('Gradient Field Analyzer') |
| | title_label.setAlignment(Qt.AlignCenter) |
| | title_font = QFont() |
| | title_font.setPointSize(16) |
| | title_font.setBold(True) |
| | title_label.setFont(title_font) |
| | main_layout.addWidget(title_label) |
| | |
| | |
| | self.tabs = QTabWidget() |
| | main_layout.addWidget(self.tabs) |
| | |
| | |
| | self.create_analysis_tab() |
| | self.create_case1_tab() |
| | self.create_case2_tab() |
| | self.create_numerical_examples_tab() |
| | |
| | |
| | self.statusBar().showMessage('Ready') |
| | |
| | def create_analysis_tab(self): |
| | """Tab for running the complete analysis""" |
| | tab = QWidget() |
| | layout = QVBoxLayout(tab) |
| | |
| | |
| | desc_label = QLabel( |
| | "Run the complete gradient field analysis from the case study. " |
| | "This will analyze both Case 1 (one constant component) and " |
| | "Case 2 (both linear components)." |
| | ) |
| | desc_label.setWordWrap(True) |
| | layout.addWidget(desc_label) |
| | |
| | |
| | run_btn = QPushButton('Run Complete Analysis') |
| | run_btn.clicked.connect(self.run_complete_analysis) |
| | layout.addWidget(run_btn) |
| | |
| | |
| | self.analysis_output = QTextEdit() |
| | self.analysis_output.setReadOnly(True) |
| | layout.addWidget(self.analysis_output) |
| | |
| | self.tabs.addTab(tab, "Complete Analysis") |
| | |
| | def create_case1_tab(self): |
| | """Tab for Case 1: One constant component""" |
| | tab = QWidget() |
| | layout = QVBoxLayout(tab) |
| | |
| | |
| | desc_label = QLabel( |
| | "Case 1: One component of the vector field is constant. " |
| | "The potential function can be found by direct integration." |
| | ) |
| | desc_label.setWordWrap(True) |
| | layout.addWidget(desc_label) |
| | |
| | |
| | form_group = QGroupBox("Vector Field Parameters") |
| | form_layout = QFormLayout(form_group) |
| | |
| | |
| | self.case1_component = QComboBox() |
| | self.case1_component.addItems(['x', 'y']) |
| | form_layout.addRow("Constant Component:", self.case1_component) |
| | |
| | |
| | self.case1_constant = QLineEdit() |
| | self.case1_constant.setText('2') |
| | form_layout.addRow("Constant Value:", self.case1_constant) |
| | |
| | |
| | self.case1_function = QLineEdit() |
| | self.case1_function.setText('y**2') |
| | form_layout.addRow("Function (for non-constant component):", self.case1_function) |
| | |
| | layout.addWidget(form_group) |
| | |
| | |
| | btn_layout = QHBoxLayout() |
| | |
| | analyze_btn = QPushButton('Analyze Case 1') |
| | analyze_btn.clicked.connect(self.analyze_case1) |
| | btn_layout.addWidget(analyze_btn) |
| | |
| | symbolic_btn = QPushButton('Show Symbolic Analysis') |
| | symbolic_btn.clicked.connect(self.show_symbolic_case1) |
| | btn_layout.addWidget(symbolic_btn) |
| | |
| | layout.addLayout(btn_layout) |
| | |
| | |
| | self.case1_output = QTextEdit() |
| | self.case1_output.setReadOnly(True) |
| | layout.addWidget(self.case1_output) |
| | |
| | self.tabs.addTab(tab, "Case 1") |
| | |
| | def create_case2_tab(self): |
| | """Tab for Case 2: Both linear components""" |
| | tab = QWidget() |
| | layout = QVBoxLayout(tab) |
| | |
| | |
| | desc_label = QLabel( |
| | "Case 2: Both components of the vector field are linear functions. " |
| | "The field is a gradient field if and only if a₂ = b₁." |
| | ) |
| | desc_label.setWordWrap(True) |
| | layout.addWidget(desc_label) |
| | |
| | |
| | form_group = QGroupBox("Vector Field Parameters") |
| | form_layout = QFormLayout(form_group) |
| | |
| | |
| | self.case2_a1 = QLineEdit() |
| | self.case2_a1.setText('2') |
| | form_layout.addRow("a₁ (coefficient of x in Vx):", self.case2_a1) |
| | |
| | self.case2_b1 = QLineEdit() |
| | self.case2_b1.setText('3') |
| | form_layout.addRow("b₁ (coefficient of y in Vx):", self.case2_b1) |
| | |
| | self.case2_c1 = QLineEdit() |
| | self.case2_c1.setText('1') |
| | form_layout.addRow("c₁ (constant in Vx):", self.case2_c1) |
| | |
| | |
| | self.case2_a2 = QLineEdit() |
| | self.case2_a2.setText('3') |
| | form_layout.addRow("a₂ (coefficient of x in Vy):", self.case2_a2) |
| | |
| | self.case2_b2 = QLineEdit() |
| | self.case2_b2.setText('4') |
| | form_layout.addRow("b₂ (coefficient of y in Vy):", self.case2_b2) |
| | |
| | self.case2_c2 = QLineEdit() |
| | self.case2_c2.setText('2') |
| | form_layout.addRow("c₂ (constant in Vy):", self.case2_c2) |
| | |
| | layout.addWidget(form_group) |
| | |
| | |
| | btn_layout = QHBoxLayout() |
| | |
| | analyze_btn = QPushButton('Analyze Case 2') |
| | analyze_btn.clicked.connect(self.analyze_case2) |
| | btn_layout.addWidget(analyze_btn) |
| | |
| | symbolic_btn = QPushButton('Show Symbolic Analysis') |
| | symbolic_btn.clicked.connect(self.show_symbolic_case2) |
| | btn_layout.addWidget(symbolic_btn) |
| | |
| | check_btn = QPushButton('Check Gradient Condition') |
| | check_btn.clicked.connect(self.check_gradient_condition) |
| | btn_layout.addWidget(check_btn) |
| | |
| | layout.addLayout(btn_layout) |
| | |
| | |
| | self.case2_output = QTextEdit() |
| | self.case2_output.setReadOnly(True) |
| | layout.addWidget(self.case2_output) |
| | |
| | self.tabs.addTab(tab, "Case 2") |
| | |
| | def create_numerical_examples_tab(self): |
| | """Tab for running numerical examples""" |
| | tab = QWidget() |
| | layout = QVBoxLayout(tab) |
| | |
| | |
| | desc_label = QLabel( |
| | "Run numerical examples to verify the gradient field analysis. " |
| | "These examples demonstrate both valid gradient fields and non-gradient fields." |
| | ) |
| | desc_label.setWordWrap(True) |
| | layout.addWidget(desc_label) |
| | |
| | |
| | btn_layout = QHBoxLayout() |
| | |
| | case1_examples_btn = QPushButton('Run Case 1 Examples') |
| | case1_examples_btn.clicked.connect(self.run_case1_examples) |
| | btn_layout.addWidget(case1_examples_btn) |
| | |
| | case2_examples_btn = QPushButton('Run Case 2 Examples') |
| | case2_examples_btn.clicked.connect(self.run_case2_examples) |
| | btn_layout.addWidget(case2_examples_btn) |
| | |
| | all_examples_btn = QPushButton('Run All Examples') |
| | all_examples_btn.clicked.connect(self.run_all_examples) |
| | btn_layout.addWidget(all_examples_btn) |
| | |
| | layout.addLayout(btn_layout) |
| | |
| | |
| | self.examples_output = QTextEdit() |
| | self.examples_output.setReadOnly(True) |
| | layout.addWidget(self.examples_output) |
| | |
| | self.tabs.addTab(tab, "Numerical Examples") |
| | |
| | def run_complete_analysis(self): |
| | """Run the complete analysis from the original script""" |
| | self.analysis_output.clear() |
| | |
| | |
| | output = io.StringIO() |
| | with redirect_stdout(output): |
| | try: |
| | analyzer1, analyzer2, analyzer3 = GradientFieldFactory.analyze_all_cases() |
| | self.statusBar().showMessage('Complete analysis finished successfully') |
| | except Exception as e: |
| | print(f"Error during analysis: {e}") |
| | self.statusBar().showMessage(f'Error: {e}') |
| | |
| | self.analysis_output.setPlainText(output.getvalue()) |
| | |
| | def analyze_case1(self): |
| | """Analyze a specific Case 1 example""" |
| | self.case1_output.clear() |
| | |
| | try: |
| | |
| | component = self.case1_component.currentText() |
| | constant = float(self.case1_constant.text()) |
| | function_str = self.case1_function.text() |
| | |
| | |
| | analyzer = ConstantComponentField(component) |
| | |
| | |
| | x, y = sp.symbols('x y') |
| | if component == 'x': |
| | Vx = constant |
| | Vy = sp.sympify(function_str) |
| | else: |
| | Vx = sp.sympify(function_str) |
| | Vy = constant |
| | |
| | |
| | phi = analyzer.find_potential_for_specific_field(Vx, Vy) |
| | |
| | |
| | output = f"Case 1 Analysis:\n" |
| | output += f"Vector Field: F(x,y) = [{Vx}, {Vy}]\n" |
| | output += f"Potential Function: φ(x,y) = {sp.simplify(phi)}\n\n" |
| | |
| | |
| | is_valid, diff_x, diff_y = analyzer.verify_potential(phi, Vx, Vy) |
| | output += f"Verification: ∇φ = F? {is_valid}\n" |
| | if not is_valid: |
| | output += f" ∂φ/∂x - Vx = {diff_x}\n" |
| | output += f" ∂φ/∂y - Vy = {diff_y}\n" |
| | |
| | self.case1_output.setPlainText(output) |
| | self.statusBar().showMessage('Case 1 analysis completed') |
| | |
| | except Exception as e: |
| | self.case1_output.setPlainText(f"Error: {e}") |
| | self.statusBar().showMessage(f'Error in Case 1 analysis: {e}') |
| | |
| | def show_symbolic_case1(self): |
| | """Show symbolic analysis for Case 1""" |
| | self.case1_output.clear() |
| | |
| | try: |
| | component = self.case1_component.currentText() |
| | analyzer = ConstantComponentField(component) |
| | |
| | |
| | phi = analyzer.find_potential() |
| | Vx, Vy = analyzer.get_vector_field() |
| | |
| | output = f"Symbolic Analysis for Case 1:\n" |
| | output += f"Vector Field: F(x,y) = [{Vx}, {Vy}]\n" |
| | output += f"Potential Function: φ(x,y) = {phi}\n\n" |
| | |
| | |
| | output += "Specific Examples:\n" |
| | examples = analyzer.get_specific_cases() |
| | for case_name, (Vx_ex, Vy_ex, phi_ex) in examples.items(): |
| | output += f"{case_name}:\n" |
| | output += f" F(x,y) = [{Vx_ex}, {Vy_ex}]\n" |
| | output += f" φ(x,y) = {phi_ex}\n\n" |
| | |
| | self.case1_output.setPlainText(output) |
| | self.statusBar().showMessage('Symbolic Case 1 analysis completed') |
| | |
| | except Exception as e: |
| | self.case1_output.setPlainText(f"Error: {e}") |
| | self.statusBar().showMessage(f'Error in symbolic Case 1 analysis: {e}') |
| | |
| | def analyze_case2(self): |
| | """Analyze a specific Case 2 example""" |
| | self.case2_output.clear() |
| | |
| | try: |
| | |
| | a1 = float(self.case2_a1.text()) |
| | b1 = float(self.case2_b1.text()) |
| | c1 = float(self.case2_c1.text()) |
| | a2 = float(self.case2_a2.text()) |
| | b2 = float(self.case2_b2.text()) |
| | c2 = float(self.case2_c2.text()) |
| | |
| | |
| | analyzer = LinearComponentField() |
| | x, y = sp.symbols('x y') |
| | |
| | |
| | Vx = a1*x + b1*y + c1 |
| | Vy = a2*x + b2*y + c2 |
| | |
| | output = f"Case 2 Analysis:\n" |
| | output += f"Vector Field: F(x,y) = [{Vx}, {Vy}]\n\n" |
| | |
| | |
| | is_gradient = analyzer.check_gradient_condition_for_specific(Vx, Vy) |
| | output += f"Gradient Field Condition: ∂P/∂y = ∂Q/∂x\n" |
| | output += f" ∂P/∂y = {sp.diff(Vx, y)}\n" |
| | output += f" ∂Q/∂x = {sp.diff(Vy, x)}\n" |
| | output += f" Condition satisfied? {is_gradient}\n\n" |
| | |
| | if is_gradient: |
| | |
| | phi = analyzer.find_potential_for_specific_field(Vx, Vy) |
| | output += f"Potential Function: φ(x,y) = {sp.simplify(phi)}\n\n" |
| | |
| | |
| | is_valid, diff_x, diff_y = analyzer.verify_potential(phi, Vx, Vy) |
| | output += f"Verification: ∇φ = F? {is_valid}\n" |
| | if not is_valid: |
| | output += f" ∂φ/∂x - Vx = {diff_x}\n" |
| | output += f" ∂φ/∂y - Vy = {diff_y}\n" |
| | else: |
| | output += "This field is not a gradient field. No potential function exists.\n" |
| | |
| | self.case2_output.setPlainText(output) |
| | self.statusBar().showMessage('Case 2 analysis completed') |
| | |
| | except Exception as e: |
| | self.case2_output.setPlainText(f"Error: {e}") |
| | self.statusBar().showMessage(f'Error in Case 2 analysis: {e}') |
| | |
| | def show_symbolic_case2(self): |
| | """Show symbolic analysis for Case 2""" |
| | self.case2_output.clear() |
| | |
| | try: |
| | analyzer = LinearComponentField() |
| | |
| | output = "Symbolic Analysis for Case 2:\n\n" |
| | |
| | |
| | condition = analyzer.get_gradient_condition() |
| | output += f"Gradient Field Condition: {condition} = 0\n" |
| | output += "This means: a₂ = b₁ for the general linear field\n\n" |
| | |
| | |
| | output += "Specific Gradient Cases:\n" |
| | examples = analyzer.get_specific_gradient_cases() |
| | for case_name, (Vx, Vy, phi) in examples.items(): |
| | output += f"{case_name}:\n" |
| | output += f" F(x,y) = [{Vx}, {Vy}]\n" |
| | output += f" φ(x,y) = {phi}\n\n" |
| | |
| | |
| | output += "Exact Forms from Case Study:\n" |
| | output_stream = io.StringIO() |
| | with redirect_stdout(output_stream): |
| | analyzer.demonstrate_case_study_forms() |
| | output += output_stream.getvalue() |
| | |
| | self.case2_output.setPlainText(output) |
| | self.statusBar().showMessage('Symbolic Case 2 analysis completed') |
| | |
| | except Exception as e: |
| | self.case2_output.setPlainText(f"Error: {e}") |
| | self.statusBar().showMessage(f'Error in symbolic Case 2 analysis: {e}') |
| | |
| | def check_gradient_condition(self): |
| | """Check only the gradient condition for Case 2""" |
| | try: |
| | |
| | a1 = float(self.case2_a1.text()) |
| | b1 = float(self.case2_b1.text()) |
| | a2 = float(self.case2_a2.text()) |
| | |
| | |
| | condition_satisfied = abs(a2 - b1) < 1e-10 |
| | |
| | if condition_satisfied: |
| | message = f"✓ Gradient condition satisfied: a₂ ({a2}) = b₁ ({b1})" |
| | QMessageBox.information(self, "Gradient Condition", message) |
| | else: |
| | message = f"✗ Gradient condition not satisfied: a₂ ({a2}) ≠ b₁ ({b1})" |
| | QMessageBox.warning(self, "Gradient Condition", message) |
| | |
| | except Exception as e: |
| | QMessageBox.critical(self, "Error", f"Error checking gradient condition: {e}") |
| | |
| | def run_case1_examples(self): |
| | """Run Case 1 numerical examples""" |
| | self.examples_output.clear() |
| | |
| | output = io.StringIO() |
| | with redirect_stdout(output): |
| | try: |
| | numerical_examples = NumericalExamples() |
| | numerical_examples.run_case1_examples() |
| | self.statusBar().showMessage('Case 1 examples completed') |
| | except Exception as e: |
| | print(f"Error running Case 1 examples: {e}") |
| | self.statusBar().showMessage(f'Error: {e}') |
| | |
| | self.examples_output.setPlainText(output.getvalue()) |
| | |
| | def run_case2_examples(self): |
| | """Run Case 2 numerical examples""" |
| | self.examples_output.clear() |
| | |
| | output = io.StringIO() |
| | with redirect_stdout(output): |
| | try: |
| | numerical_examples = NumericalExamples() |
| | numerical_examples.run_case2_examples() |
| | self.statusBar().showMessage('Case 2 examples completed') |
| | except Exception as e: |
| | print(f"Error running Case 2 examples: {e}") |
| | self.statusBar().showMessage(f'Error: {e}') |
| | |
| | self.examples_output.setPlainText(output.getvalue()) |
| | |
| | def run_all_examples(self): |
| | """Run all numerical examples""" |
| | self.examples_output.clear() |
| | |
| | output = io.StringIO() |
| | with redirect_stdout(output): |
| | try: |
| | numerical_examples = NumericalExamples() |
| | print("=" * 60) |
| | print("NUMERICAL EXAMPLES VERIFICATION") |
| | print("=" * 60) |
| | numerical_examples.run_case1_examples() |
| | numerical_examples.run_case2_examples() |
| | self.statusBar().showMessage('All examples completed') |
| | except Exception as e: |
| | print(f"Error running examples: {e}") |
| | self.statusBar().showMessage(f'Error: {e}') |
| | |
| | self.examples_output.setPlainText(output.getvalue()) |
| |
|
| |
|
| | def main(): |
| | app = QApplication(sys.argv) |
| | |
| | |
| | app.setStyle('Fusion') |
| | |
| | |
| | window = GradientFieldApp() |
| | window.show() |
| | |
| | |
| | sys.exit(app.exec_()) |
| |
|
| |
|
| | if __name__ == '__main__': |
| | main() |