TroglodyteDerivations commited on
Commit
0e051b9
·
verified ·
1 Parent(s): ac2d3ad

Upload 4 files

Browse files
Files changed (5) hide show
  1. .gitattributes +2 -0
  2. app.py +452 -0
  3. chapter5-6.pdf +3 -0
  4. output.mp4 +3 -0
  5. requirements.txt +3 -0
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ chapter5-6.pdf filter=lfs diff=lfs merge=lfs -text
37
+ output.mp4 filter=lfs diff=lfs merge=lfs -text
app.py ADDED
@@ -0,0 +1,452 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import numpy as np
3
+ import matplotlib.pyplot as plt
4
+ from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
5
+ from matplotlib.figure import Figure
6
+ from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
7
+ QHBoxLayout, QGroupBox, QLabel, QComboBox,
8
+ QDoubleSpinBox, QSpinBox, QPushButton, QTextEdit,
9
+ QTabWidget, QGridLayout, QProgressBar)
10
+ from PyQt5.QtCore import QThread, pyqtSignal
11
+ import random
12
+
13
+ class PSOThread(QThread):
14
+ update_signal = pyqtSignal(dict)
15
+ finished_signal = pyqtSignal(dict)
16
+
17
+ def __init__(self, problem_type, num_particles, max_iter, w, c1, c2):
18
+ super().__init__()
19
+ self.problem_type = problem_type
20
+ self.num_particles = num_particles
21
+ self.max_iter = max_iter
22
+ self.w = w
23
+ self.c1 = c1
24
+ self.c2 = c2
25
+ self.running = True
26
+
27
+ def run(self):
28
+ # Initialize particles based on problem type
29
+ if self.problem_type == "radiative_equilibrium":
30
+ bounds = [(-10, 10), (-10, 10)] # Temperature and density parameters
31
+ dim = 2
32
+ elif self.problem_type == "nuclear_reaction_rate":
33
+ bounds = [(0.1, 2.0), (1e-3, 1e-1)] # Temperature (T7) and density parameters
34
+ dim = 2
35
+ elif self.problem_type == "convective_stability":
36
+ bounds = [(0.1, 0.5), (0.1, 0.5), (0.1, 0.5)] # ∇_rad, ∇_ad, ∇_μ
37
+ dim = 3
38
+ elif self.problem_type == "opacity_optimization":
39
+ bounds = [(1e-3, 1e3), (1e4, 1e8)] # Density and temperature
40
+ dim = 2
41
+ else:
42
+ bounds = [(-5, 5), (-5, 5)]
43
+ dim = 2
44
+
45
+ # PSO initialization
46
+ particles = np.random.uniform([b[0] for b in bounds], [b[1] for b in bounds],
47
+ (self.num_particles, dim))
48
+ velocities = np.random.uniform(-1, 1, (self.num_particles, dim))
49
+ personal_best_positions = particles.copy()
50
+ personal_best_scores = np.array([self.fitness(p, self.problem_type) for p in particles])
51
+ global_best_index = np.argmin(personal_best_scores)
52
+ global_best_position = personal_best_positions[global_best_index]
53
+ global_best_score = personal_best_scores[global_best_index]
54
+
55
+ # PSO main loop
56
+ for iteration in range(self.max_iter):
57
+ if not self.running:
58
+ break
59
+
60
+ for i in range(self.num_particles):
61
+ # Update velocity
62
+ r1, r2 = random.random(), random.random()
63
+ velocities[i] = (self.w * velocities[i] +
64
+ self.c1 * r1 * (personal_best_positions[i] - particles[i]) +
65
+ self.c2 * r2 * (global_best_position - particles[i]))
66
+
67
+ # Update position
68
+ particles[i] += velocities[i]
69
+
70
+ # Apply bounds
71
+ for d in range(dim):
72
+ if particles[i, d] < bounds[d][0]:
73
+ particles[i, d] = bounds[d][0]
74
+ elif particles[i, d] > bounds[d][1]:
75
+ particles[i, d] = bounds[d][1]
76
+
77
+ # Evaluate fitness
78
+ current_fitness = self.fitness(particles[i], self.problem_type)
79
+
80
+ # Update personal best
81
+ if current_fitness < personal_best_scores[i]:
82
+ personal_best_positions[i] = particles[i].copy()
83
+ personal_best_scores[i] = current_fitness
84
+
85
+ # Update global best
86
+ if current_fitness < global_best_score:
87
+ global_best_position = particles[i].copy()
88
+ global_best_score = current_fitness
89
+
90
+ # Emit update signal
91
+ self.update_signal.emit({
92
+ 'iteration': iteration,
93
+ 'global_best': global_best_score,
94
+ 'position': global_best_position,
95
+ 'particles': particles.copy()
96
+ })
97
+
98
+ self.finished_signal.emit({
99
+ 'final_score': global_best_score,
100
+ 'final_position': global_best_position
101
+ })
102
+
103
+ def fitness(self, x, problem_type):
104
+ """Fitness function based on stellar physics problems from Chapter 5-6"""
105
+ if problem_type == "radiative_equilibrium":
106
+ # Optimize radiative temperature gradient (Eq. 5.18)
107
+ # We want to minimize deviation from ideal radiative equilibrium
108
+ T, rho = x[0], x[1]
109
+ # Simplified radiative equilibrium condition
110
+ radiative_flux = (T**3 / rho) if rho > 0 else 1e10
111
+ target_flux = 1.0 # Ideal normalized flux
112
+ return abs(radiative_flux - target_flux)
113
+
114
+ elif problem_type == "nuclear_reaction_rate":
115
+ # Optimize nuclear reaction rates (Eq. 6.29)
116
+ T7, density_param = x[0], x[1] # T7 = T/10^7 K
117
+ # Gamow peak-based reaction rate approximation
118
+ reaction_rate = (T7**(-2/3)) * np.exp(-1/T7**(1/3)) * density_param
119
+ target_rate = 0.5 # Optimal reaction rate
120
+ return abs(reaction_rate - target_rate)
121
+
122
+ elif problem_type == "convective_stability":
123
+ # Schwarzschild/Ledoux criterion optimization (Eq. 5.49, 5.50)
124
+ grad_rad, grad_ad, grad_mu = x[0], x[1], x[2]
125
+ # Stability requires: ∇_rad < ∇_ad - (χ_μ/χ_T)∇_μ
126
+ # For ideal gas: χ_μ = -1, χ_T = 1
127
+ stability_condition = grad_ad + grad_mu # Ledoux criterion
128
+ instability = max(0, grad_rad - stability_condition)
129
+ return instability # Minimize instability
130
+
131
+ elif problem_type == "opacity_optimization":
132
+ # Optimize opacity for efficient energy transport
133
+ rho, T = x[0], x[1]
134
+ # Kramers opacity approximation (Eq. 5.31, 5.32)
135
+ opacity = rho * T**(-3.5) if T > 0 else 1e10
136
+ # Target opacity range for efficient transport
137
+ target_opacity = 1.0
138
+ return abs(opacity - target_opacity)
139
+
140
+ else:
141
+ # Default sphere function
142
+ return sum(xi**2 for xi in x)
143
+
144
+ def stop(self):
145
+ self.running = False
146
+
147
+ class MplCanvas(FigureCanvas):
148
+ def __init__(self, parent=None, width=5, height=4, dpi=100):
149
+ self.fig = Figure(figsize=(width, height), dpi=dpi)
150
+ super().__init__(self.fig)
151
+ self.setParent(parent)
152
+
153
+ class PSOWindow(QMainWindow):
154
+ def __init__(self):
155
+ super().__init__()
156
+ self.pso_thread = None
157
+ self.init_ui()
158
+
159
+ def init_ui(self):
160
+ self.setWindowTitle("Stellar Physics PSO Optimizer - Chapter 5-6")
161
+ self.setGeometry(100, 100, 1200, 800)
162
+
163
+ central_widget = QWidget()
164
+ self.setCentralWidget(central_widget)
165
+ layout = QHBoxLayout(central_widget)
166
+
167
+ # Left panel - Controls
168
+ left_panel = QWidget()
169
+ left_layout = QVBoxLayout(left_panel)
170
+ left_panel.setMaximumWidth(400)
171
+
172
+ # Problem selection
173
+ problem_group = QGroupBox("Stellar Physics Optimization Problem")
174
+ problem_layout = QVBoxLayout(problem_group)
175
+
176
+ self.problem_combo = QComboBox()
177
+ self.problem_combo.addItems([
178
+ "Radiative Equilibrium",
179
+ "Nuclear Reaction Rate",
180
+ "Convective Stability",
181
+ "Opacity Optimization"
182
+ ])
183
+ problem_layout.addWidget(QLabel("Select Problem:"))
184
+ problem_layout.addWidget(self.problem_combo)
185
+
186
+ # Problem description
187
+ self.problem_desc = QTextEdit()
188
+ self.problem_desc.setMaximumHeight(150)
189
+ self.problem_desc.setReadOnly(True)
190
+ problem_layout.addWidget(QLabel("Problem Description:"))
191
+ problem_layout.addWidget(self.problem_desc)
192
+
193
+ left_layout.addWidget(problem_group)
194
+
195
+ # PSO parameters
196
+ pso_group = QGroupBox("PSO Parameters")
197
+ pso_layout = QGridLayout(pso_group)
198
+
199
+ pso_layout.addWidget(QLabel("Number of Particles:"), 0, 0)
200
+ self.num_particles = QSpinBox()
201
+ self.num_particles.setRange(10, 200)
202
+ self.num_particles.setValue(30)
203
+ pso_layout.addWidget(self.num_particles, 0, 1)
204
+
205
+ pso_layout.addWidget(QLabel("Max Iterations:"), 1, 0)
206
+ self.max_iter = QSpinBox()
207
+ self.max_iter.setRange(50, 1000)
208
+ self.max_iter.setValue(100)
209
+ pso_layout.addWidget(self.max_iter, 1, 1)
210
+
211
+ pso_layout.addWidget(QLabel("Inertia Weight (w):"), 2, 0)
212
+ self.w_spin = QDoubleSpinBox()
213
+ self.w_spin.setRange(0.1, 1.0)
214
+ self.w_spin.setValue(0.7)
215
+ self.w_spin.setSingleStep(0.1)
216
+ pso_layout.addWidget(self.w_spin, 2, 1)
217
+
218
+ pso_layout.addWidget(QLabel("Cognitive Coefficient (c1):"), 3, 0)
219
+ self.c1_spin = QDoubleSpinBox()
220
+ self.c1_spin.setRange(0.1, 3.0)
221
+ self.c1_spin.setValue(1.5)
222
+ self.c1_spin.setSingleStep(0.1)
223
+ pso_layout.addWidget(self.c1_spin, 3, 1)
224
+
225
+ pso_layout.addWidget(QLabel("Social Coefficient (c2):"), 4, 0)
226
+ self.c2_spin = QDoubleSpinBox()
227
+ self.c2_spin.setRange(0.1, 3.0)
228
+ self.c2_spin.setValue(1.5)
229
+ self.c2_spin.setSingleStep(0.1)
230
+ pso_layout.addWidget(self.c2_spin, 4, 1)
231
+
232
+ left_layout.addWidget(pso_group)
233
+
234
+ # Control buttons
235
+ self.run_button = QPushButton("Run PSO")
236
+ self.run_button.clicked.connect(self.run_pso)
237
+ left_layout.addWidget(self.run_button)
238
+
239
+ self.stop_button = QPushButton("Stop")
240
+ self.stop_button.clicked.connect(self.stop_pso)
241
+ self.stop_button.setEnabled(False)
242
+ left_layout.addWidget(self.stop_button)
243
+
244
+ # Progress
245
+ self.progress = QProgressBar()
246
+ left_layout.addWidget(self.progress)
247
+
248
+ # Results
249
+ results_group = QGroupBox("Results")
250
+ results_layout = QVBoxLayout(results_group)
251
+ self.results_text = QTextEdit()
252
+ self.results_text.setMaximumHeight(150)
253
+ results_layout.addWidget(self.results_text)
254
+ left_layout.addWidget(results_group)
255
+
256
+ layout.addWidget(left_panel)
257
+
258
+ # Right panel - Visualization
259
+ right_panel = QTabWidget()
260
+
261
+ # Convergence plot
262
+ self.convergence_canvas = MplCanvas(self, width=6, height=4, dpi=100)
263
+ self.convergence_ax = self.convergence_canvas.fig.add_subplot(111)
264
+ right_panel.addTab(self.convergence_canvas, "Convergence")
265
+
266
+ # Particle positions
267
+ self.particles_canvas = MplCanvas(self, width=6, height=4, dpi=100)
268
+ self.particles_ax = self.particles_canvas.fig.add_subplot(111)
269
+ right_panel.addTab(self.particles_canvas, "Particles")
270
+
271
+ # Fitness landscape
272
+ self.landscape_canvas = MplCanvas(self, width=6, height=4, dpi=100)
273
+ self.landscape_ax = self.landscape_canvas.fig.add_subplot(111)
274
+ right_panel.addTab(self.landscape_canvas, "Fitness Landscape")
275
+
276
+ layout.addWidget(right_panel)
277
+
278
+ # Update problem description
279
+ self.update_problem_desc()
280
+ self.problem_combo.currentTextChanged.connect(self.update_problem_desc)
281
+
282
+ def update_problem_desc(self):
283
+ problem = self.problem_combo.currentText()
284
+ descriptions = {
285
+ "Radiative Equilibrium":
286
+ "Optimize radiative temperature gradient (Eq. 5.18)\n"
287
+ "Minimize deviation from ideal radiative equilibrium conditions\n"
288
+ "Parameters: Temperature, Density",
289
+
290
+ "Nuclear Reaction Rate":
291
+ "Optimize thermonuclear reaction rates (Eq. 6.29)\n"
292
+ "Find optimal conditions for efficient energy generation\n"
293
+ "Based on Gamow peak theory\n"
294
+ "Parameters: Temperature (T7), Density parameter",
295
+
296
+ "Convective Stability":
297
+ "Apply Schwarzschild/Ledoux criteria (Eq. 5.49, 5.50)\n"
298
+ "Minimize convective instability in stellar layers\n"
299
+ "Parameters: ∇_rad, ∇_ad, ∇_μ",
300
+
301
+ "Opacity Optimization":
302
+ "Optimize opacity for efficient energy transport\n"
303
+ "Based on Kramers opacity law (Eq. 5.31)\n"
304
+ "Find optimal density-temperature conditions\n"
305
+ "Parameters: Density, Temperature"
306
+ }
307
+ self.problem_desc.setText(descriptions.get(problem, ""))
308
+
309
+ def run_pso(self):
310
+ if self.pso_thread and self.pso_thread.isRunning():
311
+ return
312
+
313
+ problem_map = {
314
+ "Radiative Equilibrium": "radiative_equilibrium",
315
+ "Nuclear Reaction Rate": "nuclear_reaction_rate",
316
+ "Convective Stability": "convective_stability",
317
+ "Opacity Optimization": "opacity_optimization"
318
+ }
319
+
320
+ problem_type = problem_map[self.problem_combo.currentText()]
321
+
322
+ self.pso_thread = PSOThread(
323
+ problem_type=problem_type,
324
+ num_particles=self.num_particles.value(),
325
+ max_iter=self.max_iter.value(),
326
+ w=self.w_spin.value(),
327
+ c1=self.c1_spin.value(),
328
+ c2=self.c2_spin.value()
329
+ )
330
+
331
+ self.pso_thread.update_signal.connect(self.update_plots)
332
+ self.pso_thread.finished_signal.connect(self.optimization_finished)
333
+
334
+ self.run_button.setEnabled(False)
335
+ self.stop_button.setEnabled(True)
336
+ self.progress.setValue(0)
337
+ self.progress.setMaximum(self.max_iter.value())
338
+
339
+ self.convergence_ax.clear()
340
+ self.particles_ax.clear()
341
+ self.landscape_ax.clear()
342
+
343
+ self.best_scores = []
344
+ self.iterations = []
345
+
346
+ self.pso_thread.start()
347
+
348
+ def stop_pso(self):
349
+ if self.pso_thread:
350
+ self.pso_thread.stop()
351
+ self.pso_thread.wait()
352
+ self.run_button.setEnabled(True)
353
+ self.stop_button.setEnabled(False)
354
+
355
+ def update_plots(self, data):
356
+ iteration = data['iteration']
357
+ best_score = data['global_best']
358
+ position = data['position']
359
+ particles = data['particles']
360
+
361
+ # Update convergence plot
362
+ self.best_scores.append(best_score)
363
+ self.iterations.append(iteration)
364
+
365
+ self.convergence_ax.clear()
366
+ self.convergence_ax.plot(self.iterations, self.best_scores, 'b-', linewidth=2)
367
+ self.convergence_ax.set_xlabel('Iteration')
368
+ self.convergence_ax.set_ylabel('Best Fitness')
369
+ self.convergence_ax.set_title('PSO Convergence')
370
+ self.convergence_ax.grid(True, alpha=0.3)
371
+ self.convergence_canvas.draw()
372
+
373
+ # Update particles plot (2D projection)
374
+ self.particles_ax.clear()
375
+ if particles.shape[1] >= 2:
376
+ self.particles_ax.scatter(particles[:, 0], particles[:, 1],
377
+ c='blue', alpha=0.6, s=20)
378
+ self.particles_ax.scatter([position[0]], [position[1]],
379
+ c='red', s=100, marker='*', label='Global Best')
380
+ self.particles_ax.set_xlabel('Parameter 1')
381
+ self.particles_ax.set_ylabel('Parameter 2')
382
+ self.particles_ax.set_title('Particle Positions')
383
+ self.particles_ax.legend()
384
+ self.particles_ax.grid(True, alpha=0.3)
385
+ self.particles_canvas.draw()
386
+
387
+ # Update fitness landscape for 2D problems
388
+ if particles.shape[1] == 2:
389
+ self.update_fitness_landscape(position, particles)
390
+
391
+ # Update progress
392
+ self.progress.setValue(iteration + 1)
393
+
394
+ # Update results
395
+ self.results_text.setText(
396
+ f"Iteration: {iteration + 1}\n"
397
+ f"Best Fitness: {best_score:.6f}\n"
398
+ f"Best Position: {position}\n"
399
+ )
400
+
401
+ def update_fitness_landscape(self, best_position, particles):
402
+ self.landscape_ax.clear()
403
+
404
+ # Create meshgrid for fitness landscape
405
+ x = np.linspace(-5, 5, 50)
406
+ y = np.linspace(-5, 5, 50)
407
+ X, Y = np.meshgrid(x, y)
408
+
409
+ # Calculate fitness for each point
410
+ Z = np.zeros_like(X)
411
+ for i in range(X.shape[0]):
412
+ for j in range(X.shape[1]):
413
+ Z[i, j] = self.pso_thread.fitness([X[i, j], Y[i, j]],
414
+ self.pso_thread.problem_type)
415
+
416
+ # Plot contour
417
+ contour = self.landscape_ax.contourf(X, Y, Z, levels=50, alpha=0.8)
418
+ self.landscape_ax.contour(X, Y, Z, levels=10, colors='black', alpha=0.3)
419
+
420
+ # Plot particles
421
+ self.landscape_ax.scatter(particles[:, 0], particles[:, 1],
422
+ c='white', s=20, alpha=0.7)
423
+ self.landscape_ax.scatter([best_position[0]], [best_position[1]],
424
+ c='red', s=100, marker='*', label='Global Best')
425
+
426
+ self.landscape_ax.set_xlabel('Parameter 1')
427
+ self.landscape_ax.set_ylabel('Parameter 2')
428
+ self.landscape_ax.set_title('Fitness Landscape')
429
+ self.landscape_canvas.draw()
430
+
431
+ def optimization_finished(self, data):
432
+ self.run_button.setEnabled(True)
433
+ self.stop_button.setEnabled(False)
434
+ self.progress.setValue(self.max_iter.value())
435
+
436
+ final_text = (
437
+ f"Optimization Completed!\n"
438
+ f"Final Fitness: {data['final_score']:.8f}\n"
439
+ f"Optimal Parameters: {data['final_position']}\n"
440
+ f"Total Iterations: {self.max_iter.value()}\n"
441
+ f"Number of Particles: {self.num_particles.value()}"
442
+ )
443
+ self.results_text.setText(final_text)
444
+
445
+ def main():
446
+ app = QApplication(sys.argv)
447
+ window = PSOWindow()
448
+ window.show()
449
+ sys.exit(app.exec_())
450
+
451
+ if __name__ == '__main__':
452
+ main()
chapter5-6.pdf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:19bf72d59f6eda512e30d9bb3994e79dd011f53f72214adc7d9690afb5bceffd
3
+ size 535618
output.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a7aad1c0c9d20d34f99b644b6685491cf31f56242dd1d73f3bb4b8fdbc7d18d1
3
+ size 14820093
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ pyqt5
2
+ matplotlib
3
+ numpy