root/src/gapc/ui/tab_plot.cpp @ 06f244abd607a7c31b6ed64e2a2c378638e727d2

Revision 06f244abd607a7c31b6ed64e2a2c378638e727d2, 18.1 KB (checked in by David C. Lonie <loniedavid@…>, 13 months ago)

Added a preoptimization queue for MolecularXtals?.

  • Property mode set to 100644
Line 
1/**********************************************************************
2  TabPlot - Tab with interactive plot
3
4  Copyright (C) 2009-2011 by David Lonie
5
6  This library is free software; you can redistribute it and/or modify
7  it under the terms of the GNU Library General Public License as
8  published by the Free Software Foundation; either version 2.1 of the
9  License, or (at your option) any later version.
10
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 ***********************************************************************/
16
17#include <gapc/ui/tab_plot.h>
18
19#include <gapc/gapc.h>
20#include <gapc/ui/dialog.h>
21#include <gapc/structures/protectedcluster.h>
22
23#include <globalsearch/macros.h>
24#include <globalsearch/queuemanager.h>
25#include <globalsearch/tracker.h>
26
27#include <avogadro/glwidget.h>
28#include <avogadro/primitive.h>
29#include <avogadro/primitivelist.h>
30
31#include <QSettings>
32#include <QReadWriteLock>
33
34using namespace Avogadro;
35using namespace GlobalSearch;
36
37namespace GAPC {
38
39  TabPlot::TabPlot( GAPCDialog *parent, OptGAPC *p ) :
40    AbstractTab(parent, p),
41    m_plot_mutex(new QReadWriteLock()),
42    m_plotObject(0)
43  {
44    ui.setupUi(m_tab_widget);
45
46    // Plot setup
47    ui.plot_plot->setAntialiasing(true);
48    updatePlot();
49
50    // dialog connections
51    connect(m_dialog, SIGNAL(moleculeChanged(GlobalSearch::Structure*)),
52            this, SLOT(highlightPC(GlobalSearch::Structure*)));
53    connect(m_opt, SIGNAL(sessionStarted()),
54            this, SLOT(populatePCList()));
55    connect(m_opt, SIGNAL(readOnlySessionStarted()),
56            this, SLOT(populatePCList()));
57    connect(m_dialog->getGLWidget(), SIGNAL(mouseRelease(QMouseEvent*)),
58            this, SLOT(updatePlot()));
59
60    // Plot connections
61    connect(ui.push_refresh, SIGNAL(clicked()),
62            this, SLOT(refreshPlot()));
63    connect(ui.combo_xAxis, SIGNAL(currentIndexChanged(int)),
64            this, SLOT(refreshPlot()));
65    connect(ui.combo_yAxis, SIGNAL(currentIndexChanged(int)),
66            this, SLOT(refreshPlot()));
67    connect(ui.combo_plotType, SIGNAL(currentIndexChanged(int)),
68            this, SLOT(refreshPlot()));
69    connect(ui.combo_distHistPC, SIGNAL(currentIndexChanged(int)),
70            this, SLOT(refreshPlot()));
71    connect(ui.combo_distHistPC, SIGNAL(currentIndexChanged(int)),
72            this, SLOT(selectMoleculeFromIndex(int)));
73    connect(ui.cb_labelPoints, SIGNAL(toggled(bool)),
74            this, SLOT(updatePlot()));
75    connect(ui.combo_labelType, SIGNAL(currentIndexChanged(int)),
76            this, SLOT(updatePlot()));
77    connect(ui.cb_showDuplicates, SIGNAL(toggled(bool)),
78            this, SLOT(updatePlot()));
79    connect(ui.cb_showIncompletes, SIGNAL(toggled(bool)),
80            this, SLOT(updatePlot()));
81    connect(ui.plot_plot, SIGNAL(pointClicked(PlotPoint*)),
82            this, SLOT(selectMoleculeFromPlot(PlotPoint*)));
83    connect(ui.plot_plot, SIGNAL(pointClicked(PlotPoint*)),
84            this, SLOT(lockClearAndSelectPoint(PlotPoint*)));
85    connect(m_opt, SIGNAL(refreshAllStructureInfo()),
86            this, SLOT(refreshPlot()));
87    connect(m_opt, SIGNAL(refreshAllStructureInfo()),
88            this, SLOT(populatePCList()));
89    connect(m_opt->queue(), SIGNAL(structureUpdated(GlobalSearch::Structure*)),
90            this, SLOT(populatePCList()));
91    connect(m_opt->tracker(), SIGNAL(newStructureAdded(GlobalSearch::Structure*)),
92            this, SLOT(populatePCList()));
93    connect(m_opt->queue(), SIGNAL(structureUpdated(GlobalSearch::Structure*)),
94            this, SLOT(updatePlot()));
95    connect(m_opt->tracker(), SIGNAL(newStructureAdded(GlobalSearch::Structure*)),
96            this, SLOT(updatePlot()));
97
98    initialize();
99  }
100
101  TabPlot::~TabPlot()
102  {
103    delete m_plot_mutex;
104    // m_plotObject is deleted by the PlotWidget
105  }
106
107  void TabPlot::writeSettings(const QString &filename)
108  {
109    SETTINGS(filename);
110    const int VERSION = 1;
111    settings->beginGroup("gapc/plot/");
112    settings->setValue("version",         VERSION);
113    settings->setValue("x_label",         ui.combo_xAxis->currentIndex());
114    settings->setValue("y_label",         ui.combo_yAxis->currentIndex());
115    settings->setValue("showDuplicates",  ui.cb_showDuplicates->isChecked());
116    settings->setValue("showIncompletes", ui.cb_showIncompletes->isChecked());
117    settings->setValue("labelPoints",     ui.cb_labelPoints->isChecked());
118    settings->setValue("labelType",       ui.combo_labelType->currentIndex());
119    settings->setValue("plotType",        ui.combo_plotType->currentIndex());
120    settings->endGroup();
121
122    DESTROY_SETTINGS(filename);
123  }
124
125  void TabPlot::readSettings(const QString &filename)
126  {
127    SETTINGS(filename);
128    settings->beginGroup("gapc/plot/");
129    int loadedVersion = settings->value("version", 0).toInt();
130    ui.combo_xAxis->setCurrentIndex( settings->value("x_label", Structure_T).toInt());
131    ui.combo_yAxis->setCurrentIndex( settings->value("y_label", Enthalpy_T).toInt());
132    ui.cb_showDuplicates->setChecked( settings->value("showDuplicates", false).toBool());
133    ui.cb_showIncompletes->setChecked( settings->value("showIncompletes", false).toBool());
134    ui.cb_labelPoints->setChecked( settings->value("labelPoints", false).toBool());
135    ui.combo_labelType->setCurrentIndex( settings->value("labelType", Structure_L).toInt());
136    ui.combo_plotType->setCurrentIndex( settings->value("plotType", Trend_PT).toInt());
137    settings->endGroup();
138
139    // Update config data
140    switch (loadedVersion) {
141    case 0:
142    case 1:
143    default:
144      break;
145    }
146
147  }
148
149  void TabPlot::updateGUI()
150  {
151    switch (ui.combo_plotType->currentIndex()) {
152    case Trend_PT:
153    default:
154      ui.gb_distance->setEnabled(false);
155      ui.gb_trend->setEnabled(true);
156      break;
157    case DistHist_PT:
158      ui.gb_trend->setEnabled(false);
159      ui.gb_distance->setEnabled(true);
160      break;
161    }
162  }
163
164  void TabPlot::disconnectGUI() {
165    ui.push_refresh->disconnect();
166    ui.combo_xAxis->disconnect();
167    ui.combo_yAxis->disconnect();
168    ui.combo_plotType->disconnect();
169    ui.combo_distHistPC->disconnect();
170    ui.cb_labelPoints->disconnect();
171    ui.combo_labelType->disconnect();
172    ui.cb_showDuplicates->disconnect();
173    ui.cb_showIncompletes->disconnect();
174    ui.plot_plot->disconnect();
175    this->disconnect();
176    disconnect(m_dialog, 0, this, 0);
177    disconnect(m_opt, 0, this, 0);
178  }
179
180  void TabPlot::lockClearAndSelectPoint(PlotPoint *pp) {
181    m_plot_mutex->lockForRead();
182    ui.plot_plot->clearAndSelectPoint(pp);
183    m_plot_mutex->unlock();
184  }
185
186  void TabPlot::refreshPlot() {
187    //qDebug() << "TabPlot::refreshPlot() called";
188
189    // Reset connections
190    ui.plot_plot->disconnect(this);
191
192    // Set up plot object
193    updatePlot();
194
195    // Reset limits and connections.
196    if (ui.combo_plotType->currentIndex() != DistHist_PT) {
197      ui.plot_plot->scaleLimits();
198      connect(ui.plot_plot, SIGNAL(pointClicked(PlotPoint*)),
199              this, SLOT(selectMoleculeFromPlot(PlotPoint*)));
200      connect(ui.plot_plot, SIGNAL(pointClicked(PlotPoint*)),
201              this, SLOT(lockClearAndSelectPoint(PlotPoint*)));
202    }
203  }
204
205  void TabPlot::updatePlot()
206  {
207    updateGUI();
208    if (!m_opt) return;
209
210    // Make sure we have structures!
211    if (m_opt->tracker()->size() == 0) {
212      return;
213    }
214
215    // Lock plot mutex
216    m_plot_mutex->lockForWrite();
217
218    // Turn off updates
219    ui.plot_plot->blockSignals(true);
220
221    switch (ui.combo_plotType->currentIndex()) {
222    case Trend_PT:
223      plotTrends();
224      break;
225    case DistHist_PT:
226      plotDistHist();
227      break;
228    }
229
230    ui.plot_plot->blockSignals(false);
231
232    m_plot_mutex->unlock();
233  }
234
235  void TabPlot::plotTrends()
236  {
237    // Store current limits for later
238    QRectF oldDataRect = ui.plot_plot->dataRect();
239
240    // Clear old data...
241    ui.plot_plot->resetPlot();
242
243    m_plotObject = new PlotObject (Qt::red, PlotObject::Points, 4, PlotObject::Triangle);
244
245    double x, y;
246    int ind;
247    ProtectedCluster *pc;
248    PlotPoint *pp;
249    // Load config settings:
250    bool labelPoints            = ui.cb_labelPoints->isChecked();
251    bool showDuplicates         = ui.cb_showDuplicates->isChecked();
252    bool showIncompletes        = ui.cb_showIncompletes->isChecked();
253    LabelTypes labelType        = LabelTypes(ui.combo_labelType->currentIndex());
254    PlotAxes xAxis              = PlotAxes(ui.combo_xAxis->currentIndex());
255    PlotAxes yAxis              = PlotAxes(ui.combo_yAxis->currentIndex());
256
257    for (int i = 0; i < m_opt->tracker()->size(); i++) {
258      x = y = 0;
259      pc = qobject_cast<ProtectedCluster*>(m_opt->tracker()->at(i));
260      QReadLocker pcLocker (pc->lock());
261      // Don't plot removed structures or those who have not completed their first INCAR.
262      if ((pc->getStatus() != ProtectedCluster::Optimized && !showIncompletes)) {
263        if  (!(pc->getStatus() == ProtectedCluster::Duplicate && showDuplicates)) {
264          continue;
265        }
266      }
267
268      if  (pc->getStatus() == ProtectedCluster::Duplicate && !showDuplicates) {
269        continue;
270      }
271
272      if (pc->getStatus() == ProtectedCluster::Killed ||
273          pc->getStatus() == ProtectedCluster::Removed ||
274          fabs(pc->getEnthalpy()) <= 1e-50) {
275        continue;
276      }
277
278      // Get X/Y data
279      for (int j = 0; j < 2; j++) { // 0 = x, 1 = y
280        switch (j) {
281        case 0:         ind = xAxis; break;
282        default:        ind = yAxis; break;
283        }
284
285        switch (ind) {
286        case Structure_T:
287          switch (j) {
288          case 0:       x = i+1; break;
289          default:      y = i+1; break;
290          }
291          break;
292        case Generation_T:
293          switch (j) {
294          case 0:       x = pc->getGeneration(); break;
295          default:      y = pc->getGeneration(); break;
296          }
297          break;
298        case Enthalpy_T:
299          // Skip pcs that don't have enthalpy/energy set
300          if (pc->getEnergy() == 0.0 && !pc->hasEnthalpy()) continue;
301          switch (j) {
302          case 0:       x = pc->getEnthalpy(); break;
303          default:      y = pc->getEnthalpy(); break;
304          }
305          break;
306        }
307      }
308      pp = m_plotObject->addPoint(x,y);
309      // Store index for later lookup
310      pp->setCustomData(i);
311      // Set point label if requested
312      if (labelPoints) {
313        switch (labelType) {
314        case Enthalpy_L:
315          pp->setLabel(QString::number(pc->getEnthalpy(), 'g', 5));
316          break;
317        case Generation_L:
318          pp->setLabel(QString::number(pc->getGeneration()));
319          break;
320        case Structure_L:
321          pp->setLabel(QString::number(i));
322          break;
323        }
324      }
325    }
326
327    // Set axis labels
328    for (int j = 0; j < 2; j++) { // 0 = x, 1 = y
329      switch (j) {
330      case 0:   ind = ui.combo_xAxis->currentIndex(); break;
331      default:  ind = ui.combo_yAxis->currentIndex(); break;
332      }
333
334      QString label;
335      switch (ind) {
336      case Structure_T:
337        label = tr("Structure");
338        switch (j) {
339        case 0:         ui.plot_plot->axis(PlotWidget::BottomAxis)->setLabel(label); break;
340        default:        ui.plot_plot->axis(PlotWidget::LeftAxis)->setLabel(label); break;
341        }
342        break;
343      case Generation_T:
344        label = tr("Generation");
345        switch (j) {
346        case 0:         ui.plot_plot->axis(PlotWidget::BottomAxis)->setLabel(label); break;
347        default:        ui.plot_plot->axis(PlotWidget::LeftAxis)->setLabel(label); break;
348        }
349        break;
350      case Enthalpy_T:
351        label = tr("Enthalpy (eV)");
352        switch (j) {
353        case 0:         ui.plot_plot->axis(PlotWidget::BottomAxis)->setLabel(label); break;
354        default:        ui.plot_plot->axis(PlotWidget::LeftAxis)->setLabel(label); break;
355        }
356        break;
357      }
358    }
359
360    ui.plot_plot->addPlotObject(m_plotObject);
361
362    // Do not scale if m_plotObject is empty.
363    // If we have one point, set limits to something appropriate:
364    if (m_plotObject->points().size() == 1) {
365      double x = m_plotObject->points().at(0)->x();
366      double y = m_plotObject->points().at(0)->y();
367      ui.plot_plot->setDefaultLimits(x-1, x+1, y+1, y-1);
368    }
369    // For multiple points, let plotwidget handle it.
370    else if (m_plotObject->points().size() >= 2) {
371      // run scaleLimits to set the default limits, but then set the
372      // limits to the previous region
373      ui.plot_plot->scaleLimits();
374      ui.plot_plot->setLimits(oldDataRect.left(),
375                              oldDataRect.right(),
376                              oldDataRect.top(), // These are backwards from intuition,
377                              oldDataRect.bottom()); // but that's how Qt works...
378    }
379  }
380
381  void TabPlot::plotDistHist()
382  {
383    // Clear old data...
384    ui.plot_plot->resetPlot();
385
386    // Initialize vars
387    m_plotObject = new PlotObject (Qt::red, PlotObject::Bars);
388    double x, y;
389    PlotPoint *pp;
390    QList<double> d, f, f_temp;
391
392    // Determine pc
393    int ind = ui.combo_distHistPC->currentIndex();
394    if (ind < 0 || ind > m_opt->tracker()->size() - 1) {
395      ind = 0;
396    }
397    ProtectedCluster *pc = qobject_cast<ProtectedCluster*>(m_opt->tracker()->at(ind));
398
399    // Determine selected atoms, if any
400    QList<Primitive*> selected = m_dialog->getGLWidget()->selectedPrimitives().subList(Primitive::AtomType);
401
402    // Get histogram
403    // If no atoms selected...
404    if (selected.size() == 0) {
405      pc->lock()->lockForRead();
406      pc->getDefaultHistogram(&d, &f);
407      pc->lock()->unlock();
408    }
409    // If atoms are selected:
410    else {
411      pc->lock()->lockForRead();
412      for (int i = 0; i < selected.size(); i++) {
413        pc->generateIADHistogram(&d, &f_temp,
414                                 0, 15, .1,
415                                 qobject_cast<Atom*>(selected.at(i)));
416        if (f.isEmpty()) {
417          f = f_temp;
418        }
419        else {
420          for (int j = 0; j < f.size(); j++) {
421            f[j] += f_temp[j];
422          }
423        }
424      }
425      pc->lock()->unlock();
426    }
427
428    // Populate plot object
429    for (int i = 0; i < d.size(); i++) {
430      x = d.at(i);
431      y = f.at(i);
432      pp = m_plotObject->addPoint(x,y);
433    }
434
435    ui.plot_plot->axis(PlotWidget::BottomAxis)->setLabel(tr("Distance"));
436    ui.plot_plot->axis(PlotWidget::LeftAxis)->setLabel(tr("Count"));
437
438    ui.plot_plot->addPlotObject(m_plotObject);
439
440    // Set default limits
441    ui.plot_plot->scaleLimits();
442    ui.plot_plot->setDefaultLimits(0, 8, 0, ui.plot_plot->dataRect().bottom());
443  }
444
445  void TabPlot::populatePCList()
446  {
447    int ind = ui.combo_distHistPC->currentIndex();
448    ui.combo_distHistPC->blockSignals(true);
449    ui.combo_distHistPC->clear();
450    const QList<Structure*> *structures = m_opt->tracker()->list();
451    ProtectedCluster *pc;
452    QString s;
453    for (int i = 0; i < structures->size(); i++) {
454      pc = qobject_cast<ProtectedCluster*>(structures->at(i));
455      pc->lock()->lockForRead();
456      s.clear();
457      // index:
458      s.append(QString::number(i) + ": ");
459      // generation and ID:
460      s.append(pc->getIDString());
461      // disposition
462      switch (pc->getStatus()) {
463      case ProtectedCluster::Optimized:
464        s.append(" (o)");
465        break;
466      case ProtectedCluster::StepOptimized:
467      case ProtectedCluster::WaitingForOptimization:
468      case ProtectedCluster::Submitted:
469      case ProtectedCluster::InProcess:
470      case ProtectedCluster::Empty:
471      case ProtectedCluster::Restart:
472      case ProtectedCluster::Updating:
473      case ProtectedCluster::Preoptimizing:
474        s.append(" (p)");
475        break;
476      case ProtectedCluster::Error:
477        s.append(" (e)");
478        break;
479      case ProtectedCluster::Killed:
480      case ProtectedCluster::Removed:
481        s.append(" (k)");
482        break;
483      case ProtectedCluster::Duplicate:
484        s.append(" (d)");
485        break;
486      default: break;
487      }
488      ui.combo_distHistPC->addItem(s);
489      pc->lock()->unlock();
490    }
491    if (ind == -1) ind = 0;
492    ui.combo_distHistPC->setCurrentIndex(ind);
493    ui.combo_distHistPC->blockSignals(false);
494  }
495
496  void TabPlot::selectMoleculeFromPlot(PlotPoint *pp)
497  {
498    if (!pp) return;
499    int index = pp->customData().toInt();
500    selectMoleculeFromIndex(index);
501  }
502
503  void TabPlot::selectMoleculeFromIndex(int index)
504  {
505    if (index < 0 || index > m_opt->tracker()->size() - 1) {
506      index = 0;
507    }
508    if (m_opt->tracker()->size() == 0) {
509      return;
510    }
511    emit moleculeChanged(m_opt->tracker()->at(index));
512  }
513
514  void TabPlot::highlightPC(Structure *s)
515  {
516    ProtectedCluster *pc = qobject_cast<ProtectedCluster*>(s);
517
518    // Bail out if there is no plotobject in memory
519    if (!m_plotObject)
520      return;
521    QReadLocker plotLocker (m_plot_mutex);
522    pc->lock()->lockForRead();
523    uint gen = pc->getGeneration();
524    uint id  = pc->getIDNumber();
525    pc->lock()->unlock();
526    int ind;
527    ProtectedCluster *tpc;
528    for (int i = 0; i < m_opt->tracker()->size(); i++) {
529      tpc = qobject_cast<ProtectedCluster*>(m_opt->tracker()->at(i));
530      tpc->lock()->lockForRead();
531      uint tgen = tpc->getGeneration();
532      uint tid = tpc->getIDNumber();
533      tpc->lock()->unlock();
534      if ( tgen == gen &&
535           tid == id ) {
536        ind = i;
537        break;
538      }
539    }
540    if (ui.combo_plotType->currentIndex() == Trend_PT) {
541      PlotPoint* pp;
542      bool found = false;
543      QList<PlotPoint*> *points = new QList<PlotPoint*>(m_plotObject->points());
544      for (int i = 0; i < points->size(); i++) {
545        pp = points->at(i);
546        if (pp->customData().toInt() == ind) {
547          ui.plot_plot->blockSignals(true);
548          ui.plot_plot->clearAndSelectPoint(pp);
549          ui.plot_plot->blockSignals(false);
550          found = true;
551          break;
552        }
553      }
554      delete points;
555      if (!found) {
556        // If not found, clear selection
557        ui.plot_plot->blockSignals(true);
558        ui.plot_plot->clearSelection();
559        ui.plot_plot->blockSignals(false);
560      }
561    }
562    // Update structure combo
563    plotLocker.unlock();
564    ui.combo_distHistPC->blockSignals(true);
565    ui.combo_distHistPC->setCurrentIndex(ind);
566    ui.combo_distHistPC->blockSignals(false);
567    if (ui.combo_plotType->currentIndex() == DistHist_PT) {
568      refreshPlot();
569    }
570  }
571}
572
Note: See TracBrowser for help on using the browser.