added graphs
[pde-python.git] / gui.py
blob415e628616cec61209c7472d7cab977c7b594de0
1 #-*- coding: utf-8
3 # Политика префиксов в именах
4 # QLineEdit - edit_
5 # QLabel - label_
6 # QPushButton - button_
9 import sys, os
11 from PyQt4.QtCore import *
12 from PyQt4.QtGui import *
14 import matplotlib
15 from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
16 from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
17 from matplotlib.figure import Figure
19 import numpy as np
21 from grid import ExplicitSolver, ImplicitSolver, norm
22 try:
23 from waves import Exm, setParameters
24 except ImportError:
25 from third import Exm, setParameters
26 import const as co
29 ABOUT_IMAGE = 'about.jpg'
30 #IMAGE_WIDTH = 500
31 #IMAGE_HEIGHT = 500
33 ABOUT_TEXT = u'Курсовую работу выполнили:<br />студенты группы 6407<br /><b>Каранашев Мухамед</b><br /><b>Гайдель Андрей</b>'
34 ABOUT_TEXT_WIDTH = 300
37 def split_number(x):
38 return ('%g' % x).split('e')
40 def normal(x):
41 return np.float64('1e' + split_number(x)[1])
43 class Dummy(object):
44 pass
46 class AppForm(QMainWindow):
48 def __init__(self, parent=None):
49 QMainWindow.__init__(self, parent)
50 self.setWindowTitle(u'Курсовой проект')
52 self.data = Dummy()
53 self.data.counter_sol = self.data.counter_res = 1
55 self.create_main_frame()
56 self.setWindowState(Qt.WindowMaximized)
58 self.on_grid_change()
60 # self.test_graph()
62 def create_main_frame(self):
63 self.main_frame = QWidget()
64 self.init_work_frame()
65 self.init_param_frame()
67 self.splitter = QSplitter()
68 self.splitter.addWidget(self.param_frame)
70 self.splitter.addWidget(self.work_frame)
71 self.main_layout = QGridLayout(self.main_frame)
72 # self.main_layout.addWidget(self.param_frame, 0, 0)
73 # self.main_layout.addWidget(self.work_frame, 0, 1)
74 self.main_layout.addWidget(self.splitter)
75 self.setCentralWidget(self.main_frame)
77 def init_param_frame(self):
78 self.param_frame = QWidget()
79 param_group = QGroupBox(u"&Параметры")
80 param_layout = QGridLayout(self.param_frame)
81 param_layout.addWidget(param_group, 0, 0)
83 self.edit_LY = QLineEdit(str(co.LY))
84 self.edit_LY.setMinimumWidth(40)
85 self.edit_LZ = QLineEdit(str(co.LZ))
86 self.edit_LZ.setMinimumWidth(40)
87 self.edit_C = QLineEdit(str(co.C))
88 self.edit_C.setMinimumWidth(40)
89 self.edit_LAMBDA = QLineEdit(str(co.LAMBDA))
90 self.edit_LAMBDA.setMinimumWidth(40)
91 self.edit_T = QLineEdit('1e-14')
92 self.edit_dim_y = QLineEdit(str(50))
93 self.edit_dim_z = QLineEdit(str(50))
95 pg_layout = QFormLayout(param_group)
96 pg_layout.addRow(u'Ширина ly', self.edit_LY)
97 pg_layout.addRow(u'Высота lz', self.edit_LZ)
98 pg_layout.addRow(u'Скорость C', self.edit_C)
99 pg_layout.addRow(u'Волна λ', self.edit_LAMBDA)
100 pg_layout.addRow(u'Момент T', self.edit_T)
101 pg_layout.addRow(u'Размер по y (I)', self.edit_dim_y)
102 pg_layout.addRow(u'Размер по z (J)', self.edit_dim_z)
103 self.param_frame.setMaximumWidth(250)
105 self.connect(self.edit_LY, SIGNAL("returnPressed()"), self.on_grid_change)
106 self.connect(self.edit_LZ, SIGNAL("returnPressed()"), self.on_grid_change)
107 self.connect(self.edit_dim_y, SIGNAL("returnPressed()"), self.on_grid_change)
108 self.connect(self.edit_dim_z, SIGNAL("returnPressed()"), self.on_grid_change)
110 bu_group = QWidget()
111 bu_layout = QVBoxLayout(bu_group)
112 save_solution = QPushButton("Save solution")
113 save_research = QPushButton("Save research")
114 self.connect(save_solution, SIGNAL("clicked()"), self.save_solution)
115 self.connect(save_research, SIGNAL("clicked()"), self.save_research)
116 bu_layout.addWidget(save_solution)
117 bu_layout.addWidget(save_research)
118 param_layout.addWidget(bu_group, 3, 0)
120 def save_solution(self):
121 base = os.path.join('graph', 'solution', str(self.data.counter_sol))
122 self.z_fig.savefig(base + '.png')
123 print 'saved', base + '.png'
124 self.z_fig.savefig(base + '.eps')
125 print 'saved', base + '.eps'
126 self.data.counter_sol += 1
128 def save_research(self):
129 base = os.path.join('graph', 'research', str(self.data.counter_res))
130 self.n_fig.savefig(path + '.png')
131 print 'saved', base + '.png'
132 self.n_fig.savegif(path + '.eps')
133 print 'saved', base + '.eps'
134 self.data.counter_res += 1
136 def _make_analytic(self):
137 a_group = QGroupBox(u"Аналитическое решение")
138 a_group.setCheckable(True)
139 a_layout = QFormLayout(a_group)
141 self.edit_length = QLineEdit(str(500))
142 a_layout.addRow(u"Элементов ряда", self.edit_length)
143 self.edit_length.setMaximumWidth(100)
145 return a_group
147 def _make_explicit(self):
148 e_group = QGroupBox(u"Явная схема")
149 e_group.setCheckable(True)
150 e_group.setChecked(False)
151 e_layout = QFormLayout(e_group)
152 self.edit_exp_step_t = QLineEdit()
153 e_layout.addRow(u"Шаг по t", self.edit_exp_step_t)
155 return e_group
157 def _make_implicit(self):
158 i_group = QGroupBox(u"Неявная схема")
159 i_group.setCheckable(True)
160 i_group.setChecked(False)
161 i_layout = QFormLayout(i_group)
162 self.edit_imp_step_t = QLineEdit()
163 i_layout.addRow(u"Шаг по t", self.edit_imp_step_t)
165 return i_group
167 def _make_t_norm(self):
168 t_group = QGroupBox(u'Ось T')
169 t_layout = QFormLayout(t_group)
171 self.edit_k_start = QLineEdit(str(10))
172 self.edit_k_end = QLineEdit(str(100))
173 self.edit_k_step = QLineEdit(str(10))
174 self.edit_k_M = QLineEdit(str(600))
175 self.t_norm_button = QPushButton(u'Пуск')
176 self.connect(self.t_norm_button, SIGNAL("clicked()"), self.on_test_ht)
177 t_layout.addRow(u'Мин. узлов', self.edit_k_start)
178 t_layout.addRow(u'Макс. узлов', self.edit_k_end)
179 t_layout.addRow(u'Шаг', self.edit_k_step)
180 t_layout.addRow(u'Ряд', self.edit_k_M)
181 t_layout.addRow(self.t_norm_button)
183 return t_group
186 def _make_y_norm(self):
187 y_group = QGroupBox(u"Ось Y")
188 y_layout = QFormLayout(y_group)
190 self.edit_y_start = QLineEdit('10')
191 self.edit_y_end = QLineEdit('100')
192 self.edit_y_step = QLineEdit('10')
193 self.edit_y_ht = QLineEdit('1e-16')
194 self.edit_y_M = QLineEdit(str(600))
195 self.y_norm_button = QPushButton(u'Пуск')
196 self.connect(self.y_norm_button, SIGNAL("clicked()"), self.on_test_hy)
197 y_layout.addRow(u'Мин. узлов', self.edit_y_start)
198 y_layout.addRow(u'Макс. узлов', self.edit_y_end)
199 y_layout.addRow(u'Шаг', self.edit_y_step)
200 y_layout.addRow(u'ht', self.edit_y_ht)
201 y_layout.addRow(u'Ряд', self.edit_y_M)
202 y_layout.addRow(self.y_norm_button)
204 return y_group
206 def _make_z_norm(self):
207 z_group = QGroupBox(u"Ось Z")
208 z_layout = QFormLayout(z_group)
210 self.edit_z_start = QLineEdit('10')
211 self.edit_z_end = QLineEdit('100')
212 self.edit_z_step = QLineEdit('10')
213 self.edit_z_ht = QLineEdit('1e-16')
214 self.edit_z_M = QLineEdit(str(600))
215 self.z_norm_button = QPushButton(u'Пуск')
216 self.connect(self.z_norm_button, SIGNAL("clicked()"), self.on_test_hz)
217 z_layout.addRow(u'Мин. узлов', self.edit_z_start)
218 z_layout.addRow(u'Макс. узлов', self.edit_z_end)
219 z_layout.addRow(u'Шаг', self.edit_z_step)
220 z_layout.addRow(u'ht', self.edit_z_ht)
221 z_layout.addRow(u'Ряд', self.edit_z_M)
222 z_layout.addRow(self.z_norm_button)
224 return z_group
226 def _set_solver(self, t):
227 if t:
228 self.Solver = ExplicitSolver
229 else:
230 self.Solver = ImplicitSolver
231 print self.Solver
233 def _make_norm_frame(self):
234 self.norm_frame = QWidget()
235 self.n_fig = Figure((5.0, 5.0), dpi = self.dpi)
236 self.n_canvas = FigureCanvas(self.n_fig)
237 self.n_canvas.setParent(self.main_frame)
238 self.n_axes = self.n_fig.add_axes([.1, .1, .8, .8])
239 n_layout = QGridLayout(self.norm_frame)
240 n_layout.addWidget(self.n_canvas, 0, 0)
241 n_toolbar = NavigationToolbar(self.n_canvas, self.norm_frame)
242 n_layout.addWidget(n_toolbar, 1, 0)
244 scheme_type_frame = QWidget()
245 scheme_type_layout = QGridLayout(scheme_type_frame)
246 self.exp_radio_button = QRadioButton(u'Явная схема', scheme_type_frame)
247 self.imp_radio_button = QRadioButton(u'Неявная схема', scheme_type_frame)
248 self.connect(self.exp_radio_button, SIGNAL("toggled(bool)"), self._set_solver)
249 self.exp_radio_button.setChecked(True)
250 scheme_type_layout.addWidget(self.exp_radio_button, 0, 0)
251 scheme_type_layout.addWidget(self.imp_radio_button, 0, 1)
253 n_layout.addWidget(scheme_type_frame, 2, 0)
255 n_param_frame = QWidget()
256 n_param_layout = QGridLayout(n_param_frame)
257 n_param_layout.addWidget(self._make_t_norm(), 0, 0)
258 n_param_layout.addWidget(self._make_y_norm(), 0, 1)
259 n_param_layout.addWidget(self._make_z_norm(), 0, 2)
260 n_layout.addWidget(n_param_frame, 3, 0)
262 def _make_about_frame(self):
263 about_frame = QWidget()
264 lay = QHBoxLayout(about_frame)
265 about_image = QImage(ABOUT_IMAGE)
266 image_label = QLabel()
267 image_label.setPixmap(QPixmap.fromImage(about_image))
268 about_label = QLabel(ABOUT_TEXT)
269 about_label.setMinimumWidth(ABOUT_TEXT_WIDTH)
270 lay.addWidget(image_label)
271 lay.addWidget(about_label)
273 return about_frame
275 def init_work_frame(self):
276 self.work_frame = QTabWidget()
278 self.dpi = 75
279 self.z_fig = Figure((5.0, 5.0), dpi = self.dpi)
280 self.z_canvas = FigureCanvas(self.z_fig)
281 self.z_canvas.setParent(self.main_frame)
282 self.z_axes = self.z_fig.add_axes([.1, .1, .8, .8])
284 self.graph_frame = QWidget()
285 graph_layout = QGridLayout(self.graph_frame)
286 graph_layout.addWidget(self.z_canvas, 0, 0, 1, 1)
288 self.mpl_toolbar = NavigationToolbar(self.z_canvas, self.graph_frame)
289 # self.mpl_toolbar.setOrientation(Qt.Vertical)
290 graph_layout.addWidget(self.mpl_toolbar, 1, 0, 1, 1)
292 scheme_frame = QWidget()
293 scheme_layout = QGridLayout(scheme_frame)
294 self.a_group = self._make_analytic()
295 self.exp_group = self._make_explicit()
296 self.imp_group = self._make_implicit()
297 scheme_layout.addWidget(self.a_group, 0, 0, 1, 1)
298 scheme_layout.addWidget(self.exp_group, 0, 1, 1, 1)
299 scheme_layout.addWidget(self.imp_group, 0, 2, 1, 1)
301 self.button_scheme_run = QPushButton(u'Пуск')
302 self.connect(self.button_scheme_run, SIGNAL("clicked()"), self.on_scheme_run)
303 self.button_scheme_run.setFocus(Qt.ActiveWindowFocusReason)
305 graph_layout.addWidget(scheme_frame, 2, 0)
306 graph_layout.addWidget(self.button_scheme_run, 3, 0)
308 self._make_norm_frame()
310 self.about_frame = self._make_about_frame()
312 self.work_frame.addTab(self.graph_frame, u"&Разностная схема")
313 self.work_frame.addTab(self.norm_frame, u"&Исследование аппроксимации")
314 self.work_frame.addTab(self.about_frame, u"&О программе")
316 def on_test_ht(self):
317 print self.Solver
319 try:
320 ly, lz, c, lambda_, t = self._parse_args()
321 I, J = self._parse_grid()
322 k_min = int(str(self.edit_k_start.text()))
323 k_max = int(str(self.edit_k_end.text()))
324 k_step = int(str(self.edit_k_step.text()))
325 M = int(str(self.edit_k_M.text()))
326 except ValueError:
327 QMessageBox.critical(
328 self,
329 u'Ошибка',
330 u'Параметры введены в неверном формате.<br />Пожалуйста, исправьте их и повторите.')
331 return
333 x_vals = []
334 y_vals = []
335 hz = lz / J
336 hy = ly / I
338 if not co.test_exp_stable(ly/I, lz/J, t / k_min):
339 warn = QMessageBox.warning(
340 self,
341 u'Явная схема',
342 u'С такими параметрами система может быть неустойчива!<br />Вы уверены, что хотите продолжить?',
343 QMessageBox.Yes | QMessageBox.No)
344 if (warn == QMessageBox.No):
345 return
347 for k_cur in xrange(k_min, k_max + 1, k_step):
348 ht = t / k_cur
349 print k_cur, ht
350 x_vals.append(ht)
351 solver = self.Solver(I, J, t, ht, ly=ly, lz=lz, lambda_=lambda_, C=c)
352 u = solver.solve()
353 for i in xrange(u.shape[0]):
354 for j in xrange(u.shape[1]):
355 u[i, j] -= Exm(i * hy, j * hz, t, M)
356 y_vals.append(np.max(np.abs(u)))
358 self.n_axes.clear()
359 line, = self.n_axes.plot(x_vals, y_vals, '.-')
361 self.n_axes.grid(True)
362 self.n_axes.set_xlabel(u'ht')
363 self.n_axes.set_ylabel(u'err')
364 self.n_canvas.draw()
366 def on_test_hy(self):
367 try:
368 ly, lz, c, lambda_, t = self._parse_args()
369 I, J = self._parse_grid()
370 i_min = int(str(self.edit_y_start.text()))
371 i_max = int(str(self.edit_y_end.text()))
372 i_step = int(str(self.edit_y_step.text()))
373 ht = np.float64(str(self.edit_y_ht.text()))
374 M = int(str(self.edit_y_M.text()))
375 except ValueError:
376 QMessageBox.critical(
377 self,
378 u'Ошибка',
379 u'Параметры введены в неверном формате.<br />Пожалуйста, исправьте их и повторите.')
380 return
382 x_vals = []
383 y_vals = []
384 hz = lz / J
386 if not co.test_exp_stable(ly/i_max, lz/J, ht):
387 warn = QMessageBox.warning(
388 self,
389 u'Явная схема',
390 u'С такими параметрами система может быть неустойчива!<br />Вы уверены, что хотите продолжить?',
391 QMessageBox.Yes | QMessageBox.No)
392 if (warn == QMessageBox.No):
393 return
395 for i_cur in xrange(i_min, i_max + 1, i_step):
396 hy = ly / i_cur
397 print i_cur, hy
398 x_vals.append(hy)
399 solver = self.Solver(i_cur, J, t, ht, ly=ly, lz=lz, lambda_=lambda_, C=c)
400 u = solver.solve()
401 for i in xrange(u.shape[0]):
402 for j in xrange(u.shape[1]):
403 u[i, j] -= Exm(i * hy, j * hz, t, M)
404 y_vals.append(np.max(np.abs(u)))
406 self.n_axes.clear()
407 line, = self.n_axes.plot(x_vals, y_vals, '.-')
409 self.n_axes.grid(True)
410 self.n_axes.set_xlabel(u'hy')
411 self.n_axes.set_ylabel(u'err')
412 self.n_canvas.draw()
414 def on_test_hz(self):
415 try:
416 ly, lz, c, lambda_, t = self._parse_args()
417 I, J = self._parse_grid()
418 j_min = int(str(self.edit_z_start.text()))
419 j_max = int(str(self.edit_z_end.text()))
420 j_step = int(str(self.edit_z_step.text()))
421 ht = np.float64(str(self.edit_z_ht.text()))
422 M = int(str(self.edit_z_M.text()))
423 except ValueError:
424 QMessageBox.critical(
425 self,
426 u'Ошибка',
427 u'Параметры введены в неверном формате.<br />Пожалуйста, исправьте их и повторите.')
428 return
430 x_vals = []
431 y_vals = []
432 hy = ly / I
434 if not co.test_exp_stable(ly/I, lz/j_max, ht):
435 warn = QMessageBox.warning(
436 self,
437 u'Явная схема',
438 u'С такими параметрами система может быть неустойчива!<br />Вы уверены, что хотите продолжить?',
439 QMessageBox.Yes | QMessageBox.No)
440 if (warn == QMessageBox.No):
441 return
443 for j_cur in xrange(j_min, j_max + 1, j_step):
444 hz = lz / j_cur
445 print j_cur, hz
446 x_vals.append(hz)
447 solver = self.Solver(I, j_cur, t, ht, ly=ly, lz=lz, lambda_=lambda_, C=c)
448 u = solver.solve()
449 for i in xrange(u.shape[0]):
450 for j in xrange(u.shape[1]):
451 u[i, j] -= Exm(i * hy, j * hz, t, M)
452 y_vals.append(np.max(np.abs(u)))
454 self.n_axes.clear()
455 line, = self.n_axes.plot(x_vals, y_vals, '.-')
457 self.n_axes.grid(True)
458 self.n_axes.set_xlabel(u'hz')
459 self.n_axes.set_ylabel(u'err')
460 self.n_canvas.draw()
462 def on_grid_change(self):
463 ly_str = unicode(self.edit_LY.text())
464 lz_str = unicode(self.edit_LZ.text())
465 ny_str = unicode(self.edit_dim_y.text())
466 nz_str = unicode(self.edit_dim_z.text())
468 ly = np.float64(ly_str)
469 lz = np.float64(lz_str)
470 ny = int(ny_str)
471 nz = int(nz_str)
472 hy = (ly / ny)
473 hz = (lz / nz)
474 h_exp = min(hy, hz) / (np.sqrt(2) * co.C)
475 h_imp = hy / co.C
476 exp_l = ("%g" % h_exp).split('e')
477 imp_l = ("%g" % h_imp).split('e')
478 ht_exp = '1e' + exp_l[1]
479 ht_imp = str(np.trunc(np.float64(imp_l[0]))) + 'e' + imp_l[1]
480 self.edit_exp_step_t.setText(ht_exp)
481 self.edit_imp_step_t.setText(ht_imp)
483 def clear_axes(self, axes):
484 axes.clear()
485 axes.grid(True)
486 axes.set_xlabel('z')
487 axes.set_ylabel('Ex')
489 def test_graph(self):
490 self.clear_axes(self.z_axes)
491 self.z_canvas.draw()
493 def _parse_a(self):
494 return int(unicode(self.edit_length.text()))
496 def _parse_grid(self):
497 I = int(unicode(self.edit_dim_y.text()))
498 J = int(unicode(self.edit_dim_z.text()))
499 return I, J
501 def _parse_exp(self):
502 s = unicode(self.edit_exp_step_t.text()).strip()
503 if s == '':
504 return None
505 return np.float64(s)
507 def _parse_imp(self):
508 s = unicode(self.edit_imp_step_t.text()).strip()
509 if s == '':
510 return None
511 return np.float64(s)
513 def _parse_args(self):
514 ly, lz, c, lambda_, t = [np.float64(unicode(p.text()).strip()) \
515 for p in [self.edit_LY, self.edit_LZ, self.edit_C, self.edit_LAMBDA, self.edit_T]]
516 return ly, lz, c, lambda_, t
518 def on_scheme_run(self):
519 is_analytic, is_explicit, is_implicit = [g.isChecked() \
520 for g in [self.a_group, self.exp_group, self.imp_group]]
522 if not (is_analytic or is_explicit or is_implicit):
523 return
525 cols = 0
526 if is_analytic:
527 cols += 1
528 if is_explicit:
529 cols += 1
530 if is_implicit:
531 cols += 1
533 exp_ht, imp_ht = None, None
535 try:
536 if is_analytic:
537 m = self._parse_a()
538 if is_explicit or is_implicit:
539 exp_ht = self._parse_exp()
540 imp_ht = self._parse_imp()
541 except ValueError:
542 QMessageBox.critical(
543 self,
544 u'Ошибка',
545 u'Параметры введены в неверном формате.<br />Пожалуйста, исправьте их и повторите.')
546 return
548 try:
549 ly, lz, c, lambda_, t = self._parse_args()
550 I, J = self._parse_grid()
551 except ValueError:
552 QMessageBox.critical(
553 self,
554 u'Ошибка',
555 u'Параметры введены в неверном формате.<br />Пожалуйста, исправьте их и повторите.')
556 return
558 if exp_ht is not None:
559 if not co.test_exp_stable(ly/I, lz/J, exp_ht):
560 warn = QMessageBox.warning(
561 self,
562 u'Явная схема',
563 u'С такими параметрами система может быть неустойчива!<br />Вы уверены, что хотите продолжить?',
564 QMessageBox.Yes | QMessageBox.No)
565 if (warn == QMessageBox.No):
566 return
568 if imp_ht is not None:
569 if not co.test_imp_stable(ly/I, imp_ht):
570 warn = QMessageBox.warning(
571 self,
572 u'Неявная схема',
573 u'С такими параметрами система может быть неустойчива!<br />Вы уверены, что хотите продолжить?',
574 QMessageBox.Yes | QMessageBox.No)
575 if (warn == QMessageBox.No):
576 return
578 self.data.z = np.linspace(0, lz, J + 1)
580 self.z_axes.clear()
581 lines = []
582 legs = []
583 if is_analytic:
584 setParameters(ly, lz, c, lambda_)
585 self.data.E_a = [Exm(ly / 2, z_, t, m) for z_ in self.data.z]
586 line, = self.z_axes.plot(self.data.z, self.data.E_a, color='red')
587 lines.append(line)
588 legs.append('Analytical')
589 if is_explicit:
590 solver = ExplicitSolver(I, J, t, exp_ht, ly=ly, lz=lz, lambda_=lambda_, C=c)
591 u = solver.solve()
592 self.data.E_exp = u[u.shape[0] / 2, :]
593 line, = self.z_axes.plot(self.data.z, self.data.E_exp, color='blue')
594 lines.append(line)
595 legs.append('Explicit scheme')
596 if is_implicit:
597 solver = ImplicitSolver(I, J, t, imp_ht, ly=ly, lz=lz, lambda_=lambda_, C=c)
598 u = solver.solve()
599 self.data.E_imp = u[u.shape[0] / 2, :]
600 line, = self.z_axes.plot(self.data.z, self.data.E_imp, color='green')
601 lines.append(line)
602 legs.append('Implicit scheme')
603 self.z_axes.grid(True)
604 self.z_axes.set_xlim(0, max(self.data.z))
605 emax = max(self.data.E_a)
606 self.z_axes.set_ylim(-1.5 * emax, 1.5 * emax)
607 self.z_axes.set_xlabel('z')
608 self.z_axes.set_ylabel('Ex')
609 self.z_axes.legend(lines, legs, loc='upper center', bbox_to_anchor=(0.5, 1.13), ncol=cols)
610 self.z_canvas.draw()