1 /* Copyright (c) 2015  Gerald Knizia
2  *
3  * This file is part of the IboView program (see: http://www.iboview.org)
4  *
5  * IboView is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, version 3.
8  *
9  * IboView is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with bfint (LICENSE). If not, see http://www.gnu.org/licenses/
16  *
17  * Please see IboView documentation in README.txt for:
18  * -- A list of included external software and their licenses. The included
19  *    external software's copyright is not touched by this agreement.
20  * -- Notes on re-distribution and contributions to/further development of
21  *    the IboView software
22  */
23 
24 #include <QAbstractProxyModel>
25 #include <algorithm>
26 #include <math.h>
27 #include "CxVec3.h"
28 #include "Iv.h"
29 #include "IvDocument.h"
30 #include "IvTables.h"
31 #include "CtConstants.h"
32 #include "ui_TablesForm.h"
33 using std::sqrt;
34 
35 // // c/p'd from http://www.qtcentre.org/wiki/index.php?title=Transpose_proxy_model
36 // class FTransposeProxyModel : public QAbstractProxyModel
37 // {
38 // public:
39 //    FTransposeProxyModel(QObject *p = 0) : QAbstractProxyModel(p){}
40 //
41 //    QModelIndex mapFromSource( const QModelIndex & sourceIndex ) const{
42 //       return index(sourceIndex.column(), sourceIndex.row());
43 //    }
44 //    QModelIndex mapToSource( const QModelIndex & proxyIndex ) const{
45 //       return sourceModel()->index(proxyIndex.column(), proxyIndex.row());
46 //    }
47 //    QModelIndex index(int r, int c, const QModelIndex &index=QModelIndex()) const{
48 //       return createIndex(r,c);
49 //       IR_SUPPRESS_UNUSED_WARNING(index);
50 //    }
51 //    QModelIndex parent(const QModelIndex&) const {
52 //       return QModelIndex();
53 //    }
54 //    int rowCount(const QModelIndex &) const{
55 //       return sourceModel()->columnCount();
56 //    }
57 //    int columnCount(const QModelIndex &) const{
58 //       return sourceModel()->rowCount();
59 //    }
60 //    QVariant data(const QModelIndex &ind, int role) const {
61 //       return sourceModel()->data(mapToSource(ind), role);
62 //    }
63 // };
64 
65 // ^- hmmm.. this doesn't work. headerData arguments are wrong (section always supplied as 0),
66 //    and orientation is not patched up. maybe I just switch everything manually...
67 
68 
69 
70 
71 
72 
73 
74 
75 
FMeasure(FDocument * pDocument_,QString const & UnitName_,int nDigits_,double fAuToOutFactor_)76 FMeasure::FMeasure(FDocument *pDocument_, QString const &UnitName_, int nDigits_, double fAuToOutFactor_)
77    : m_pDocument(pDocument_), m_UnitName(UnitName_), m_nDigits(nDigits_), m_AuToOut(fAuToOutFactor_)
78 {
79 }
80 
~FMeasure()81 FMeasure::~FMeasure()
82 {
83 }
84 
UnitName() const85 QString FMeasure::UnitName() const
86 {
87    return m_UnitName;
88 }
89 
FmtValue(double f,uint Flags) const90 QString FMeasure::FmtValue(double f, uint Flags) const
91 {
92    if (0 != (Flags & FORMAT_ValueOnly))
93       return QString("%2").arg(f,0,'f',m_nDigits);
94    else
95       return QString("%1 = %2 %3").arg(Name()).arg(f,0,'f',m_nDigits).arg(UnitName());
96 }
97 
MeasureFrame(FFrame * pFrame,uint Flags) const98 QString FMeasure::MeasureFrame(FFrame *pFrame, uint Flags) const
99 {
100    FFrameMeasurePtrList
101       DummyList;
102 //    DummyList.push_back(FFramePtr(pFrame));
103    DummyList.push_back(pFrame);
104    FMeasureSet
105       Value;
106    MakeValues(Value, DummyList);
107    if (Value.size() != 1) {
108       IvNotify(NOTIFY_Error, IvFmt("Something went wrong while computing measure %1.", this->Name()));
109       return "!MEASURE-ERROR";
110    }
111    return FmtValue(Value[0], Flags);
112 }
113 
114 
115 
FMeasureBondLength(int iAt_,int jAt_,FDocument * pDocument_)116 FMeasureBondLength::FMeasureBondLength(int iAt_, int jAt_, FDocument *pDocument_)
117    : FMeasure(pDocument_,"pm",2,ct::ToAng*100.), m_iAt(iAt_), m_jAt(jAt_)
118 {}
119 
Name() const120 QString FMeasureBondLength::Name() const
121 {
122    return QString("r(%1--%2)").arg(m_pDocument->AtomLabel(m_iAt), m_pDocument->AtomLabel(m_jAt));
123 }
124 
MakeValues(FMeasureSet & FrameValues,FFrameMeasurePtrList & Frames) const125 void FMeasureBondLength::MakeValues(FMeasureSet &FrameValues, FFrameMeasurePtrList &Frames) const
126 {
127    FrameValues.clear();
128    FrameValues.reserve(Frames.size());
129 //    foreach(FFrameMeasurePtrList::value_type const *itFrame, Frames) {
130    FFrameMeasurePtrList::const_iterator itFrame;
131    _for_each(itFrame, Frames) {
132       ct::FAtomSet *pAtoms = (*itFrame)->pGetAtoms();
133       if (pAtoms && size_t(m_iAt) < pAtoms->size() && size_t(m_jAt) < pAtoms->size()) {
134          ct::FVector3
135             vI = (*pAtoms)[size_t(m_iAt)].vPos,
136             vJ = (*pAtoms)[size_t(m_jAt)].vPos;
137          FrameValues.push_back(m_AuToOut * Dist(vI, vJ));
138       } else {
139          FrameValues.push_back(0);
140       }
141    }
142 }
143 
144 // return angle between Left--Center and Center--Right (in radians)
Angle(ct::FVector3 const & Left,ct::FVector3 const & Center,ct::FVector3 const & Right)145 static double Angle(ct::FVector3 const &Left, ct::FVector3 const &Center, ct::FVector3 const &Right)
146 {
147    ct::FVector3
148       vA = Normalized(Left - Center),
149       vB = Normalized(Right - Center);
150    return std::acos(Dot(vA, vB));
151 }
152 
153 
FMeasureBondAngle(int iAt_,int jAt_,int kAt_,FDocument * pDocument_)154 FMeasureBondAngle::FMeasureBondAngle(int iAt_, int jAt_, int kAt_, FDocument *pDocument_)
155    : FMeasure(pDocument_,QString::fromWCharArray(L"\u00b0"),2,180./M_PI), m_iAt(iAt_), m_jAt(jAt_), m_kAt(kAt_)
156 {}
157 
Name() const158 QString FMeasureBondAngle::Name() const
159 {
160    return QString(QString::fromWCharArray(L"\u03b1(%1 | %2 | %3)")).arg(m_pDocument->AtomLabel(m_iAt), m_pDocument->AtomLabel(m_jAt), m_pDocument->AtomLabel(m_kAt));
161 }
162 
MakeValues(FMeasureSet & FrameValues,FFrameMeasurePtrList & Frames) const163 void FMeasureBondAngle::MakeValues(FMeasureSet &FrameValues, FFrameMeasurePtrList &Frames) const
164 {
165    FrameValues.clear();
166    FrameValues.reserve(Frames.size());
167 //    foreach(FFrameMeasurePtrList::value_type const *itFrame, Frames) {
168    FFrameMeasurePtrList::const_iterator itFrame;
169    _for_each(itFrame, Frames) {
170       ct::FAtomSet *pAtoms = (*itFrame)->pGetAtoms();
171       if (pAtoms && size_t(m_iAt) < pAtoms->size() && size_t(m_jAt) < pAtoms->size()) {
172          ct::FVector3
173             vI = (*pAtoms)[size_t(m_iAt)].vPos,
174             vJ = (*pAtoms)[size_t(m_jAt)].vPos,
175             vK = (*pAtoms)[size_t(m_kAt)].vPos;
176          FrameValues.push_back(m_AuToOut * Angle(vI, vJ, vK));
177       } else {
178          FrameValues.push_back(0);
179       }
180    }
181 }
182 
183 
184 // return angle between Left--Center and Center--Right (in radians)
Dihedral(ct::FVector3 const & vA,ct::FVector3 const & vB,ct::FVector3 const & vC,ct::FVector3 const & vD)185 static double Dihedral(ct::FVector3 const &vA, ct::FVector3 const &vB, ct::FVector3 const &vC, ct::FVector3 const &vD)
186 {
187    ct::FVector3
188       v0 = vB - vA,
189       v1 = vC - vB,
190       v2 = vD - vC,
191       vCross01 = Cross(v0,v1),
192       vCross12 = Cross(v1,v2),
193       vCross0112 = Cross(vCross01, vCross12);
194    return std::atan2(Dot(vCross0112, v1.Normalized()), Dot(vCross01, vCross12));
195    // ^- confused yet? 8)
196 }
197 
198 
FMeasurePlaneAngle(int iAt_,int jAt_,int kAt_,int lAt_,FDocument * pDocument_)199 FMeasurePlaneAngle::FMeasurePlaneAngle(int iAt_, int jAt_, int kAt_, int lAt_, FDocument *pDocument_)
200    : FMeasure(pDocument_,QString::fromWCharArray(L"\u00b0"),2,180./M_PI), m_iAt(iAt_), m_jAt(jAt_), m_kAt(kAt_), m_lAt(lAt_)
201 {}
202 
Name() const203 QString FMeasurePlaneAngle::Name() const
204 {
205    return QString(QString::fromWCharArray(L"\u03d5(%1 | %2 | %3 | %4)")).arg(m_pDocument->AtomLabel(m_iAt), m_pDocument->AtomLabel(m_jAt), m_pDocument->AtomLabel(m_kAt), m_pDocument->AtomLabel(m_lAt));
206 }
207 
208 
MakeValues(FMeasureSet & FrameValues,FFrameMeasurePtrList & Frames) const209 void FMeasurePlaneAngle::MakeValues(FMeasureSet &FrameValues, FFrameMeasurePtrList &Frames) const
210 {
211    FrameValues.clear();
212    FrameValues.reserve(Frames.size());
213 //    foreach(FFrameMeasurePtrList::value_type const *itFrame, Frames) {
214    FFrameMeasurePtrList::const_iterator itFrame;
215    _for_each(itFrame, Frames) {
216       ct::FAtomSet *pAtoms = (*itFrame)->pGetAtoms();
217       if (pAtoms && size_t(m_iAt) < pAtoms->size() && size_t(m_jAt) < pAtoms->size()) {
218          ct::FVector3
219             vI = (*pAtoms)[size_t(m_iAt)].vPos,
220             vJ = (*pAtoms)[size_t(m_jAt)].vPos,
221             vK = (*pAtoms)[size_t(m_kAt)].vPos,
222             vL = (*pAtoms)[size_t(m_lAt)].vPos;
223          FrameValues.push_back(m_AuToOut * Dihedral(vI, vJ, vK, vL));
224       } else {
225          FrameValues.push_back(0);
226       }
227    }
228 }
229 
230 
231 
232 
FMeasureFrameGradient(FDocument * pDocument_)233 FMeasureFrameGradient::FMeasureFrameGradient(FDocument *pDocument_)
234    : FMeasure(pDocument_,"mgu",6,1.)
235 {
236    // mgu: mystery gradient units (different programs write different units into
237    // the gradient fields of .xyz files, and particularly what Turbomole was
238    // doing... no idea.)
239 }
240 
MakeValues(FMeasureSet & FrameValues,FFrameMeasurePtrList & Frames) const241 void FMeasureFrameGradient::MakeValues(FMeasureSet &FrameValues, FFrameMeasurePtrList &Frames) const
242 {
243    FrameValues.clear();
244    FrameValues.reserve(Frames.size());
245 //    foreach(FFrameMeasurePtrList::value_type const *itFrame, Frames) {
246    FFrameMeasurePtrList::const_iterator itFrame;
247    _for_each(itFrame, Frames) {
248 //       ct::FAtomSet
249 //          *pAtoms = (*itFrame)->pGetAtoms();
250 //       double
251 //          fGrad = 0.;
252 //       if (pAtoms) {
253 //          for (size_t iAt = 0; iAt < pAtoms->size(); ++ iAt)
254 //             fGrad += ct::LengthSq((*pAtoms)[iAt].vGrad);
255 //       }
256 //       FrameValues.push_back(sqrt(fGrad));
257       FrameValues.push_back((*itFrame)->GetGradient());
258    }
259 }
260 
Name() const261 QString FMeasureFrameGradient::Name() const
262 {
263    return QString::fromUtf8("|grad E|");
264 }
265 
266 
FMeasureFrameEnergy(FDocument * pDocument_)267 FMeasureFrameEnergy::FMeasureFrameEnergy(FDocument *pDocument_)
268    : FMeasure(pDocument_,"Eh",8,1.)
269 {
270 }
271 
MakeValues(FMeasureSet & FrameValues,FFrameMeasurePtrList & Frames) const272 void FMeasureFrameEnergy::MakeValues(FMeasureSet &FrameValues, FFrameMeasurePtrList &Frames) const
273 {
274    FrameValues.clear();
275    FrameValues.reserve(Frames.size());
276 //    foreach(FFrameMeasurePtrList::value_type const *itFrame, Frames) {
277    FFrameMeasurePtrList::const_iterator itFrame;
278    _for_each(itFrame, Frames) {
279       ct::FAtomSet
280          *pAtoms = (*itFrame)->pGetAtoms();
281       double
282          fEnergy = 0.;
283       if (pAtoms)
284          fEnergy = pAtoms->GetLastEnergy();
285       FrameValues.push_back(fEnergy);
286    }
287 }
288 
Name() const289 QString FMeasureFrameEnergy::Name() const
290 {
291    return QString::fromUtf8("Energy");
292 }
293 
294 
FMeasureFrameId(FDocument * pDocument_)295 FMeasureFrameId::FMeasureFrameId(FDocument *pDocument_)
296    : FMeasure(pDocument_,"",0,1.)
297 {
298 }
299 
MakeValues(FMeasureSet & FrameValues,FFrameMeasurePtrList & Frames) const300 void FMeasureFrameId::MakeValues(FMeasureSet &FrameValues, FFrameMeasurePtrList &Frames) const
301 {
302    FrameValues.resize(Frames.size());
303    for (size_t i = 0; i < Frames.size(); ++ i)
304 //       FrameValues[i] = double(i);
305       FrameValues[i] = m_pDocument->iFrameId(&*Frames[i]);
306 }
307 
Name() const308 QString FMeasureFrameId::Name() const
309 {
310    return QString("#Frame");
311 }
312 
313 
314 
FDocumentMeasures(FDocument * pDocument_,QObject * Parent_)315 FDocumentMeasures::FDocumentMeasures(FDocument *pDocument_, QObject *Parent_)
316    : FBase(Parent_), m_pDocument(pDocument_)
317 {
318    AddMeasure(new FMeasureFrameId(m_pDocument));
319    AddMeasure(new FMeasureFrameEnergy(m_pDocument));
320    AddMeasure(new FMeasureFrameGradient(m_pDocument));
321 
322    // note: if this doesn't work, the Q_OBJECT is missing. Would complain about non-existent slots
323    // in the base class.
324    ConnectForwardSignals();
325 }
326 
ConnectForwardSignals()327 void FDocumentMeasures::ConnectForwardSignals()
328 {
329    // forward those things... to deal with newly inserted frames etc.
330    connect(m_pDocument, SIGNAL(layoutAboutToBeChanged()), this, SLOT(parentLayoutAboutToBeChanged()));
331    connect(m_pDocument, SIGNAL(layoutChanged()), this, SLOT(parentLayoutChanged()));
332 }
333 
~FDocumentMeasures()334 FDocumentMeasures::~FDocumentMeasures()
335 {
336 }
337 
338 
rowCount(const QModelIndex & parent) const339 int FDocumentMeasures::rowCount(const QModelIndex &parent) const
340 {
341    return m_pDocument->columnCount();
342    IR_SUPPRESS_UNUSED_WARNING(parent);
343 }
344 
columnCount(const QModelIndex & parent) const345 int FDocumentMeasures::columnCount(const QModelIndex &parent) const
346 {
347    return static_cast<int>(m_List.size());
348    IR_SUPPRESS_UNUSED_WARNING(parent);
349 }
350 
headerData(int section,Qt::Orientation orientation,int role) const351 QVariant FDocumentMeasures::headerData(int section, Qt::Orientation orientation, int role) const
352 {
353 //    IvEmit("HeaderData: Section = %1  orientation = %2  role = %3", section, int(orientation), role);
354    if (role == Qt::DisplayRole && orientation == Qt::Vertical) {
355       FFrame
356          *pFrame = m_pDocument->GetFrame(section, false);
357       if (pFrame == 0)
358          return QVariant("#UNK");
359       return IvFmt("Frame %1", section);
360    }
361    if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
362       FMeasure const
363          *pMeasure = GetMeasure(int(section));
364       if (pMeasure == 0)
365          return QVariant("#UNK");
366       QString
367          UnitName = pMeasure->UnitName();
368       if (UnitName.isEmpty())
369          return pMeasure->Name();
370       else
371          return IvFmt("%1 [%2]", pMeasure->Name(), UnitName);
372    }
373    if ( role == Qt::FontRole ) {
374          QFont CaptionFont;
375          CaptionFont.setBold(true);
376          return CaptionFont;
377    }
378    return QVariant();
379 }
380 
data(const QModelIndex & index,int role) const381 QVariant FDocumentMeasures::data(const QModelIndex &index, int role) const
382 {
383    if (role == Qt::DisplayRole) {
384       FMeasure const
385          *pMeasure = GetMeasure(index);
386       FFrame
387          *pFrame = m_pDocument->GetFrame(index.row(),false);
388       if (pFrame == 0 || pMeasure == 0)
389          return QVariant("#UNK");
390       return QVariant(pMeasure->MeasureFrame(pFrame,FMeasure::FORMAT_ValueOnly));
391    }
392    if (role == Qt::TextAlignmentRole)
393       return QVariant(Qt::AlignRight);
394    return QVariant();
395 }
396 
removeColumns(int column,int count,const QModelIndex & parent)397 bool FDocumentMeasures::removeColumns(int column, int count, const QModelIndex &parent)
398 {
399    if (count < 0 || column + count >= columnCount()) {
400       IV_NOTIFY(NOTIFY_Warning, "Attempted to remove non-existent measurement rows.");
401       return false;
402    }
403    beginRemoveColumns(parent, column, column + count - 1);
404    FMeasureList::iterator
405 //       itFirst = std::next(m_List.begin(), column),
406 //       itLast = std::next(itFirst, count);
407       itFirst = m_List.begin() + column,
408       itLast = itFirst + count;
409    m_List.erase(itFirst, itLast);
410    endRemoveColumns();
411    return true;
412 }
413 
AddMeasure(FMeasurePtr pMeasure)414 void FDocumentMeasures::AddMeasure(FMeasurePtr pMeasure)
415 {
416    beginInsertColumns(QModelIndex(), rowCount(), rowCount()); // 'last' is inclusive!.
417    m_List.push_back(pMeasure);
418    endInsertColumns();
419 }
420 
GetMeasure(QModelIndex const & index)421 FMeasure *FDocumentMeasures::GetMeasure(QModelIndex const &index)
422 {
423    FFrame
424       *pFrame = m_pDocument->GetFrame(index.row(),false);
425    if (pFrame == 0)
426       return 0;
427    return GetMeasure(int(index.column()));
428 }
429 
GetMeasure(int iColumn)430 FMeasure *FDocumentMeasures::GetMeasure(int iColumn)
431 {
432    if (iColumn < 0 || iColumn >= columnCount())
433       return 0;
434    return &*m_List[size_t(iColumn)];
435 }
436 
parentLayoutAboutToBeChanged()437 void FDocumentMeasures::parentLayoutAboutToBeChanged()
438 {
439    emit layoutAboutToBeChanged();
440 }
441 
parentLayoutChanged()442 void FDocumentMeasures::parentLayoutChanged()
443 {
444    emit layoutChanged();
445 }
446 
447 
FTablesForm(FDocument * pDocument_,QWidget * pParent_)448 FTablesForm::FTablesForm(FDocument *pDocument_, QWidget *pParent_)
449    : FBase(pParent_),
450      ui(new Ui::TablesForm),
451      m_pDocument(pDocument_)
452 {
453    ui->setupUi(this);
454    ui->tableView_Values->setModel(m_pDocument->GetMeasures());
455 
456 #if QT_VERSION >= 0x050000
457 //    ui->tableView_Values->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
458    ui->tableView_Values->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
459 #else
460    // qt5 doc's say there is a compatibiltiy layer for this.. but it doesn't seem to exist
461    // in my windows qt 5.3.2 version.
462 //    ui->tableView_Values->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
463    ui->tableView_Values->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
464 #endif
465    ui->tableView_Values->resizeColumnsToContents();
466 
467 //    FTransposeProxyModel
468 //       *pProxyModel = new FTransposeProxyModel(this);
469 //    pProxyModel->setSourceModel(m_pDocument->GetMeasures());
470 //    ui->tableView_Values->setModel(pProxyModel);
471 }
472