TroglodyteDerivations's picture
Upload 22 files
4f1509e verified
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 the original script components
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 and main layout
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout(central_widget)
# Title
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)
# Create tab widget
self.tabs = QTabWidget()
main_layout.addWidget(self.tabs)
# Create tabs
self.create_analysis_tab()
self.create_case1_tab()
self.create_case2_tab()
self.create_numerical_examples_tab()
# Status bar
self.statusBar().showMessage('Ready')
def create_analysis_tab(self):
"""Tab for running the complete analysis"""
tab = QWidget()
layout = QVBoxLayout(tab)
# Description
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 analysis button
run_btn = QPushButton('Run Complete Analysis')
run_btn.clicked.connect(self.run_complete_analysis)
layout.addWidget(run_btn)
# Output area
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)
# Description
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)
# Input form
form_group = QGroupBox("Vector Field Parameters")
form_layout = QFormLayout(form_group)
# Component selection
self.case1_component = QComboBox()
self.case1_component.addItems(['x', 'y'])
form_layout.addRow("Constant Component:", self.case1_component)
# Constant value
self.case1_constant = QLineEdit()
self.case1_constant.setText('2')
form_layout.addRow("Constant Value:", self.case1_constant)
# Function for non-constant component
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)
# Buttons
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)
# Output area
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)
# Description
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)
# Input form
form_group = QGroupBox("Vector Field Parameters")
form_layout = QFormLayout(form_group)
# Coefficients for Vx = a1*x + b1*y + c1
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)
# Coefficients for Vy = a2*x + b2*y + c2
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)
# Buttons
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)
# Output area
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)
# Description
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)
# Buttons
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)
# Output area
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()
# Capture stdout to display in the text area
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:
# Get parameters from UI
component = self.case1_component.currentText()
constant = float(self.case1_constant.text())
function_str = self.case1_function.text()
# Create analyzer
analyzer = ConstantComponentField(component)
# Create vector field
x, y = sp.symbols('x y')
if component == 'x':
Vx = constant
Vy = sp.sympify(function_str)
else:
Vx = sp.sympify(function_str)
Vy = constant
# Find potential
phi = analyzer.find_potential_for_specific_field(Vx, Vy)
# Display results
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"
# Verify
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)
# Get symbolic results
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"
# Show specific cases
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:
# Get parameters from UI
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())
# Create analyzer
analyzer = LinearComponentField()
x, y = sp.symbols('x y')
# Create vector field
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"
# Check gradient condition
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:
# Find potential
phi = analyzer.find_potential_for_specific_field(Vx, Vy)
output += f"Potential Function: φ(x,y) = {sp.simplify(phi)}\n\n"
# Verify
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"
# Show gradient condition
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"
# Show specific gradient cases
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"
# Show case study forms
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:
# Get parameters from UI
a1 = float(self.case2_a1.text())
b1 = float(self.case2_b1.text())
a2 = float(self.case2_a2.text())
# Check condition
condition_satisfied = abs(a2 - b1) < 1e-10 # Account for floating point errors
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)
# Set application style
app.setStyle('Fusion')
# Create and show the main window
window = GradientFieldApp()
window.show()
# Start the event loop
sys.exit(app.exec_())
if __name__ == '__main__':
main()