From 0429c2d123a22bdae134ca3ca589115fae5a4684 Mon Sep 17 00:00:00 2001 From: Michel Heinz Date: Thu, 5 May 2022 17:00:02 +0200 Subject: [PATCH 01/28] renamed vboxes in InPsightsWidget. --- src/GUI/source/InPsightsWidget.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/GUI/source/InPsightsWidget.cpp b/src/GUI/source/InPsightsWidget.cpp index d0494c45..a24fffc4 100644 --- a/src/GUI/source/InPsightsWidget.cpp +++ b/src/GUI/source/InPsightsWidget.cpp @@ -57,8 +57,8 @@ void InPsightsWidget::createWidget() { auto hbox = new QHBoxLayout(this); auto vboxOuter = new QVBoxLayout(); - auto vboxInner = new QVBoxLayout(); - auto vboxInner2 = new QVBoxLayout(); + auto vboxSettings = new QVBoxLayout(); + auto vboxParticleHighlighting = new QVBoxLayout(); auto selectorBox = new QGroupBox("Particle highlighting:"); auto settingsBox = new QGroupBox("Settings:"); @@ -94,10 +94,10 @@ void InPsightsWidget::createWidget() { lineGrid->addWidget(deselectAllButton,0,1); vboxOuter->addWidget(selectorBox); - selectorBox->setLayout(vboxInner2); + selectorBox->setLayout(vboxParticleHighlighting); auto selectorGrid = new QGridLayout(); - vboxInner2->addLayout(selectorGrid,1); + vboxParticleHighlighting->addLayout(selectorGrid,1); selectorGrid->addWidget(new QLabel("Nuclei"),0,0); selectorGrid->addWidget(atom1Box,1,0); selectorGrid->addWidget(atom2Box,1,1); @@ -107,12 +107,12 @@ void InPsightsWidget::createWidget() { //vboxOuter->addWidget(maximaProcessingWidget,1); vboxOuter->addWidget(settingsBox); - settingsBox->setLayout(vboxInner); + settingsBox->setLayout(vboxSettings); maximaList->setSortingEnabled(true); auto checkboxGrid = new QGridLayout(); - vboxInner->addLayout(checkboxGrid,1); + vboxSettings->addLayout(checkboxGrid,1); // first row checkboxGrid->addWidget(atomsCheckBox,0,0); From 611ebef25739c5a41add49f28f917011e80e08c0 Mon Sep 17 00:00:00 2001 From: Michel Heinz Date: Thu, 5 May 2022 16:44:56 +0200 Subject: [PATCH 02/28] reduced orthogonality threshold in cone.cpp --- src/GUI/source/Cone.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GUI/source/Cone.cpp b/src/GUI/source/Cone.cpp index de6e9e0c..6828569e 100644 --- a/src/GUI/source/Cone.cpp +++ b/src/GUI/source/Cone.cpp @@ -41,7 +41,7 @@ void Cone::rotateToOrientation(const QVector3D &orientation) { auto perpendicular = QVector3D::crossProduct(origVec, orientation); auto l = perpendicular.length(); - float epsilon = 0.00001; + double epsilon = 1.0e-14f; if (l > epsilon) { QVector3D axis = perpendicular.normalized(); From 2e40be08d8bb1beddbd7b77bd6d42046c87e5537 Mon Sep 17 00:00:00 2001 From: Michel Heinz Date: Thu, 5 May 2022 16:46:01 +0200 Subject: [PATCH 03/28] change inheritance of arrow from Cylinder to Abstract3dObject --- src/GUI/include/Arrow.h | 3 ++- src/GUI/source/Arrow.cpp | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/GUI/include/Arrow.h b/src/GUI/include/Arrow.h index 5348de5f..b67bd798 100644 --- a/src/GUI/include/Arrow.h +++ b/src/GUI/include/Arrow.h @@ -8,7 +8,7 @@ #include "Cone.h" #include -class Arrow : public Cylinder { +class Arrow : public Abstract3dObject { public: Arrow(Qt3DCore::QEntity *root, QColor color, @@ -18,6 +18,7 @@ class Arrow : public Cylinder { float relativeTipBottomRadius = 1.25f, float alpha = 1.0f); private: + Cylinder* shaft_; Cone* tip_; QVector3D calculateReducedCylinderEnd(const std::pair &pair, float relativeTipLength); diff --git a/src/GUI/source/Arrow.cpp b/src/GUI/source/Arrow.cpp index ac9e6416..d5cdf6dd 100644 --- a/src/GUI/source/Arrow.cpp +++ b/src/GUI/source/Arrow.cpp @@ -12,9 +12,10 @@ Arrow::Arrow(Qt3DCore::QEntity *root, float relativeTipBottomRadius, float alpha) : - Cylinder(root, color, {pair.first,calculateReducedCylinderEnd(pair, relativeTipLength)}, - baseRadius, alpha), - tip_(new Cone(root, color, {calculateReducedCylinderEnd(pair, relativeTipLength), pair.second}, baseRadius * relativeTipBottomRadius, 0.0f, alpha)) { + Abstract3dObject(root, QColor(), {0, 0, 0}), + shaft_(new Cylinder(this, color, {pair.first,calculateReducedCylinderEnd(pair, relativeTipLength)}, + baseRadius, alpha)), + tip_(new Cone(this, color, {calculateReducedCylinderEnd(pair, relativeTipLength), pair.second}, baseRadius * relativeTipBottomRadius, 0.0f, alpha)) { assert(baseRadius > 0); assert(relativeTipLength > 0 && "The relative tip length must be a positive value."); assert(relativeTipLength < 0.5f && "The relative tip length must be shorter than the half length of the vector."); From be60121e71d33ba317ba98a2828d233d64ebe932 Mon Sep 17 00:00:00 2001 From: Michel Heinz Date: Thu, 5 May 2022 16:46:54 +0200 Subject: [PATCH 04/28] Added eigenvalues and eigenvectors to clusterdata --- .../MaximaProcessing/include/ClusterData.h | 6 +++- .../MaximaProcessing/source/ClusterData.cpp | 30 ++++++++++++++++--- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/Methods/MaximaProcessing/include/ClusterData.h b/src/Methods/MaximaProcessing/include/ClusterData.h index f5cb8bf4..94ea4140 100644 --- a/src/Methods/MaximaProcessing/include/ClusterData.h +++ b/src/Methods/MaximaProcessing/include/ClusterData.h @@ -33,7 +33,9 @@ class ClusterData { const MatrixStatistics RenStats, const std::vector& seds, const Eigen::MatrixXd& sedOverlaps, - const std::vector& subCounts + const std::vector& subCounts, + const std::vector &eigenvalues, + const std::vector> &eigenvectors ); // TODO Refactor (hacky solution for local clustering) @@ -75,6 +77,8 @@ class ClusterData { Eigen::MatrixXd overlaps_; SelectionEnergyCalculator::SelectionInteractionEnergies selectionInteractionEnergies_; std::vector selections_; + std::vector eigenvalues_; + std::vector> eigenvectors_; }; namespace YAML { diff --git a/src/Methods/MaximaProcessing/source/ClusterData.cpp b/src/Methods/MaximaProcessing/source/ClusterData.cpp index 68532f3d..1b658369 100644 --- a/src/Methods/MaximaProcessing/source/ClusterData.cpp +++ b/src/Methods/MaximaProcessing/source/ClusterData.cpp @@ -21,7 +21,9 @@ ClusterData::ClusterData(unsigned totalNumberOfStructures, const MatrixStatistics RenStats, const std::vector &seds, const Eigen::MatrixXd& sedOverlaps, - const std::vector& subCounts + const std::vector& subCounts, + const std::vector &eigenvalues, + const std::vector> &eigenvectors ) : N_(totalNumberOfStructures), @@ -39,7 +41,9 @@ ClusterData::ClusterData(unsigned totalNumberOfStructures, RenStats_(RenStats), voxelCubes_(seds), overlaps_(sedOverlaps), - subN_(subCounts) + subN_(subCounts), + eigenvalues_(eigenvalues), + eigenvectors_(eigenvectors) {}; ClusterData::ClusterData(unsigned totalNumberOfStructures, @@ -81,7 +85,9 @@ ClusterData::ClusterData(unsigned totalNumberOfStructures, overlaps_(sedOverlaps), selectionInteractionEnergies_(selectionInteractionEnergies), selections_(selections), - subN_(subCounts) + subN_(subCounts), + eigenvalues_(), + eigenvectors_() {}; ElectronsVector ClusterData::representativeStructure() const { @@ -90,6 +96,7 @@ ElectronsVector ClusterData::representativeStructure() const { namespace YAML { Node convert::encode(const ClusterData &rhs) { + // TODO add eigenvalues and eigenvectors? Node node; node["N"] = rhs.N_; node["ValueRange"] = rhs.valueStats_; @@ -144,6 +151,19 @@ namespace YAML { } } + std::vector eigenvalues; + std::vector> eigenvectors; + for (auto subNode : node["Structures"]){ + if (subNode["Eigenvalues"]){ + eigenvalues.emplace_back(subNode["Eigenvalues"].as()); + std::vector vecs3d; + for (auto eigenVec : subNode["Eigenvectors"]){ + vecs3d.emplace_back(eigenVec.as()); + } + eigenvectors.emplace_back(vecs3d); + } + } + rhs = ClusterData( node["N"].as(), structures, @@ -162,7 +182,9 @@ namespace YAML { node["Ren"].as(), cubes, sedOverlaps, - subCounts + subCounts, + eigenvalues, + eigenvectors ); return true; From 1b8349c931c968df940e9a96a8ea482324372d16 Mon Sep 17 00:00:00 2001 From: Michel Heinz Date: Thu, 5 May 2022 16:47:49 +0200 Subject: [PATCH 05/28] added drawEigenvectors and removeEigenvector functions --- src/GUI/include/MoleculeWidget.h | 5 +++++ src/GUI/source/MoleculeWidget.cpp | 35 +++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/GUI/include/MoleculeWidget.h b/src/GUI/include/MoleculeWidget.h index 1359a133..bd9e9288 100644 --- a/src/GUI/include/MoleculeWidget.h +++ b/src/GUI/include/MoleculeWidget.h @@ -19,6 +19,7 @@ #include #include #include +#include class MoleculeWidget : public QWidget{ Q_OBJECT @@ -30,6 +31,8 @@ class MoleculeWidget : public QWidget{ //TODO make base MoleculeWidget and InPsightsMoleculeWidget child void drawAxes(bool drawQ = true); + void drawEigenvectors(bool drawQ = true, unsigned clusterId = 0, unsigned structureId = 0, unsigned eigenvalueId = 0, + float scale = 1.0f); void drawAtoms(bool drawQ = true); void drawBonds(bool drawQ = true, double limit = 0.5); void drawSpinCorrelations(const std::vector &clusterData, @@ -46,6 +49,7 @@ class MoleculeWidget : public QWidget{ void setSharedAtomsVector(AtomsVector atomsVector); void addElectronsVector(const ElectronsVector& electronsVector, int clusterId = 0, int structureId = 0, bool coloredQ = false); void removeElectronsVector(int clusterId = 0, int structureId = 0); + void removeEigenvectors(); void addSeds(int clusterId, int structureId, const std::vector &clusterData, double includedPercentage); void removeSeds(int clusterId); @@ -84,6 +88,7 @@ public slots: std::shared_ptr sharedAtomsVector_; AtomsVector3D *atomsVector3D_; CartesianAxes *cartesianAxes_; + std::vector eigenvectors_; public: std::map> activeSedsMap_, activeMaximaHullsMap_; std::map> activeElectronsVectorsMap_; diff --git a/src/GUI/source/MoleculeWidget.cpp b/src/GUI/source/MoleculeWidget.cpp index 6141908a..6474fe22 100644 --- a/src/GUI/source/MoleculeWidget.cpp +++ b/src/GUI/source/MoleculeWidget.cpp @@ -45,6 +45,7 @@ MoleculeWidget::MoleculeWidget(QWidget *parent) zoomText_(new QLabel("Zoom")), atomsVector3D_(nullptr), cartesianAxes_(nullptr), + eigenvectors_(), light_(new Qt3DRender::QDirectionalLight(root_)){ auto outerLayout = new QVBoxLayout(this); @@ -192,6 +193,40 @@ void MoleculeWidget::drawAxes(bool drawQ) { } } +void MoleculeWidget::drawEigenvectors(bool drawQ, unsigned clusterId, unsigned structureId, unsigned eigenvalueId, float scale) { + auto inPsightsWidget = dynamic_cast(parent()); + unsigned electronsNumber = inPsightsWidget->clusterCollection_[clusterId].exemplaricStructures_[structureId].numberOfEntities(); + if (drawQ) { + if (not eigenvectors_.empty()) { + for (auto eigenvector : eigenvectors_) { + eigenvector->deleteLater(); + } + eigenvectors_ = std::vector(); + } + for (unsigned i = 0; i < electronsNumber; i++) { + Eigen::Vector3d ePosVector =inPsightsWidget->clusterCollection_[clusterId].exemplaricStructures_[structureId].positionsVector()[i]; + Eigen::Vector3d eigenVector = inPsightsWidget->clusterCollection_[clusterId].eigenvectors_[structureId][eigenvalueId * electronsNumber + i] * scale; + Eigen::Vector3d tempVector = ePosVector + eigenVector; + QString color = "blue"; + if (inPsightsWidget->clusterCollection_[clusterId].exemplaricStructures_[structureId].typesVector()[i] == Spins::fromString("a")) { + color = "red"; + } + eigenvectors_.emplace_back(new Arrow(moleculeEntity_, QColor(color), + {GuiHelper::toQVector3D(ePosVector), GuiHelper::toQVector3D(tempVector)}, 0.01f, 0.25f, 2.0f)); + } + } + else { + removeEigenvectors(); + } +} + +void MoleculeWidget::removeEigenvectors() { + for (auto eigenvector : eigenvectors_) { + eigenvector->deleteLater(); + } + eigenvectors_ = std::vector(); +} + void MoleculeWidget::drawAtoms(bool drawQ) { if (drawQ) { atomsVector3D_ = new AtomsVector3D(moleculeEntity_, *sharedAtomsVector_); From 627e711f41db365df540d962e4a75e8339b3b62c Mon Sep 17 00:00:00 2001 From: Michel Heinz Date: Thu, 5 May 2022 16:48:25 +0200 Subject: [PATCH 06/28] added eigenvector to GUI --- src/GUI/include/InPsightsWidget.h | 16 +- src/GUI/source/InPsightsWidget.cpp | 316 ++++++++++++++++++++++++++--- 2 files changed, 305 insertions(+), 27 deletions(-) diff --git a/src/GUI/include/InPsightsWidget.h b/src/GUI/include/InPsightsWidget.h index a30096c2..4547b518 100644 --- a/src/GUI/include/InPsightsWidget.h +++ b/src/GUI/include/InPsightsWidget.h @@ -35,28 +35,36 @@ public slots: void onDeselectAll(bool); void onSedChecked(int stateId); void onSedBoxChanged(double value); + void onEigenvectorSpinBoxChanged(int value); + void onScaleVectorBoxChanged(double value); void onBondBoxChanged(double value); + void onMoveElectronsCheckBoxChecked(int stateId); void updateSelectedStructures(int); + void addMovedElectronsVector(int clusterId, int structureId, int secondId); + bool checkEigenvalues(); + std::vector getTickedStructuresCountVector(); private: std::string filename_; MoleculeWidget *moleculeWidget; QCheckBox *atomsCheckBox, *bondsCheckBox, *axesCheckBox, *sampleAverageCheckBox, *spinCorrelationsCheckBox, - *sedsCheckBox,*maximaHullsCheckBox, *plotAllCheckBox, *coloredCheckBox; - QDoubleSpinBox *spinCorrelationBox, *sedPercentageBox, *bondBox; - QSpinBox *atom1Box, *atom2Box, *electron1Box, *electron2Box; + *sedsCheckBox,*maximaHullsCheckBox, *plotAllCheckBox, *coloredCheckBox, *moveElectronsCheckBox; + QDoubleSpinBox *spinCorrelationBox, *sedPercentageBox, *bondBox, *scaleVectorBox; + QSpinBox *atom1Box, *atom2Box, *electron1Box, *electron2Box, *eigenvectorSpinBox; QPushButton *deselectAllButton; QTreeWidget *maximaList; - QLabel *probabilitySum; + QLabel *probabilitySum, *eigenvalueLabel; void showSplashScreen(); void loadData(); void initialView(); void setupSpinBoxes(); + void setupLabels(); void connectSignals(); void createWidget(); void redrawSpinDecorations(); double sumProbabilities(); + void resetEigenvalueLabel(); }; #endif //INPSIGHTS_INPSIGHTSWIDGET_H diff --git a/src/GUI/source/InPsightsWidget.cpp b/src/GUI/source/InPsightsWidget.cpp index a24fffc4..e65748ff 100644 --- a/src/GUI/source/InPsightsWidget.cpp +++ b/src/GUI/source/InPsightsWidget.cpp @@ -32,15 +32,19 @@ InPsightsWidget::InPsightsWidget(QWidget *parent, const std::string& filename) maximaHullsCheckBox(new QCheckBox("Maxima hulls", this)), plotAllCheckBox(new QCheckBox("All of cluster", this)), coloredCheckBox(new QCheckBox("Multicolored", this)), + moveElectronsCheckBox(new QCheckBox("Move electrons", this)), spinCorrelationBox(new QDoubleSpinBox(this)), sedPercentageBox(new QDoubleSpinBox(this)), + scaleVectorBox(new QDoubleSpinBox(this)), bondBox(new QDoubleSpinBox(this)), atom1Box(new QSpinBox(this)), atom2Box(new QSpinBox(this)), + eigenvectorSpinBox(new QSpinBox(this)), electron1Box(new QSpinBox(this)), electron2Box(new QSpinBox(this)), maximaList(new QTreeWidget(this)), probabilitySum(new QLabel(this)), + eigenvalueLabel(new QLabel(this)), deselectAllButton(new QPushButton("Deselect all", this)) { @@ -59,8 +63,10 @@ void InPsightsWidget::createWidget() { auto vboxOuter = new QVBoxLayout(); auto vboxSettings = new QVBoxLayout(); auto vboxParticleHighlighting = new QVBoxLayout(); + auto vboxEigenvectors = new QVBoxLayout(); auto selectorBox = new QGroupBox("Particle highlighting:"); auto settingsBox = new QGroupBox("Settings:"); + auto eigenvectorsBox = new QGroupBox("Eigenvectors:"); setLayout(hbox); @@ -99,11 +105,28 @@ void InPsightsWidget::createWidget() { auto selectorGrid = new QGridLayout(); vboxParticleHighlighting->addLayout(selectorGrid,1); selectorGrid->addWidget(new QLabel("Nuclei"),0,0); - selectorGrid->addWidget(atom1Box,1,0); - selectorGrid->addWidget(atom2Box,1,1); - selectorGrid->addWidget(new QLabel("Electrons"),2,0); - selectorGrid->addWidget(electron1Box,3,0); - selectorGrid->addWidget(electron2Box,3,1); + selectorGrid->addWidget(atom1Box,0,1); + selectorGrid->addWidget(atom2Box,0,2); + selectorGrid->addWidget(new QLabel("Electrons"),1,0); + selectorGrid->addWidget(electron1Box,1,1); + selectorGrid->addWidget(electron2Box,1,2); + + if (not clusterCollection_[0].eigenvalues_.empty()) { + vboxOuter->addWidget(eigenvectorsBox); + eigenvectorsBox->setLayout(vboxEigenvectors); + + auto eigenvectorsGrid = new QGridLayout(); + vboxEigenvectors->addLayout(eigenvectorsGrid, 1); + + // first row + eigenvectorsGrid->addWidget(eigenvectorSpinBox,0,0); + eigenvectorsGrid->addWidget(eigenvalueLabel,0,1); + resetEigenvalueLabel(); + + //second row + eigenvectorsGrid->addWidget(moveElectronsCheckBox,1,1); + eigenvectorsGrid->addWidget(scaleVectorBox,1,0); + } //vboxOuter->addWidget(maximaProcessingWidget,1); vboxOuter->addWidget(settingsBox); @@ -141,6 +164,7 @@ void InPsightsWidget::createWidget() { checkboxGrid->addWidget(spinCorrelationBox,5,1); setupSpinBoxes(); + setupLabels(); } void InPsightsWidget::connectSignals() { @@ -198,10 +222,45 @@ void InPsightsWidget::connectSignals() { connect(sampleAverageCheckBox, &QCheckBox::stateChanged, this, &InPsightsWidget::updateSelectedStructures); - connect(deselectAllButton, &QPushButton::clicked, this, &InPsightsWidget::onDeselectAll); + connect(eigenvectorSpinBox, qOverload(&QSpinBox::valueChanged), + this, &InPsightsWidget::onEigenvectorSpinBoxChanged); + + connect(scaleVectorBox, qOverload(&QDoubleSpinBox::valueChanged), + this, &InPsightsWidget::onScaleVectorBoxChanged); + + connect(moveElectronsCheckBox, &QCheckBox::stateChanged, + this, &InPsightsWidget::onMoveElectronsCheckBoxChecked); + + connect(deselectAllButton, &QPushButton::clicked, + this, &InPsightsWidget::onDeselectAll); +} + +void InPsightsWidget::setupLabels() { + eigenvalueLabel->setAlignment(Qt::AlignCenter); } void InPsightsWidget::setupSpinBoxes() { + + scaleVectorBox->setRange(-10,10); + scaleVectorBox->setWrapping(false); + scaleVectorBox->setSingleStep(0.1); + scaleVectorBox->setValue(1); + scaleVectorBox->setAccelerated(true); + + int numberEigenvalues; + if(clusterCollection_[0].eigenvalues_.empty()) { + numberEigenvalues = 1; + } + else { + numberEigenvalues = clusterCollection_[0].eigenvalues_[0].size(); + } + eigenvectorSpinBox->setRange(-1,numberEigenvalues-1); + eigenvectorSpinBox->setWrapping(true); + eigenvectorSpinBox->setSingleStep(1); + eigenvectorSpinBox->setValue(-1); + eigenvectorSpinBox->setSpecialValueText(tr("none")); + eigenvectorSpinBox->setAccelerated(true); + spinCorrelationBox->setRange(0.0,1.0); spinCorrelationBox->setSingleStep(0.01); spinCorrelationBox->setValue(1.0); @@ -255,7 +314,9 @@ void InPsightsWidget::selectedStructure(QTreeWidgetItem *item, int column) { if (column != 0) spdlog::critical("Column 0 expected but got {} ", column); - + std::vector TickedStructuresCountVector = getTickedStructuresCountVector(); + int count = TickedStructuresCountVector[0]; + bool checkEigenval = checkEigenvalues(); auto id = item->data(0, Qt::ItemDataRole::UserRole).toList(); auto clusterId = id[0].toInt(); auto secondId = id[1].toInt(); @@ -267,22 +328,35 @@ void InPsightsWidget::selectedStructure(QTreeWidgetItem *item, int column) { auto createQ = item->checkState(0) == Qt::CheckState::Checked; if (createQ) { - auto sampleAverage = clusterCollection_[clusterId].sampleAverage_; - - if (sampleAverageCheckBox->checkState() == Qt::CheckState::Checked && - sampleAverage.numberOfEntities() > 0) { - moleculeWidget->addElectronsVector(sampleAverage, clusterId, secondId, - coloredCheckBox->checkState() == Qt::Checked); - } else if (sampleAverageCheckBox->checkState() == Qt::CheckState::Checked - && sampleAverage.numberOfEntities() == 0) { - moleculeWidget->addElectronsVector(clusterCollection_[clusterId].exemplaricStructures_[structureId], - clusterId, secondId, coloredCheckBox->checkState() == Qt::Checked); - spdlog::warn("Sample averaged vectors were not calculated. Plotting the first maximum instead..."); - } else { + if (eigenvectorSpinBox->value() != -1 and count > 1) { + spdlog::warn("Chose only one structure for eigenvalues"); + } + if (sampleAverageCheckBox->checkState() == Qt::CheckState::Checked){ + auto sampleAverage = clusterCollection_[clusterId].sampleAverage_; + if (sampleAverage.numberOfEntities() > 0) { + moleculeWidget->addElectronsVector(sampleAverage, clusterId, secondId, + coloredCheckBox->checkState() == Qt::Checked); + } + else { + moleculeWidget->addElectronsVector(clusterCollection_[clusterId].exemplaricStructures_[structureId], + clusterId, secondId, coloredCheckBox->checkState() == Qt::Checked); + spdlog::warn("Sample averaged vectors were not calculated. Plotting the first maximum instead..."); + } + } + else { moleculeWidget->addElectronsVector(clusterCollection_[clusterId].exemplaricStructures_[structureId], clusterId, secondId, coloredCheckBox->checkState() == Qt::Checked); } + if (checkEigenvalues() and eigenvectorSpinBox->value() != -1) { + eigenvalueLabel->setText(QString::number(clusterCollection_[clusterId].eigenvalues_[structureId][eigenvectorSpinBox->value()], 'f', 4)); + moleculeWidget->drawEigenvectors(true, clusterId, structureId, eigenvectorSpinBox->value(), scaleVectorBox->value()); + } + else { + moleculeWidget->removeEigenvectors(); + eigenvalueLabel->setText(QString(" ")); + } + if (sedsCheckBox->checkState() == Qt::CheckState::Checked && moleculeWidget->activeSedsMap_.find(clusterId) == moleculeWidget->activeSedsMap_.end()) { moleculeWidget->addSeds(clusterId, structureId, clusterCollection_, sedPercentageBox->value()); @@ -299,7 +373,38 @@ void InPsightsWidget::selectedStructure(QTreeWidgetItem *item, int column) { onElectron1BoxChanged(electron1Box->value()); onElectron2BoxChanged(electron2Box->value()); - } else { + } + else { + if (eigenvectorSpinBox->value() != -1 and count > 1) { + spdlog::warn("Chose only one structure for eigenvalues"); + } + if (not checkEigenval) { + moveElectronsCheckBox->setCheckState(Qt::Unchecked); + } + if (checkEigenval and eigenvectorSpinBox->value() != -1) { + auto* root = maximaList->invisibleRootItem(); + unsigned cluId = -1; + unsigned strId = 0; + // iterate over topLevelItems + for (int i = 0; i < root->childCount(); ++i) { + if(root->child(i)->checkState(0) == Qt::Checked) { + cluId = i; + } + // iterate over childs of topLevelItem i + for (int j = 0; jchild(i)->childCount(); ++j) { + if(root->child(i)->child(j)->checkState(0) == Qt::Checked) { + cluId = i; + strId = j; + } + } + } + eigenvalueLabel->setText(QString::number(clusterCollection_[cluId].eigenvalues_[strId][eigenvectorSpinBox->value()], 'f', 4)); + moleculeWidget->drawEigenvectors(true, cluId, strId, eigenvectorSpinBox->value(), scaleVectorBox->value()); + } + else { + moleculeWidget->removeEigenvectors(); + eigenvalueLabel->setText(QString(" ")); + } moleculeWidget->removeElectronsVector(clusterId, secondId); if (moleculeWidget->activeSedsMap_.find(clusterId) != moleculeWidget->activeSedsMap_.end()) @@ -310,9 +415,71 @@ void InPsightsWidget::selectedStructure(QTreeWidgetItem *item, int column) { } redrawSpinDecorations(); probabilitySum->setText(QString("Σ Weight = ") + QString::number(sumProbabilities(), 'f', 4)); - }; +void InPsightsWidget::resetEigenvalueLabel() { + eigenvalueLabel->setText(QString(" ")); +} + +void InPsightsWidget::addMovedElectronsVector(int clusterId, int structureId, int secondId) { + unsigned electronsNumber = clusterCollection_[clusterId].exemplaricStructures_[structureId].numberOfEntities(); + auto startElectronsVector = clusterCollection_[clusterId].exemplaricStructures_[structureId]; + auto eigenvector = clusterCollection_[clusterId].eigenvectors_[structureId]; + PositionsVector movedElectronPositions; + for (unsigned i = 0; i < electronsNumber; ++i) { + movedElectronPositions.append(startElectronsVector.positionsVector()[i] + + eigenvector[eigenvectorSpinBox->value() * electronsNumber + i] * + scaleVectorBox->value()); + } + auto movedElectronsVector = ElectronsVector(movedElectronPositions, + startElectronsVector.typesVector()); + moleculeWidget->addElectronsVector(movedElectronsVector, clusterId, secondId); +} + +bool InPsightsWidget::checkEigenvalues() { + if(clusterCollection_[0].eigenvalues_.empty()) { + return false; + } + else { + std::vector TickedStructuresCountVector = getTickedStructuresCountVector(); + int count = TickedStructuresCountVector[0]; + if (count > 1) { + return false; + } + if (count == 0) { + return false; + } + } + return true; +} + +std::vector InPsightsWidget::getTickedStructuresCountVector() { + auto* root = maximaList->invisibleRootItem(); + std::vector TickedStructuresCountVector; + unsigned count = 0; + unsigned clusterId = -1; + unsigned structureId = -1; + // iterate over topLevelItems + for (int i = 0; i < root->childCount(); ++i) { + if(root->child(i)->checkState(0) == Qt::Checked) { + count += 1; + clusterId = i; + } + // iterate over childs of topLevelItem i + for (int j = 0; jchild(i)->childCount(); ++j) { + if(root->child(i)->child(j)->checkState(0) == Qt::Checked) { + count += 1; + clusterId = i; + structureId = j; + } + } + } + TickedStructuresCountVector.emplace_back(count); + TickedStructuresCountVector.emplace_back(clusterId); + TickedStructuresCountVector.emplace_back(structureId); + return TickedStructuresCountVector; +} + void InPsightsWidget::updateSelectedStructures(int) { auto* root = maximaList->invisibleRootItem(); @@ -410,11 +577,15 @@ void InPsightsWidget::onBondBoxChanged(double value) { } void InPsightsWidget::onAtom1BoxChanged(int value) { - moleculeWidget->onAtomsHighlighted(value); + if (atomsCheckBox->isChecked()) { + moleculeWidget->onAtomsHighlighted(value); + } } void InPsightsWidget::onAtom2BoxChanged(int value) { - moleculeWidget->onAtomsChecked(value); + if (atomsCheckBox->isChecked()) { + moleculeWidget->onAtomsChecked(value); + } } void InPsightsWidget::onElectron1BoxChanged(int value) { @@ -425,6 +596,105 @@ void InPsightsWidget::onElectron2BoxChanged(int value) { moleculeWidget->onElectronsChecked(value); } + + +void InPsightsWidget::onEigenvectorSpinBoxChanged(int value) { + if (value != -1) { + std::vector tickedStructuresCountVector = getTickedStructuresCountVector(); + int count = tickedStructuresCountVector[0]; + int id = tickedStructuresCountVector[1]; + int secondId = tickedStructuresCountVector[2]; + int structureId = secondId; + if (structureId == -1) { + structureId = 0; + } + if (count > 1) { + spdlog::warn("Chose only one structure for eigenvalues"); + } + else if (count == 1){ + eigenvalueLabel->setText(QString::number(clusterCollection_[id].eigenvalues_[structureId][value], 'f', 4)); + moleculeWidget->drawEigenvectors(true, id, structureId, value, scaleVectorBox->value()); + if (moveElectronsCheckBox->isChecked()) { + moveElectronsCheckBox->setCheckState(Qt::Unchecked); + updateSelectedStructures(42); + } + else { + updateSelectedStructures(42); + } + } + if (count == 0) { + eigenvalueLabel->setText(QString(" ")); + spdlog::warn("Chose a structure for eigenvalues"); + } + } + if (value == -1 ) { + eigenvalueLabel->setText(QString(" ")); + moleculeWidget->removeEigenvectors(); + //moleculeWidget->drawEigenvectors(false); + } +} + +void InPsightsWidget::onScaleVectorBoxChanged(double value) { +// updateSelectedStructures(42); + std::vector tickedStructuresCountVector = getTickedStructuresCountVector(); + int count = tickedStructuresCountVector[0]; + if (count == 1 and eigenvectorSpinBox->value() != -1) { + int clusterId = tickedStructuresCountVector[1]; + int structureId = tickedStructuresCountVector[2]; + int secondId = structureId; + if (structureId == -1) { + structureId = 0; + } + if (moveElectronsCheckBox->checkState() == Qt::Checked) { + moleculeWidget->removeElectronsVector(clusterId, secondId); + addMovedElectronsVector(clusterId, structureId, secondId); + moleculeWidget->drawEigenvectors(true, clusterId, structureId, eigenvectorSpinBox->value(), value); + } + } +} + +void InPsightsWidget::onMoveElectronsCheckBoxChecked(int stateId){ + spinCorrelationsCheckBox->setCheckState(Qt::Unchecked); + std::vector tickedStructuresCountVector = getTickedStructuresCountVector(); + int count = tickedStructuresCountVector[0]; + if (moveElectronsCheckBox->isChecked()) { + if (count == 0){ + spdlog::warn("Chose a structure for moving the electrons"); + moveElectronsCheckBox->setCheckState(Qt::Unchecked); + } + if (count > 1) { + spdlog::warn("Chose only one structure for moving the electrons"); + moveElectronsCheckBox->setCheckState(Qt::Unchecked); + } + if (count == 1 and eigenvectorSpinBox->value() == -1) { + spdlog::warn("Chose an eigenvector for moving the electrons"); + moveElectronsCheckBox->setCheckState(Qt::Unchecked); + } + } + + if (count == 1 and eigenvectorSpinBox->value() != -1) { + int clusterId = tickedStructuresCountVector[1]; + int structureId = tickedStructuresCountVector[2]; + int secondId = structureId; + if (structureId == -1) { + structureId = 0; + } + if (moveElectronsCheckBox->checkState() == Qt::Unchecked) { + moleculeWidget->removeElectronsVector(clusterId, secondId); + moleculeWidget->addElectronsVector(clusterCollection_[clusterId].exemplaricStructures_[structureId], + clusterId, secondId, + coloredCheckBox->checkState() == Qt::Checked); + } + else { + moleculeWidget->removeElectronsVector(clusterId, secondId); + addMovedElectronsVector(clusterId, structureId, secondId); + } + } +// else { +// updateSelectedStructures(42); +// } +} + void InPsightsWidget::showSplashScreen() { auto splashScreen = new QSplashScreen(); auto pixmap = QPixmap(":inPsights.png").scaledToWidth(450, Qt::TransformationMode::SmoothTransformation); From 4d0119509bdece751bc882a9cd519ba4de781845 Mon Sep 17 00:00:00 2001 From: Michel Heinz Date: Thu, 5 May 2022 19:00:16 +0200 Subject: [PATCH 07/28] fixed scaling the eigenvectors --- src/GUI/source/InPsightsWidget.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/GUI/source/InPsightsWidget.cpp b/src/GUI/source/InPsightsWidget.cpp index e65748ff..ff8f74de 100644 --- a/src/GUI/source/InPsightsWidget.cpp +++ b/src/GUI/source/InPsightsWidget.cpp @@ -650,6 +650,9 @@ void InPsightsWidget::onScaleVectorBoxChanged(double value) { addMovedElectronsVector(clusterId, structureId, secondId); moleculeWidget->drawEigenvectors(true, clusterId, structureId, eigenvectorSpinBox->value(), value); } + else { + moleculeWidget->drawEigenvectors(true, clusterId, structureId, eigenvectorSpinBox->value(), value); + } } } From 9cb3cb1e5045aae8fc00c60d7a5c714828f10aff Mon Sep 17 00:00:00 2001 From: Michel Heinz Date: Fri, 6 May 2022 10:00:43 +0200 Subject: [PATCH 08/28] removed widgets for eigenvectoranalysis if no eigenvalues/vectors were calculated --- src/GUI/source/InPsightsWidget.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/GUI/source/InPsightsWidget.cpp b/src/GUI/source/InPsightsWidget.cpp index ff8f74de..660746da 100644 --- a/src/GUI/source/InPsightsWidget.cpp +++ b/src/GUI/source/InPsightsWidget.cpp @@ -127,7 +127,13 @@ void InPsightsWidget::createWidget() { eigenvectorsGrid->addWidget(moveElectronsCheckBox,1,1); eigenvectorsGrid->addWidget(scaleVectorBox,1,0); } - + else{ + eigenvectorSpinBox->deleteLater(); + eigenvalueLabel->deleteLater(); + moveElectronsCheckBox->deleteLater(); + scaleVectorBox->deleteLater(); + } + //vboxOuter->addWidget(maximaProcessingWidget,1); vboxOuter->addWidget(settingsBox); settingsBox->setLayout(vboxSettings); From 619c4a3a371087a1e3d05505d1d3c093c2e0a068 Mon Sep 17 00:00:00 2001 From: Michel Heinz Date: Mon, 9 May 2022 09:14:57 +0200 Subject: [PATCH 09/28] fixed a segmentation fault when eigenvalues are missing, a moving electrons bug, and a sample average bug --- src/GUI/include/InPsightsWidget.h | 2 + src/GUI/source/InPsightsWidget.cpp | 162 ++++++++++++++++++++--------- 2 files changed, 115 insertions(+), 49 deletions(-) diff --git a/src/GUI/include/InPsightsWidget.h b/src/GUI/include/InPsightsWidget.h index 4547b518..f9554581 100644 --- a/src/GUI/include/InPsightsWidget.h +++ b/src/GUI/include/InPsightsWidget.h @@ -42,6 +42,7 @@ public slots: void updateSelectedStructures(int); void addMovedElectronsVector(int clusterId, int structureId, int secondId); bool checkEigenvalues(); + void onSampleAverageCheckBoxChanged(int stateId); std::vector getTickedStructuresCountVector(); private: @@ -54,6 +55,7 @@ public slots: QPushButton *deselectAllButton; QTreeWidget *maximaList; QLabel *probabilitySum, *eigenvalueLabel; + std::vector lastMovedElectronClusterVector; void showSplashScreen(); void loadData(); diff --git a/src/GUI/source/InPsightsWidget.cpp b/src/GUI/source/InPsightsWidget.cpp index 660746da..19436b11 100644 --- a/src/GUI/source/InPsightsWidget.cpp +++ b/src/GUI/source/InPsightsWidget.cpp @@ -45,7 +45,8 @@ InPsightsWidget::InPsightsWidget(QWidget *parent, const std::string& filename) maximaList(new QTreeWidget(this)), probabilitySum(new QLabel(this)), eigenvalueLabel(new QLabel(this)), - deselectAllButton(new QPushButton("Deselect all", this)) + deselectAllButton(new QPushButton("Deselect all", this)), + lastMovedElectronClusterVector({0, 0, -1}) { loadData(); @@ -226,7 +227,7 @@ void InPsightsWidget::connectSignals() { this, &InPsightsWidget::updateSelectedStructures); connect(sampleAverageCheckBox, &QCheckBox::stateChanged, - this, &InPsightsWidget::updateSelectedStructures); + this, &InPsightsWidget::onSampleAverageCheckBoxChanged); connect(eigenvectorSpinBox, qOverload(&QSpinBox::valueChanged), this, &InPsightsWidget::onEigenvectorSpinBoxChanged); @@ -334,10 +335,22 @@ void InPsightsWidget::selectedStructure(QTreeWidgetItem *item, int column) { auto createQ = item->checkState(0) == Qt::CheckState::Checked; if (createQ) { - if (eigenvectorSpinBox->value() != -1 and count > 1) { - spdlog::warn("Chose only one structure for eigenvalues"); + if (not clusterCollection_[0].eigenvalues_.empty()) { + if (eigenvectorSpinBox->value() != -1 and count > 1) { + spdlog::warn("Chose only one structure for eigenvalues"); + } } if (sampleAverageCheckBox->checkState() == Qt::CheckState::Checked){ + if (not clusterCollection_[0].eigenvalues_.empty()) { + if (eigenvectorSpinBox->value() != -1) { + spdlog::warn("No eigenvectors were calculated for the sample average"); + eigenvectorSpinBox->setValue(-1); + } + if (moveElectronsCheckBox->isChecked()) { + spdlog::warn("Cannot move electrons for the sample average"); + moveElectronsCheckBox->setCheckState(Qt::Unchecked); + } + } auto sampleAverage = clusterCollection_[clusterId].sampleAverage_; if (sampleAverage.numberOfEntities() > 0) { moleculeWidget->addElectronsVector(sampleAverage, clusterId, secondId, @@ -353,16 +366,25 @@ void InPsightsWidget::selectedStructure(QTreeWidgetItem *item, int column) { moleculeWidget->addElectronsVector(clusterCollection_[clusterId].exemplaricStructures_[structureId], clusterId, secondId, coloredCheckBox->checkState() == Qt::Checked); } - - if (checkEigenvalues() and eigenvectorSpinBox->value() != -1) { - eigenvalueLabel->setText(QString::number(clusterCollection_[clusterId].eigenvalues_[structureId][eigenvectorSpinBox->value()], 'f', 4)); - moleculeWidget->drawEigenvectors(true, clusterId, structureId, eigenvectorSpinBox->value(), scaleVectorBox->value()); - } - else { - moleculeWidget->removeEigenvectors(); - eigenvalueLabel->setText(QString(" ")); + if (not clusterCollection_[0].eigenvalues_.empty()) { + if (checkEigenvalues() and eigenvectorSpinBox->value() != -1) { + eigenvalueLabel->setText(QString::number(clusterCollection_[clusterId].eigenvalues_[structureId][eigenvectorSpinBox->value()], 'f', 4)); + moleculeWidget->drawEigenvectors(true, clusterId, structureId, eigenvectorSpinBox->value(), scaleVectorBox->value()); + } + else { + if (moveElectronsCheckBox->isChecked()) { + moveElectronsCheckBox->setCheckState(Qt::Unchecked); + std::cout << lastMovedElectronClusterVector[0] << " " << lastMovedElectronClusterVector[1] << " " << lastMovedElectronClusterVector[2] << std::endl; + moleculeWidget->removeElectronsVector(lastMovedElectronClusterVector[0], lastMovedElectronClusterVector[2]); + moleculeWidget->addElectronsVector(clusterCollection_[lastMovedElectronClusterVector[0]] + .exemplaricStructures_[lastMovedElectronClusterVector[1]], + lastMovedElectronClusterVector[0], lastMovedElectronClusterVector[2], + coloredCheckBox->checkState() == Qt::Checked); + } + moleculeWidget->removeEigenvectors(); + eigenvalueLabel->setText(QString(" ")); + } } - if (sedsCheckBox->checkState() == Qt::CheckState::Checked && moleculeWidget->activeSedsMap_.find(clusterId) == moleculeWidget->activeSedsMap_.end()) { moleculeWidget->addSeds(clusterId, structureId, clusterCollection_, sedPercentageBox->value()); @@ -381,36 +403,39 @@ void InPsightsWidget::selectedStructure(QTreeWidgetItem *item, int column) { onElectron2BoxChanged(electron2Box->value()); } else { - if (eigenvectorSpinBox->value() != -1 and count > 1) { - spdlog::warn("Chose only one structure for eigenvalues"); - } - if (not checkEigenval) { - moveElectronsCheckBox->setCheckState(Qt::Unchecked); - } - if (checkEigenval and eigenvectorSpinBox->value() != -1) { - auto* root = maximaList->invisibleRootItem(); - unsigned cluId = -1; - unsigned strId = 0; - // iterate over topLevelItems - for (int i = 0; i < root->childCount(); ++i) { - if(root->child(i)->checkState(0) == Qt::Checked) { - cluId = i; - } - // iterate over childs of topLevelItem i - for (int j = 0; jchild(i)->childCount(); ++j) { - if(root->child(i)->child(j)->checkState(0) == Qt::Checked) { + if (not clusterCollection_[0].eigenvalues_.empty()) { + if (eigenvectorSpinBox->value() != -1 and count > 1) { + spdlog::warn("Chose only one structure for eigenvalues"); + } + if (not checkEigenval) { + moveElectronsCheckBox->setCheckState(Qt::Unchecked); + } + if (checkEigenval and eigenvectorSpinBox->value() != -1) { + auto* root = maximaList->invisibleRootItem(); + unsigned cluId = -1; + unsigned strId = 0; + // iterate over topLevelItems + for (int i = 0; i < root->childCount(); ++i) { + if(root->child(i)->checkState(0) == Qt::Checked) { cluId = i; - strId = j; + } + // iterate over childs of topLevelItem i + for (int j = 0; jchild(i)->childCount(); ++j) { + if(root->child(i)->child(j)->checkState(0) == Qt::Checked) { + cluId = i; + strId = j; + } } } + eigenvalueLabel->setText(QString::number(clusterCollection_[cluId].eigenvalues_[strId][eigenvectorSpinBox->value()], 'f', 4)); + moleculeWidget->drawEigenvectors(true, cluId, strId, eigenvectorSpinBox->value(), scaleVectorBox->value()); + } + else { + moleculeWidget->removeEigenvectors(); + eigenvalueLabel->setText(QString(" ")); } - eigenvalueLabel->setText(QString::number(clusterCollection_[cluId].eigenvalues_[strId][eigenvectorSpinBox->value()], 'f', 4)); - moleculeWidget->drawEigenvectors(true, cluId, strId, eigenvectorSpinBox->value(), scaleVectorBox->value()); - } - else { - moleculeWidget->removeEigenvectors(); - eigenvalueLabel->setText(QString(" ")); } + moleculeWidget->removeElectronsVector(clusterId, secondId); if (moleculeWidget->activeSedsMap_.find(clusterId) != moleculeWidget->activeSedsMap_.end()) @@ -440,6 +465,9 @@ void InPsightsWidget::addMovedElectronsVector(int clusterId, int structureId, in auto movedElectronsVector = ElectronsVector(movedElectronPositions, startElectronsVector.typesVector()); moleculeWidget->addElectronsVector(movedElectronsVector, clusterId, secondId); + lastMovedElectronClusterVector[0] = clusterId; + lastMovedElectronClusterVector[1] = structureId; + lastMovedElectronClusterVector[2] = secondId; } bool InPsightsWidget::checkEigenvalues() { @@ -486,6 +514,26 @@ std::vector InPsightsWidget::getTickedStructuresCountVector() { return TickedStructuresCountVector; } +void InPsightsWidget::onSampleAverageCheckBoxChanged(int stateId) { + if (not clusterCollection_[0].eigenvalues_.empty()) { + if (moveElectronsCheckBox->isChecked()) { + sampleAverageCheckBox->setCheckState(Qt::Unchecked); + spdlog::warn("Cannot move electrons for the sample average"); + } + if (eigenvectorSpinBox->value() != -1) { + sampleAverageCheckBox->setCheckState(Qt::Unchecked); + spdlog::warn("No eigenvectors were calculated for the sample average"); + } + if (not moveElectronsCheckBox->isChecked() and eigenvectorSpinBox->value() == -1) { + updateSelectedStructures(42); + } + } + else { + updateSelectedStructures(42); + } + +} + void InPsightsWidget::updateSelectedStructures(int) { auto* root = maximaList->invisibleRootItem(); @@ -602,18 +650,31 @@ void InPsightsWidget::onElectron2BoxChanged(int value) { moleculeWidget->onElectronsChecked(value); } - - void InPsightsWidget::onEigenvectorSpinBoxChanged(int value) { - if (value != -1) { - std::vector tickedStructuresCountVector = getTickedStructuresCountVector(); - int count = tickedStructuresCountVector[0]; - int id = tickedStructuresCountVector[1]; - int secondId = tickedStructuresCountVector[2]; - int structureId = secondId; - if (structureId == -1) { - structureId = 0; + if (sampleAverageCheckBox->isChecked() and value != -1) { + eigenvectorSpinBox->setValue(-1); + value = -1; + spdlog::warn("No eigenvectors were calculated for the sample average"); + } + std::vector tickedStructuresCountVector = getTickedStructuresCountVector(); + int count = tickedStructuresCountVector[0]; + int id = tickedStructuresCountVector[1]; + int secondId = tickedStructuresCountVector[2]; + int structureId = secondId; + if (structureId == -1) { + structureId = 0; + } + if (value == -1) { + if (not sampleAverageCheckBox->isChecked() and moveElectronsCheckBox->isChecked()) { + moveElectronsCheckBox->setCheckState(Qt::Unchecked); + spdlog::warn("Chose an eigenvector to move the electrons"); + moleculeWidget->removeElectronsVector(id, secondId); + moleculeWidget->addElectronsVector(clusterCollection_[id].exemplaricStructures_[structureId], + id, secondId, + coloredCheckBox->checkState() == Qt::Checked); } + } + if (value != -1) { if (count > 1) { spdlog::warn("Chose only one structure for eigenvalues"); } @@ -663,7 +724,10 @@ void InPsightsWidget::onScaleVectorBoxChanged(double value) { } void InPsightsWidget::onMoveElectronsCheckBoxChecked(int stateId){ - spinCorrelationsCheckBox->setCheckState(Qt::Unchecked); + if (sampleAverageCheckBox->isChecked() and moveElectronsCheckBox->isChecked()) { + moveElectronsCheckBox->setCheckState(Qt::Unchecked); + spdlog::warn("Cannot move electrons for the sample average"); + } std::vector tickedStructuresCountVector = getTickedStructuresCountVector(); int count = tickedStructuresCountVector[0]; if (moveElectronsCheckBox->isChecked()) { From 47adc9a355cc449f2526429f904f41eb072bafc3 Mon Sep 17 00:00:00 2001 From: Michel Heinz Date: Mon, 9 May 2022 09:15:34 +0200 Subject: [PATCH 10/28] cleaned up the code and added spin correlations when moving the electrons --- src/GUI/source/InPsightsWidget.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/GUI/source/InPsightsWidget.cpp b/src/GUI/source/InPsightsWidget.cpp index 19436b11..c2589995 100644 --- a/src/GUI/source/InPsightsWidget.cpp +++ b/src/GUI/source/InPsightsWidget.cpp @@ -683,10 +683,6 @@ void InPsightsWidget::onEigenvectorSpinBoxChanged(int value) { moleculeWidget->drawEigenvectors(true, id, structureId, value, scaleVectorBox->value()); if (moveElectronsCheckBox->isChecked()) { moveElectronsCheckBox->setCheckState(Qt::Unchecked); - updateSelectedStructures(42); - } - else { - updateSelectedStructures(42); } } if (count == 0) { @@ -697,12 +693,10 @@ void InPsightsWidget::onEigenvectorSpinBoxChanged(int value) { if (value == -1 ) { eigenvalueLabel->setText(QString(" ")); moleculeWidget->removeEigenvectors(); - //moleculeWidget->drawEigenvectors(false); } } void InPsightsWidget::onScaleVectorBoxChanged(double value) { -// updateSelectedStructures(42); std::vector tickedStructuresCountVector = getTickedStructuresCountVector(); int count = tickedStructuresCountVector[0]; if (count == 1 and eigenvectorSpinBox->value() != -1) { @@ -721,6 +715,7 @@ void InPsightsWidget::onScaleVectorBoxChanged(double value) { moleculeWidget->drawEigenvectors(true, clusterId, structureId, eigenvectorSpinBox->value(), value); } } + redrawSpinDecorations(); } void InPsightsWidget::onMoveElectronsCheckBoxChecked(int stateId){ @@ -732,15 +727,15 @@ void InPsightsWidget::onMoveElectronsCheckBoxChecked(int stateId){ int count = tickedStructuresCountVector[0]; if (moveElectronsCheckBox->isChecked()) { if (count == 0){ - spdlog::warn("Chose a structure for moving the electrons"); + spdlog::warn("Chose a structure to move the electrons"); moveElectronsCheckBox->setCheckState(Qt::Unchecked); } if (count > 1) { - spdlog::warn("Chose only one structure for moving the electrons"); + spdlog::warn("Chose only one structure to move the electrons"); moveElectronsCheckBox->setCheckState(Qt::Unchecked); } if (count == 1 and eigenvectorSpinBox->value() == -1) { - spdlog::warn("Chose an eigenvector for moving the electrons"); + spdlog::warn("Chose an eigenvector to move the electrons"); moveElectronsCheckBox->setCheckState(Qt::Unchecked); } } @@ -763,9 +758,7 @@ void InPsightsWidget::onMoveElectronsCheckBoxChecked(int stateId){ addMovedElectronsVector(clusterId, structureId, secondId); } } -// else { -// updateSelectedStructures(42); -// } + redrawSpinDecorations(); } void InPsightsWidget::showSplashScreen() { From 3eaa6644a1ab4e37de405bc29d2bd61968f31b97 Mon Sep 17 00:00:00 2001 From: Leonard Reuter Date: Tue, 7 Jun 2022 12:31:04 +0200 Subject: [PATCH 11/28] InPsights now display potential differences. --- docs/USER_MANUAL.md | 1 + src/GUI/source/InPsightsWidget.cpp | 23 +++++++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/docs/USER_MANUAL.md b/docs/USER_MANUAL.md index 42a5eecc..4b1455f0 100644 --- a/docs/USER_MANUAL.md +++ b/docs/USER_MANUAL.md @@ -140,3 +140,4 @@ Possible options are: The `inPsights` executable is the `Qt5` based GUI to visualize the processed data and requires an `-out.yml` file as an input. Execution of `inPsights input-out.yml` from the command-line starts the GUI in a separate window. +* `globalMinPhi` (`float`): Can be added to the `-out.yml` file to change the reference for the ΔΦ values. Default: lowest value that was found. diff --git a/src/GUI/source/InPsightsWidget.cpp b/src/GUI/source/InPsightsWidget.cpp index c2589995..6b585fc4 100644 --- a/src/GUI/source/InPsightsWidget.cpp +++ b/src/GUI/source/InPsightsWidget.cpp @@ -75,10 +75,10 @@ void InPsightsWidget::createWidget() { hbox->addWidget(moleculeWidget, 1); hbox->addLayout(vboxOuter, 0); - maximaList->setMinimumWidth(350); + maximaList->setMinimumWidth(352); // put into MaximaTreeWidget class - auto headerLabels = QList({"ID", "Weight", "min(Φ)", "max(Φ)"}); + auto headerLabels = QList({"ID", "Weight", "min ΔΦ", "max ΔΦ"}); maximaList->setColumnCount(headerLabels.size()); maximaList->setHeaderLabels(headerLabels); maximaList->header()->setStretchLastSection(false); @@ -811,6 +811,13 @@ void InPsightsWidget::loadData() { Camera::settings = Settings::Camera(doc); } + float globalMinPhi; + if (doc["GlobalMinPhi"]) { + globalMinPhi = doc["GlobalMinPhi"].as(); + } + else { + globalMinPhi = doc["Clusters"][0].as().valueStats_.cwiseMin()[0]/2.0; + } for (int clusterId = 0; clusterId < static_cast(doc["Clusters"].size()); ++clusterId) { spdlog::info("{} out of {} clusters loaded...", clusterId+1, static_cast(doc["Clusters"].size())); @@ -818,20 +825,20 @@ void InPsightsWidget::loadData() { const auto & cluster = clusterCollection_.back(); float minPhi = cluster.valueStats_.cwiseMin()[0]/2.0; - auto minPhiString = QString::number(minPhi, 'f', 3); - if (minPhi > 0) + auto minPhiString = QString::number(minPhi-globalMinPhi, 'f', 4); + if (minPhi-globalMinPhi >= 0) minPhiString = QString(' ') + minPhiString; float maxPhi = cluster.valueStats_.cwiseMax()[0]/2.0; - auto maxPhiString = QString::number(maxPhi, 'f', 3); - if (maxPhi > 0) + auto maxPhiString = QString::number(maxPhi-globalMinPhi, 'f', 4); + if (maxPhi-globalMinPhi >= 0) maxPhiString = QString(' ') + maxPhiString; auto item = new IntegerSortedTreeWidgetItem( maximaList, {QString::number(clusterId), QString::number(1.0 * cluster.N_ / doc["NSamples"].as(), 'f', 4), - minPhiString.left(6), - maxPhiString.left(6)}); + minPhiString.left(7), + maxPhiString.left(7)}); item->setCheckState(0, Qt::CheckState::Unchecked); From d9b29b56c359b242c2fdadb3f103db01fa15c98f Mon Sep 17 00:00:00 2001 From: Leonard Reuter Date: Tue, 7 Jun 2022 12:36:16 +0200 Subject: [PATCH 12/28] Added camera settings to user manual. --- docs/USER_MANUAL.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/USER_MANUAL.md b/docs/USER_MANUAL.md index 4b1455f0..506f4526 100644 --- a/docs/USER_MANUAL.md +++ b/docs/USER_MANUAL.md @@ -141,3 +141,8 @@ The `inPsights` executable is the `Qt5` based GUI to visualize the processed dat Execution of `inPsights input-out.yml` from the command-line starts the GUI in a separate window. * `globalMinPhi` (`float`): Can be added to the `-out.yml` file to change the reference for the ΔΦ values. Default: lowest value that was found. + +#### Camera: +The `Camera` settings can be adjusted in the `-out.yml` file. The `Reset camera` button always returns to these settings given in the input file: +* `zoom` (`int`): Initial zoom for the camera. Default: `100`. +* `pan`, `tilt`, `roll` (`int`): initial pan, tilt, and roll angles. Default: `0`. From 39ccd7e0df8eff9872f78683f0b337de084f968d Mon Sep 17 00:00:00 2001 From: Leonard Reuter Date: Wed, 15 Jun 2022 14:42:50 +0200 Subject: [PATCH 13/28] Removed two unused yaml nodes from ProcessMaxima.cpp. --- src/Executables/ProcessMaxima.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/Executables/ProcessMaxima.cpp b/src/Executables/ProcessMaxima.cpp index 819a68d5..abda28d5 100644 --- a/src/Executables/ProcessMaxima.cpp +++ b/src/Executables/ProcessMaxima.cpp @@ -139,9 +139,6 @@ int main(int argc, char *argv[]) { auto clusteringNode = inputYaml["Clustering"]; - std::vector> clusterNumberGraphAnalysisResults; - std::vector> totalWeightDifferencesAnalysisResults; - maxima.sortAll(); for (const auto& node : clusteringNode) { auto methodName = node.first.as(); @@ -276,17 +273,7 @@ int main(int argc, char *argv[]) { outputYaml << Key << "Atoms" << Value << atoms << Comment("[a0]") << Key << "Rnn" << Value << Metrics::positionalDistances(atoms.positionsVector()) << Comment("[a0]") << Key << "NSamples" << Value << samples.size() - << Key << "OverallResults" << Value << results - << Key << "ClusterNumberGraphAnalysis" << BeginSeq; - for (const auto & graphAnalysisResult : clusterNumberGraphAnalysisResults) { - outputYaml << YAML::Flow << graphAnalysisResult; - } - outputYaml << EndSeq; - outputYaml << Key << "TotalClusterWeightDifferenceAnalysis" << BeginSeq; - for (const auto & weightDifferenceAnalysisResult : totalWeightDifferencesAnalysisResults) { - outputYaml << YAML::Flow << weightDifferenceAnalysisResult; - } - outputYaml << EndSeq; + << Key << "OverallResults" << Value << results; spdlog::info("Calculating statistics..."); From 8c7c9da6e332872a86bddaf617e3ca278c6d6d0c Mon Sep 17 00:00:00 2001 From: Leonard Reuter Date: Wed, 15 Jun 2022 14:44:04 +0200 Subject: [PATCH 14/28] Made Voxel yaml nodes optional in input. --- src/Executables/ProcessMaxima.cpp | 15 ++++++++++----- .../include/VoxelCubeOverlapCalculation.h | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/Executables/ProcessMaxima.cpp b/src/Executables/ProcessMaxima.cpp index abda28d5..8a09f2e3 100644 --- a/src/Executables/ProcessMaxima.cpp +++ b/src/Executables/ProcessMaxima.cpp @@ -75,7 +75,8 @@ void validateInput(const YAML::Node &inputYaml) { Settings::MaximaProcessing maximaProcessingSettings(inputYaml); validateClusteringSettings(inputYaml); - VoxelCubeGeneration::settings = Settings::VoxelCubeGeneration(inputYaml); + if (inputYaml["VoxelCubeGeneration"]) + VoxelCubeGeneration::settings = Settings::VoxelCubeGeneration(inputYaml); spdlog::set_level(spdlog::level::info); spdlog::info("Input is valid."); @@ -253,11 +254,15 @@ int main(int argc, char *argv[]) { usedSettings["Clustering"] = usedClusteringSettings; - VoxelCubeGeneration::settings = Settings::VoxelCubeGeneration(inputYaml); - VoxelCubeGeneration::settings.appendToNode(usedSettings); + if (inputYaml["VoxelCubeGeneration"]){ + VoxelCubeGeneration::settings = Settings::VoxelCubeGeneration(inputYaml); + VoxelCubeGeneration::settings.appendToNode(usedSettings); + } - VoxelCubeOverlapCalculation::settings = Settings::VoxelCubeOverlapCalculation(inputYaml); - VoxelCubeOverlapCalculation::settings.appendToNode(usedSettings); + if (inputYaml["VoxelCubeOverlapCalculation"]){ + VoxelCubeOverlapCalculation::settings = Settings::VoxelCubeOverlapCalculation(inputYaml); + VoxelCubeOverlapCalculation::settings.appendToNode(usedSettings); + } outputYaml << BeginDoc << Comment("input from \"" + inputFilename + "\"") << inputYaml << EndDoc; diff --git a/src/Methods/MaximaProcessing/include/VoxelCubeOverlapCalculation.h b/src/Methods/MaximaProcessing/include/VoxelCubeOverlapCalculation.h index f68f5095..c48cc760 100644 --- a/src/Methods/MaximaProcessing/include/VoxelCubeOverlapCalculation.h +++ b/src/Methods/MaximaProcessing/include/VoxelCubeOverlapCalculation.h @@ -14,7 +14,7 @@ namespace Settings { class VoxelCubeOverlapCalculation : public ISettings { inline static const std::string className = {VARNAME(VoxelCubeOverlapCalculation)}; public: - Property calculateOverlapQ = {true, VARNAME(calculateOverlapQ)}; + Property calculateOverlapQ = {false, VARNAME(calculateOverlapQ)}; Property dimension = {100, VARNAME(dimension)}; Property length = {20, VARNAME(length)}; From 5c3d68c543a2643fdb1c42e6de8ebe0063f55dd1 Mon Sep 17 00:00:00 2001 From: Leonard Reuter Date: Wed, 15 Jun 2022 14:52:22 +0200 Subject: [PATCH 15/28] Made energy partitioning optional for ProcessMaxima and inPsights. --- docs/USER_MANUAL.md | 2 + src/Executables/ProcessMaxima.cpp | 53 ++++--- .../include/MaximaProcessingSettings.h | 1 + .../include/MaximaProcessor.h | 4 +- .../MaximaProcessing/source/ClusterData.cpp | 96 +++++++++---- .../source/MaximaProcessingSettings.cpp | 2 + .../source/MaximaProcessor.cpp | 132 ++++++++++-------- 7 files changed, 177 insertions(+), 113 deletions(-) diff --git a/docs/USER_MANUAL.md b/docs/USER_MANUAL.md index 506f4526..f5e11b27 100644 --- a/docs/USER_MANUAL.md +++ b/docs/USER_MANUAL.md @@ -20,6 +20,7 @@ MaximaProcessing: samplesToAnalyze: 0 # 0 = all minimalClusterWeight: 0.0 deleteCoreElectrons: false + doEnergyPartitioning: true Clustering: PreClusterer: radius: 0.01 # [a0] @@ -48,6 +49,7 @@ General settings have to be given under the top-level YAML node `MaximaProcessin * `samplesToAnalyze` (`unsigned integer`): Samples/maxima to analyze. A value of `0` means all samples/maxima from the subsequent `.bin` files are processed. * `minimalClusterWeight` (`positive float`): minimal weight of clusters to be printed in the output file . * `deleteCoreElectrons` (`bool`): If `true`, all core electrons are deleted and thus not considered in the clustering or any statistic. +* `doEnergyPartitioning` (`bool`): If `true`, values for energy partitioning are calcularted. Default: `false`. #### Clustering The clustering process is specified under the top level YAML node `Clustering` and consists of a list of clusterers. diff --git a/src/Executables/ProcessMaxima.cpp b/src/Executables/ProcessMaxima.cpp index 8a09f2e3..f60dbadf 100644 --- a/src/Executables/ProcessMaxima.cpp +++ b/src/Executables/ProcessMaxima.cpp @@ -281,42 +281,41 @@ int main(int argc, char *argv[]) { << Key << "OverallResults" << Value << results; spdlog::info("Calculating statistics..."); + MaximaProcessor maximaProcessor(outputYaml, samples, atoms, MaximaProcessing::settings.doEnergyPartitioning()); - MaximaProcessor maximaProcessor(outputYaml, samples, atoms); - - // TODO REFACTOR std::vector>> nucleiMergeLists; - if(inputYaml["MotifMerge"]) { - auto motifMergeNode = inputYaml["MotifMerge"]; - for (YAML::iterator it = motifMergeNode.begin(); it != motifMergeNode.end(); ++it) { - const YAML::Node &nucleiMergeListNode = *it; - - auto nucleiMergeList = it->as>>(); - nucleiMergeLists.emplace_back(nucleiMergeList); + std::vector nucleiIndices(0); + std::vector selections; + if (MaximaProcessing::settings.doEnergyPartitioning()) { + // TODO REFACTOR + if (inputYaml["MotifMerge"]) { + auto motifMergeNode = inputYaml["MotifMerge"]; + for (YAML::iterator it = motifMergeNode.begin(); it != motifMergeNode.end(); ++it) { + const YAML::Node &nucleiMergeListNode = *it; + + auto nucleiMergeList = it->as>>(); + nucleiMergeLists.emplace_back(nucleiMergeList); + } } - } - std::vector selections; - if(inputYaml["EnergySelections"]) { - auto energySelectionNode = inputYaml["EnergySelections"]; - for (YAML::iterator it = energySelectionNode.begin(); it != energySelectionNode.end(); ++it) { - const YAML::Node &node = *it; + if (inputYaml["EnergySelections"]) { + auto energySelectionNode = inputYaml["EnergySelections"]; + for (YAML::iterator it = energySelectionNode.begin(); it != energySelectionNode.end(); ++it) { + const YAML::Node &node = *it; - auto nucleiIndices = node["Nuclei"].as(); - auto nearestElectronsSettings = Settings::ElectronSelection(node["ElectronSelection"], atoms); + auto nucleiIndices = node["Nuclei"].as(); + auto nearestElectronsSettings = Settings::ElectronSelection(node["ElectronSelection"], atoms); - selections.emplace_back(DynamicMolecularSelection(nearestElectronsSettings, nucleiIndices)); + selections.emplace_back(DynamicMolecularSelection(nearestElectronsSettings, nucleiIndices)); + } } - } - - // local particle energies - std::vector nucleiIndices(0); - if(inputYaml["LocalParticleEnergies"]) { - auto collectiveEnergyNode = inputYaml["LocalParticleEnergies"]; - nucleiIndices = collectiveEnergyNode["nuclei"].as>(); + // local particle energies + if (inputYaml["LocalParticleEnergies"]) { + auto collectiveEnergyNode = inputYaml["LocalParticleEnergies"]; + nucleiIndices = collectiveEnergyNode["nuclei"].as>(); + } } - maximaProcessor.calculateStatistics(maxima, nucleiMergeLists, nucleiIndices, selections); outputYaml << EndMap << EndDoc; diff --git a/src/Methods/MaximaProcessing/include/MaximaProcessingSettings.h b/src/Methods/MaximaProcessing/include/MaximaProcessingSettings.h index 9bd9a386..f79b4088 100644 --- a/src/Methods/MaximaProcessing/include/MaximaProcessingSettings.h +++ b/src/Methods/MaximaProcessing/include/MaximaProcessingSettings.h @@ -25,6 +25,7 @@ namespace Settings { Property motifThreshold = {1.00, VARNAME(motifThreshold)}; Property deleteCoreElectrons = {false, VARNAME(deleteCoreElectrons)}; Property printAllMaxima = {false, VARNAME(printAllMaxima)}; + Property doEnergyPartitioning = {false, VARNAME(doEnergyPartitioning)}; MaximaProcessing(); explicit MaximaProcessing(const YAML::Node &node); diff --git a/src/Methods/MaximaProcessing/include/MaximaProcessor.h b/src/Methods/MaximaProcessing/include/MaximaProcessor.h index 76f3c313..5c25cd79 100644 --- a/src/Methods/MaximaProcessing/include/MaximaProcessor.h +++ b/src/Methods/MaximaProcessing/include/MaximaProcessor.h @@ -37,7 +37,8 @@ namespace MotifEnergyCalculator { class MaximaProcessor { public: - MaximaProcessor(YAML::Emitter &yamlDocument, const std::vector &samples, const AtomsVector &atoms); + MaximaProcessor(YAML::Emitter &yamlDocument, const std::vector &samples, const AtomsVector &atoms, + const bool &doEpart); size_t addMaximum(const Maximum &maximum); @@ -61,6 +62,7 @@ class MaximaProcessor { VectorStatistics TeStats_, EeStats_, EnStats_; TriangularMatrixStatistics SeeStats_, VeeStats_, VnnStats_, ReeStats_; MatrixStatistics VenStats_, RenStats_; + bool doEpart_; Eigen::MatrixXd Vnn_; }; diff --git a/src/Methods/MaximaProcessing/source/ClusterData.cpp b/src/Methods/MaximaProcessing/source/ClusterData.cpp index 1b658369..4aec5e01 100644 --- a/src/Methods/MaximaProcessing/source/ClusterData.cpp +++ b/src/Methods/MaximaProcessing/source/ClusterData.cpp @@ -96,7 +96,6 @@ ElectronsVector ClusterData::representativeStructure() const { namespace YAML { Node convert::encode(const ClusterData &rhs) { - // TODO add eigenvalues and eigenvectors? Node node; node["N"] = rhs.N_; node["ValueRange"] = rhs.valueStats_; @@ -131,7 +130,9 @@ namespace YAML { if (node["SedOverlaps"].IsMap() && node["SedOverlaps"][0]) sedOverlaps= node["SedOverlaps"].as(); - auto motifVector = node["Motifs"].as>(); + std::vector motifVector; + if (node["Motifs"]) + motifVector = node["Motifs"].as>(); auto structures = node["Structures"].as>(); @@ -164,22 +165,50 @@ namespace YAML { } } + VectorStatistics TeStats; + if (node["Te"]) + TeStats = node["Te"].as(); + VectorStatistics EeStats; + if (node["Ee"]) + EeStats = node["Te"].as(); + TriangularMatrixStatistics VeeStats; + if (node["Vee"]) + VeeStats = node["Vee"].as(); + MatrixStatistics VenStats; + if (node["Ven"]) + VenStats = node["Ven"].as(); + SingleValueStatistics EtotalStats; + if (node["Etotal"]) + EtotalStats = node["Ven"].as(); + VectorStatistics IntraMotifEnergiesStats; + if (node["IntraMotifEnergies"]) + IntraMotifEnergiesStats = node["IntraMotifEnergies"].as(); + TriangularMatrixStatistics InterMotifEnergiesStats; + if (node["InterMotifEnergies"]) + InterMotifEnergiesStats = node["InterMotifEnergies"].as(); + TriangularMatrixStatistics ReeStats; + if (node["Ree"]) + ReeStats = node["Ree"].as(); + MatrixStatistics RenStats; + if (node["Ren"]) + RenStats = node["Ren"].as(); + rhs = ClusterData( node["N"].as(), structures, sampleAverage, node["ValueRange"].as(), - node["Te"].as(), - node["Ee"].as(), + TeStats, + EeStats, node["SpinCorrelations"].as(), - node["Vee"].as(), - node["Ven"].as(), + VeeStats, + VenStats, Motifs(motifVector), - node["Etotal"].as(), - node["IntraMotifEnergies"].as(), - node["InterMotifEnergies"].as(), - node["Ree"].as(), - node["Ren"].as(), + EtotalStats, + IntraMotifEnergiesStats, + InterMotifEnergiesStats, + ReeStats, + RenStats, cubes, sedOverlaps, subCounts, @@ -194,25 +223,32 @@ namespace YAML { out << BeginMap << Key << "N" << Value << rhs.N_ << Key << "ValueRange" << Value << Comment("[]") << rhs.valueStats_ - << Key << "SampleAverage" << Comment("[a0]") << Value << rhs.sampleAverage_<< Newline - << Key << "Motifs" << Value << rhs.motifs_.motifs_ - << Key << "Etotal" << Comment("[Eh]") << Value << rhs.EtotalStats_ - << Key << "IntraMotifEnergies" << Comment("[Eh]") << Value << rhs.intraMotifEnergyStats_ - << Key << "InterMotifEnergies" << Comment("[Eh]") << Value << rhs.interMotifEnergyStats_ - << Key << "Selections" << Value << rhs.selections_ - << Key << "SelectionEnergyCalculation" << Value << rhs.selectionInteractionEnergies_ - << Key << "Structures" << Comment("[a0]") << Value << rhs.exemplaricStructures_ << Newline - << Key << "SpinCorrelations" << Comment("[]") << Value << rhs.SeeStats_ - << Key << "Ree" << Comment("[a0]") << Value << rhs.ReeStats_ - << Key << "Ren" << Comment("[a0]") << Value << rhs.RenStats_ - << Key << "Te" << Comment("[Eh]") << Value << rhs.electronicEnergyStats_.Te() - << Key << "Ee" << Comment("[Eh]") << Value << rhs.EeStats_ - << Key << "Vee" << Comment("[Eh]") << Value << rhs.electronicEnergyStats_.Vee() - << Key << "Ven" << Comment("[Eh]") << Value << rhs.electronicEnergyStats_.Ven() - << Key << "VoxelCubes" << Value << rhs.voxelCubes_ - << Key << "SedOverlaps" << Value << rhs.overlaps_ - << Key << "SubStructureN" << Value << rhs.subN_ - << EndMap; + << Key << "SampleAverage" << Comment("[a0]") << Value << rhs.sampleAverage_<< Newline; + if (rhs.EtotalStats_.getTotalWeight() > 0) + out << Key << "Etotal" << Comment("[Eh]") << Value << rhs.EtotalStats_; + if (not rhs.motifs_.motifs_.empty()) + out << Key << "Motifs" << Value << rhs.motifs_.motifs_ + << Key << "IntraMotifEnergies" << Comment("[Eh]") << Value << rhs.intraMotifEnergyStats_ + << Key << "InterMotifEnergies" << Comment("[Eh]") << Value << rhs.interMotifEnergyStats_; + if (not rhs.selections_.empty()) + out << Key << "Selections" << Value << rhs.selections_ + << Key << "SelectionEnergyCalculation" << Value << rhs.selectionInteractionEnergies_; + out << Key << "Structures" << Comment("[a0]") << Value << rhs.exemplaricStructures_ << Newline + << Key << "SpinCorrelations" << Comment("[]") << Value << rhs.SeeStats_; + if (rhs.ReeStats_.getTotalWeight() > 0) + out << Key << "Ree" << Comment("[a0]") << Value << rhs.ReeStats_ + << Key << "Ren" << Comment("[a0]") << Value << rhs.RenStats_ + << Key << "Te" << Comment("[Eh]") << Value << rhs.electronicEnergyStats_.Te() + << Key << "Ee" << Comment("[Eh]") << Value << rhs.EeStats_ + << Key << "Vee" << Comment("[Eh]") << Value << rhs.electronicEnergyStats_.Vee() + << Key << "Ven" << Comment("[Eh]") << Value << rhs.electronicEnergyStats_.Ven(); + if (not rhs.voxelCubes_.empty()) + out << Key << "VoxelCubes" << Value << rhs.voxelCubes_; + if (rhs.overlaps_.size() > 0) + out << Key << "SedOverlaps" << Value << rhs.overlaps_; + + out << Key << "SubStructureN" << Value << rhs.subN_ + << EndMap; return out; } diff --git a/src/Methods/MaximaProcessing/source/MaximaProcessingSettings.cpp b/src/Methods/MaximaProcessing/source/MaximaProcessingSettings.cpp index d1e5f23f..6681bd40 100644 --- a/src/Methods/MaximaProcessing/source/MaximaProcessingSettings.cpp +++ b/src/Methods/MaximaProcessing/source/MaximaProcessingSettings.cpp @@ -53,6 +53,7 @@ namespace Settings { doubleProperty ::decode(node[className], motifThreshold); boolProperty ::decode(node[className], deleteCoreElectrons); boolProperty ::decode(node[className], printAllMaxima); + boolProperty ::decode(node[className], doEnergyPartitioning); } void MaximaProcessing::appendToNode(YAML::Node &node) const { @@ -64,6 +65,7 @@ namespace Settings { node[className][motifThreshold.name()] = motifThreshold.get(); node[className][deleteCoreElectrons.name()] = deleteCoreElectrons.get(); node[className][printAllMaxima.name()] = printAllMaxima.get(); + node[className][doEnergyPartitioning.name()] = doEnergyPartitioning.get(); } } diff --git a/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp b/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp index eb120a42..a5e9c603 100644 --- a/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp +++ b/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp @@ -70,15 +70,21 @@ void MotifEnergyCalculator::partitionLowestLevel( } } -MaximaProcessor::MaximaProcessor(YAML::Emitter& yamlDocument, const std::vector& samples, const AtomsVector& atoms) +MaximaProcessor::MaximaProcessor(YAML::Emitter& yamlDocument, + const std::vector& samples, + const AtomsVector& atoms, + const bool& doEpart) : yamlDocument_(yamlDocument), samples_(samples), atoms_(atoms), - Vnn_(CoulombPotential::energies(atoms_)) + Vnn_(CoulombPotential::energies(atoms_)), + doEpart_(doEpart) { - VnnStats_.add(Vnn_); - EnStats_.add(EnergyPartitioning::ParticleBased::oneAtomEnergies(Vnn_)); + if (doEpart_){ + VnnStats_.add(Vnn_); + EnStats_.add(EnergyPartitioning::ParticleBased::oneAtomEnergies(Vnn_)); + } } unsigned long MaximaProcessor::addMaximum(const Maximum &maximum) { @@ -91,30 +97,34 @@ unsigned long MaximaProcessor::addMaximum(const Maximum &maximum) { valueStats_.add(value, count); SeeStats_.add(spinCorrelations_, count); - auto permutedNuclei = maximum.nuclei(); - permutedNuclei.permute(maximum.nuclearPermutation()); - - // Sample related statistics - for (auto & id : maximum.sampleIds()) { - auto & electrons = samples_[id].sample_; - Eigen::VectorXd Te = samples_[id].kineticEnergies_; - Eigen::MatrixXd Vee = CoulombPotential::energies(electrons); - Eigen::MatrixXd Ven = CoulombPotential::energies(electrons, permutedNuclei); - - Eigen::VectorXd Ee = EnergyPartitioning::ParticleBased::oneElectronEnergies(Te, Vee, Ven, Vnn_); // TODO wrong and deprecated -> remove - Eigen::MatrixXd Ree = Metrics::positionalDistances(electrons.positionsVector()); - Eigen::MatrixXd Ren = Metrics::positionalDistances(electrons.positionsVector(), permutedNuclei.positionsVector()); - - TeStats_.add(Te,1); - VeeStats_.add(Vee,1); - VenStats_.add(Ven,1); - EeStats_.add(Ee,1); - ReeStats_.add(Ree,1); - RenStats_.add(Ren,1); - - Eigen::VectorXd Etot(1); - Etot << EnergyPartitioning::calculateTotalEnergy(Te,Vee,Ven, Vnn_); - EtotalStats_.add(Etot); + if (doEpart_) { + auto permutedNuclei = maximum.nuclei(); + permutedNuclei.permute(maximum.nuclearPermutation()); + + // Sample related statistics + for (auto &id: maximum.sampleIds()) { + auto &electrons = samples_[id].sample_; + Eigen::VectorXd Te = samples_[id].kineticEnergies_; + Eigen::MatrixXd Vee = CoulombPotential::energies(electrons); + Eigen::MatrixXd Ven = CoulombPotential::energies(electrons, permutedNuclei); + + Eigen::VectorXd Ee = EnergyPartitioning::ParticleBased::oneElectronEnergies(Te, Vee, Ven, + Vnn_); // TODO wrong and deprecated -> remove + Eigen::MatrixXd Ree = Metrics::positionalDistances(electrons.positionsVector()); + Eigen::MatrixXd Ren = Metrics::positionalDistances(electrons.positionsVector(), + permutedNuclei.positionsVector()); + + TeStats_.add(Te, 1); + VeeStats_.add(Vee, 1); + VenStats_.add(Ven, 1); + EeStats_.add(Ee, 1); + ReeStats_.add(Ree, 1); + RenStats_.add(Ren, 1); + + Eigen::VectorXd Etot(1); + Etot << EnergyPartitioning::calculateTotalEnergy(Te, Vee, Ven, Vnn_); + EtotalStats_.add(Etot); + } } return count; @@ -140,9 +150,11 @@ void MaximaProcessor::calculateStatistics(const Cluster &cluster, ){ using namespace YAML; - yamlDocument_ << Key << "Vnn" << Comment("[Eh]") << Value << VnnStats_ - << Key << "En" << Comment("[Eh]") << Value << EnStats_ - << Key << "Clusters" << BeginSeq; + if (doEpart_) { + yamlDocument_ << Key << "Vnn" << Comment("[Eh]") << Value << VnnStats_ + << Key << "En" << Comment("[Eh]") << Value << EnStats_; + } + yamlDocument_ << Key << "Clusters" << BeginSeq; unsigned totalCount = 0; double totalWeight = 0.0; @@ -156,13 +168,15 @@ void MaximaProcessor::calculateStatistics(const Cluster &cluster, valueStats_.reset(); SeeStats_.reset(); - TeStats_.reset(); - EeStats_.reset(); - VeeStats_.reset(); - VenStats_.reset(); - EtotalStats_.reset(); - ReeStats_.reset(); - RenStats_.reset(); + if (doEpart_) { + TeStats_.reset(); + EeStats_.reset(); + VeeStats_.reset(); + VenStats_.reset(); + EtotalStats_.reset(); + ReeStats_.reset(); + RenStats_.reset(); + } if(subCluster.isLeaf()){ totalCount += addAllMaxima(subCluster); // this sets all statistic objects internally @@ -187,22 +201,30 @@ void MaximaProcessor::calculateStatistics(const Cluster &cluster, // SpinCorrelationDistribution spinCorrelationDistribution.addSpinStatistic(SeeStats_); - - // Motif analysis (requires spin correlation data) - auto adjacencyMatrix = GraphAnalysis::filter(SeeStats_.mean().cwiseAbs(), MaximaProcessing::settings.motifThreshold()); - - auto mol = MolecularGeometry(atoms_, subCluster.representative()->maximum()); - Motifs motifs(adjacencyMatrix, mol); - - // merge motifs - for(const auto& nucleiMergeList : nucleiMergeLists){ - auto motifMergeIndices = motifs.findMotifMergeIndices(mol, nucleiMergeList); - - motifs.mergeMotifs(motifMergeIndices); - } - // Motif energies - auto [intraMotifEnergyStats, interMotifEnergyStats] = MotifEnergyCalculator::partition(subCluster, samples_, motifs); + Motifs motifs; + VectorStatistics intraMotifEnergyStats; + TriangularMatrixStatistics interMotifEnergyStats; + if (doEpart_) { + // Motif analysis (requires spin correlation data) + auto adjacencyMatrix = GraphAnalysis::filter(SeeStats_.mean().cwiseAbs(), + MaximaProcessing::settings.motifThreshold()); + + auto mol = MolecularGeometry(atoms_, subCluster.representative()->maximum()); + motifs = Motifs(adjacencyMatrix, mol); + + // merge motifs + for (const auto &nucleiMergeList: nucleiMergeLists) { + auto motifMergeIndices = motifs.findMotifMergeIndices(mol, nucleiMergeList); + + motifs.mergeMotifs(motifMergeIndices); + } + + // Motif energies + auto[intraMotifEnergyStats_, interMotifEnergyStats_] = MotifEnergyCalculator::partition(subCluster, samples_,motifs); + intraMotifEnergyStats = std::move(intraMotifEnergyStats_); + interMotifEnergyStats = std::move(interMotifEnergyStats_); + } // SEDs std::vector voxelCubes; @@ -214,7 +236,7 @@ void MaximaProcessor::calculateStatistics(const Cluster &cluster, if(VoxelCubeOverlapCalculation::settings.calculateOverlapQ()) overlaps = VoxelCubeOverlapCalculation::fromCluster(subCluster, samples_); - auto weight = double(TeStats_.getTotalWeight())/double(samples_.size()); + auto weight = double(valueStats_.getTotalWeight())/double(samples_.size()); if(weight >= MaximaProcessing::settings.minimalClusterWeight.get()) { selectionEnergyCalculator.addTopLevel(subCluster); @@ -226,7 +248,7 @@ void MaximaProcessor::calculateStatistics(const Cluster &cluster, ElectronsVector sampleAverage = {subCluster.electronsVectorFromAveragedPositionsVector(subCluster.averagedSamplePositionsVector(samples_))}; - yamlDocument_ << ClusterData(TeStats_.getTotalWeight(), maxima, sampleAverage, + yamlDocument_ << ClusterData(valueStats_.getTotalWeight(), maxima, sampleAverage, valueStats_, TeStats_, EeStats_, SeeStats_, VeeStats_, VenStats_, motifs, EtotalStats_, intraMotifEnergyStats, interMotifEnergyStats, From fbc0927b86ddc4eb5f6a40bfbb3e637ce280bbdd Mon Sep 17 00:00:00 2001 From: Leonard Reuter Date: Wed, 15 Jun 2022 18:10:13 +0200 Subject: [PATCH 16/28] Added calculateSpinCorrelations option to MaximaProcessing. --- docs/USER_MANUAL.md | 1 + src/Executables/ProcessMaxima.cpp | 4 ++- src/GUI/source/InPsightsWidget.cpp | 27 ++++++++------ .../include/MaximaProcessingSettings.h | 1 + .../include/MaximaProcessor.h | 4 +-- .../MaximaProcessing/source/ClusterData.cpp | 10 ++++-- .../source/MaximaProcessingSettings.cpp | 4 +++ .../source/MaximaProcessor.cpp | 36 +++++++++++-------- 8 files changed, 56 insertions(+), 31 deletions(-) diff --git a/docs/USER_MANUAL.md b/docs/USER_MANUAL.md index f5e11b27..554f3230 100644 --- a/docs/USER_MANUAL.md +++ b/docs/USER_MANUAL.md @@ -50,6 +50,7 @@ General settings have to be given under the top-level YAML node `MaximaProcessin * `minimalClusterWeight` (`positive float`): minimal weight of clusters to be printed in the output file . * `deleteCoreElectrons` (`bool`): If `true`, all core electrons are deleted and thus not considered in the clustering or any statistic. * `doEnergyPartitioning` (`bool`): If `true`, values for energy partitioning are calcularted. Default: `false`. +* `calculateSpinCorrelations` (`bool`): If `true`, spin correlations are calculated. Has to be true for energy partitioning. Default: `true`. #### Clustering The clustering process is specified under the top level YAML node `Clustering` and consists of a list of clusterers. diff --git a/src/Executables/ProcessMaxima.cpp b/src/Executables/ProcessMaxima.cpp index f60dbadf..e2191ae0 100644 --- a/src/Executables/ProcessMaxima.cpp +++ b/src/Executables/ProcessMaxima.cpp @@ -281,7 +281,9 @@ int main(int argc, char *argv[]) { << Key << "OverallResults" << Value << results; spdlog::info("Calculating statistics..."); - MaximaProcessor maximaProcessor(outputYaml, samples, atoms, MaximaProcessing::settings.doEnergyPartitioning()); + MaximaProcessor maximaProcessor(outputYaml, samples, atoms, + MaximaProcessing::settings.doEnergyPartitioning(), + MaximaProcessing::settings.calculateSpinCorrelations()); std::vector>> nucleiMergeLists; std::vector nucleiIndices(0); diff --git a/src/GUI/source/InPsightsWidget.cpp b/src/GUI/source/InPsightsWidget.cpp index 6b585fc4..03a1cf39 100644 --- a/src/GUI/source/InPsightsWidget.cpp +++ b/src/GUI/source/InPsightsWidget.cpp @@ -190,9 +190,6 @@ void InPsightsWidget::connectSignals() { connect(spinCorrelationsCheckBox, &QCheckBox::stateChanged, this, &InPsightsWidget::onSpinCorrelationsChecked); - connect(spinCorrelationsCheckBox, &QCheckBox::stateChanged, - this, &InPsightsWidget::onSpinCorrelationsChecked); - connect(plotAllCheckBox, &QCheckBox::stateChanged, this, &InPsightsWidget::onPlotAllChecked); @@ -611,19 +608,27 @@ void InPsightsWidget::onAxesChecked(int stateId) { } void InPsightsWidget::onSpinCorrelationsChecked(int stateId) { - moleculeWidget->deleteSpinCorrelations(); - if(Qt::CheckState(stateId) == Qt::Checked) - moleculeWidget->drawSpinCorrelations(clusterCollection_, spinCorrelationBox->value(),true); - else if(Qt::CheckState(stateId) == Qt::PartiallyChecked) - moleculeWidget->drawSpinCorrelations(clusterCollection_, spinCorrelationBox->value(),false); + if (clusterCollection_[0].SeeStats_.getTotalWeight() == 0) { + if ((Qt::CheckState(stateId) == Qt::CheckState::Checked) or (Qt::CheckState(stateId) == Qt::CheckState::PartiallyChecked)) { + spdlog::warn("Spin correlations were not calculated."); + spinCorrelationsCheckBox->setCheckState(Qt::CheckState::Unchecked); + } + } + else { + moleculeWidget->deleteSpinCorrelations(); + if(Qt::CheckState(stateId) == Qt::Checked) + moleculeWidget->drawSpinCorrelations(clusterCollection_, spinCorrelationBox->value(),true); + else if(Qt::CheckState(stateId) == Qt::PartiallyChecked) + moleculeWidget->drawSpinCorrelations(clusterCollection_, spinCorrelationBox->value(),false); + } } -void InPsightsWidget::onSpinCorrelationsBoxChanged(double value) { - redrawSpinDecorations(); +void InPsightsWidget::onSpinCorrelationsBoxChanged(double value){ + if (clusterCollection_[0].SeeStats_.getTotalWeight() > 0) + redrawSpinDecorations(); } void InPsightsWidget::onBondBoxChanged(double value) { - if (bondsCheckBox->isChecked()) { bondsCheckBox->setCheckState(Qt::Unchecked); bondsCheckBox->setCheckState(Qt::Checked); diff --git a/src/Methods/MaximaProcessing/include/MaximaProcessingSettings.h b/src/Methods/MaximaProcessing/include/MaximaProcessingSettings.h index f79b4088..52a65699 100644 --- a/src/Methods/MaximaProcessing/include/MaximaProcessingSettings.h +++ b/src/Methods/MaximaProcessing/include/MaximaProcessingSettings.h @@ -26,6 +26,7 @@ namespace Settings { Property deleteCoreElectrons = {false, VARNAME(deleteCoreElectrons)}; Property printAllMaxima = {false, VARNAME(printAllMaxima)}; Property doEnergyPartitioning = {false, VARNAME(doEnergyPartitioning)}; + Property calculateSpinCorrelations = {true, VARNAME(calculateSpinCorrelations)}; MaximaProcessing(); explicit MaximaProcessing(const YAML::Node &node); diff --git a/src/Methods/MaximaProcessing/include/MaximaProcessor.h b/src/Methods/MaximaProcessing/include/MaximaProcessor.h index 5c25cd79..9adb4b7e 100644 --- a/src/Methods/MaximaProcessing/include/MaximaProcessor.h +++ b/src/Methods/MaximaProcessing/include/MaximaProcessor.h @@ -38,7 +38,7 @@ class MaximaProcessor { public: MaximaProcessor(YAML::Emitter &yamlDocument, const std::vector &samples, const AtomsVector &atoms, - const bool &doEpart); + const bool &doEpart, const bool &calcSpinCorr); size_t addMaximum(const Maximum &maximum); @@ -62,7 +62,7 @@ class MaximaProcessor { VectorStatistics TeStats_, EeStats_, EnStats_; TriangularMatrixStatistics SeeStats_, VeeStats_, VnnStats_, ReeStats_; MatrixStatistics VenStats_, RenStats_; - bool doEpart_; + bool doEpart_, calcSpinCorr_; Eigen::MatrixXd Vnn_; }; diff --git a/src/Methods/MaximaProcessing/source/ClusterData.cpp b/src/Methods/MaximaProcessing/source/ClusterData.cpp index 4aec5e01..93cf1fd3 100644 --- a/src/Methods/MaximaProcessing/source/ClusterData.cpp +++ b/src/Methods/MaximaProcessing/source/ClusterData.cpp @@ -171,6 +171,9 @@ namespace YAML { VectorStatistics EeStats; if (node["Ee"]) EeStats = node["Te"].as(); + TriangularMatrixStatistics SpinCorrelationsStats; + if (node["SpinCorrelations"]) + SpinCorrelationsStats = node["SpinCorrelations"].as(); TriangularMatrixStatistics VeeStats; if (node["Vee"]) VeeStats = node["Vee"].as(); @@ -200,7 +203,7 @@ namespace YAML { node["ValueRange"].as(), TeStats, EeStats, - node["SpinCorrelations"].as(), + SpinCorrelationsStats, VeeStats, VenStats, Motifs(motifVector), @@ -233,8 +236,9 @@ namespace YAML { if (not rhs.selections_.empty()) out << Key << "Selections" << Value << rhs.selections_ << Key << "SelectionEnergyCalculation" << Value << rhs.selectionInteractionEnergies_; - out << Key << "Structures" << Comment("[a0]") << Value << rhs.exemplaricStructures_ << Newline - << Key << "SpinCorrelations" << Comment("[]") << Value << rhs.SeeStats_; + out << Key << "Structures" << Comment("[a0]") << Value << rhs.exemplaricStructures_ << Newline; + if (rhs.SeeStats_.getTotalWeight() > 0) + out << Key << "SpinCorrelations" << Comment("[]") << Value << rhs.SeeStats_; if (rhs.ReeStats_.getTotalWeight() > 0) out << Key << "Ree" << Comment("[a0]") << Value << rhs.ReeStats_ << Key << "Ren" << Comment("[a0]") << Value << rhs.RenStats_ diff --git a/src/Methods/MaximaProcessing/source/MaximaProcessingSettings.cpp b/src/Methods/MaximaProcessing/source/MaximaProcessingSettings.cpp index 6681bd40..4aca8b55 100644 --- a/src/Methods/MaximaProcessing/source/MaximaProcessingSettings.cpp +++ b/src/Methods/MaximaProcessing/source/MaximaProcessingSettings.cpp @@ -54,6 +54,9 @@ namespace Settings { boolProperty ::decode(node[className], deleteCoreElectrons); boolProperty ::decode(node[className], printAllMaxima); boolProperty ::decode(node[className], doEnergyPartitioning); + boolProperty ::decode(node[className], calculateSpinCorrelations); + if (doEnergyPartitioning.get() and not calculateSpinCorrelations.get()) + throw std::invalid_argument("calcSpinCorrelation has to be true, if doEnergyPartitioning is true."); } void MaximaProcessing::appendToNode(YAML::Node &node) const { @@ -66,6 +69,7 @@ namespace Settings { node[className][deleteCoreElectrons.name()] = deleteCoreElectrons.get(); node[className][printAllMaxima.name()] = printAllMaxima.get(); node[className][doEnergyPartitioning.name()] = doEnergyPartitioning.get(); + node[className][calculateSpinCorrelations.name()] = calculateSpinCorrelations.get(); } } diff --git a/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp b/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp index a5e9c603..c85bbc35 100644 --- a/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp +++ b/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp @@ -73,15 +73,17 @@ void MotifEnergyCalculator::partitionLowestLevel( MaximaProcessor::MaximaProcessor(YAML::Emitter& yamlDocument, const std::vector& samples, const AtomsVector& atoms, - const bool& doEpart) + const bool& doEpart, + const bool &calcSpinCorr) : yamlDocument_(yamlDocument), samples_(samples), atoms_(atoms), - Vnn_(CoulombPotential::energies(atoms_)), - doEpart_(doEpart) + doEpart_(doEpart), + calcSpinCorr_(calcSpinCorr) { if (doEpart_){ + Vnn_ = CoulombPotential::energies(atoms_); VnnStats_.add(Vnn_); EnStats_.add(EnergyPartitioning::ParticleBased::oneAtomEnergies(Vnn_)); } @@ -90,12 +92,13 @@ MaximaProcessor::MaximaProcessor(YAML::Emitter& yamlDocument, unsigned long MaximaProcessor::addMaximum(const Maximum &maximum) { auto count = unsigned(maximum.count()); - Eigen::VectorXd value = Eigen::VectorXd::Constant(1, maximum.value()); - Eigen::MatrixXd spinCorrelations_ = SpinCorrelation::spinCorrelations(maximum.maximum().typesVector()).cast(); - // Maximum related statistics + Eigen::VectorXd value = Eigen::VectorXd::Constant(1, maximum.value()); valueStats_.add(value, count); - SeeStats_.add(spinCorrelations_, count); + if (calcSpinCorr_){ + Eigen::MatrixXd spinCorrelations_ = SpinCorrelation::spinCorrelations(maximum.maximum().typesVector()).cast(); + SeeStats_.add(spinCorrelations_, count); + } if (doEpart_) { auto permutedNuclei = maximum.nuclei(); @@ -167,7 +170,9 @@ void MaximaProcessor::calculateStatistics(const Cluster &cluster, std::vector subSubClusterCounts; valueStats_.reset(); - SeeStats_.reset(); + if (calcSpinCorr_) { + SeeStats_.reset(); + } if (doEpart_) { TeStats_.reset(); EeStats_.reset(); @@ -200,7 +205,8 @@ void MaximaProcessor::calculateStatistics(const Cluster &cluster, maxima.resize(maximalNumberOfStructuresToPrint); // SpinCorrelationDistribution - spinCorrelationDistribution.addSpinStatistic(SeeStats_); + if (calcSpinCorr_) + spinCorrelationDistribution.addSpinStatistic(SeeStats_); Motifs motifs; VectorStatistics intraMotifEnergyStats; @@ -266,11 +272,13 @@ void MaximaProcessor::calculateStatistics(const Cluster &cluster, yamlDocument_ << EndSeq; // add spinCorrelationDistribution - auto hist = spinCorrelationDistribution.getHistogramVector(); - hist /= hist.sum(); - yamlDocument_ << Key << "SpinCorrelationDistribution" << Value << hist; - yamlDocument_ << Key << "SelectionEnergyCalculation" << Value << selectionEnergyCalculator.selectionInteractions_; - + if (calcSpinCorr_){ + auto hist = spinCorrelationDistribution.getHistogramVector(); + hist /= hist.sum(); + yamlDocument_ << Key << "SpinCorrelationDistribution" << Value << hist; + } + if (doEpart_) + yamlDocument_ << Key << "SelectionEnergyCalculation" << Value << selectionEnergyCalculator.selectionInteractions_; assert(yamlDocument_.good()); } From 002938f7987117099bd420db522f3137f101f3ed Mon Sep 17 00:00:00 2001 From: Leonard Reuter Date: Wed, 15 Jun 2022 18:12:51 +0200 Subject: [PATCH 17/28] Improved and renamed maximalStructuresNumber option. --- docs/USER_MANUAL.md | 1 + .../include/MaximaProcessingSettings.h | 2 +- .../source/MaximaProcessingSettings.cpp | 10 +++++----- .../MaximaProcessing/source/MaximaProcessor.cpp | 6 ++++-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/USER_MANUAL.md b/docs/USER_MANUAL.md index 554f3230..aeea502a 100644 --- a/docs/USER_MANUAL.md +++ b/docs/USER_MANUAL.md @@ -51,6 +51,7 @@ General settings have to be given under the top-level YAML node `MaximaProcessin * `deleteCoreElectrons` (`bool`): If `true`, all core electrons are deleted and thus not considered in the clustering or any statistic. * `doEnergyPartitioning` (`bool`): If `true`, values for energy partitioning are calcularted. Default: `false`. * `calculateSpinCorrelations` (`bool`): If `true`, spin correlations are calculated. Has to be true for energy partitioning. Default: `true`. +* `maximalStructuresNumber` (`int`): If given, restricts the number of structures, that are saved per cluster. #### Clustering The clustering process is specified under the top level YAML node `Clustering` and consists of a list of clusterers. diff --git a/src/Methods/MaximaProcessing/include/MaximaProcessingSettings.h b/src/Methods/MaximaProcessing/include/MaximaProcessingSettings.h index 52a65699..eb1ed7d2 100644 --- a/src/Methods/MaximaProcessing/include/MaximaProcessingSettings.h +++ b/src/Methods/MaximaProcessing/include/MaximaProcessingSettings.h @@ -21,7 +21,7 @@ namespace Settings { Property binaryFileBasename = {"(name of the .yml input file)", VARNAME(binaryFileBasename)}; Property samplesToAnalyze = {unsigned(SamplesToAnalyze::small), VARNAME(samplesToAnalyze)}; Property minimalClusterWeight = {0.01, VARNAME(minimalClusterWeight)}; - Property maximalNumberOfStructuresToPrint = {std::numeric_limits::max(), VARNAME(maximalNumberOfStructuresToPrint)}; + Property maximalStructuresNumber = {std::numeric_limits::max(), VARNAME(maximalStructuresNumber)}; Property motifThreshold = {1.00, VARNAME(motifThreshold)}; Property deleteCoreElectrons = {false, VARNAME(deleteCoreElectrons)}; Property printAllMaxima = {false, VARNAME(printAllMaxima)}; diff --git a/src/Methods/MaximaProcessing/source/MaximaProcessingSettings.cpp b/src/Methods/MaximaProcessing/source/MaximaProcessingSettings.cpp index 4aca8b55..f2a522f3 100644 --- a/src/Methods/MaximaProcessing/source/MaximaProcessingSettings.cpp +++ b/src/Methods/MaximaProcessing/source/MaximaProcessingSettings.cpp @@ -28,10 +28,10 @@ namespace Settings { else if (value >= 1.0) throw std::invalid_argument("The minimal cluster weight cannot be 1 or larger."); }); - maximalNumberOfStructuresToPrint.onChange_.connect( + maximalStructuresNumber.onChange_.connect( [&](unsigned value) { - if (value < 0) - throw std::invalid_argument("The maximal number of structures to print cannot be negative."); + if (value < 1) + throw std::invalid_argument("The maximal number of structures to print cannot be less than 1."); }); motifThreshold.onChange_.connect( @@ -49,7 +49,7 @@ namespace Settings { unsignedProperty::decode(node[className], seed); unsignedProperty::decode(node[className], samplesToAnalyze); doubleProperty ::decode(node[className], minimalClusterWeight); - unsignedProperty::decode(node[className], maximalNumberOfStructuresToPrint); + unsignedProperty::decode(node[className], maximalStructuresNumber); doubleProperty ::decode(node[className], motifThreshold); boolProperty ::decode(node[className], deleteCoreElectrons); boolProperty ::decode(node[className], printAllMaxima); @@ -64,7 +64,7 @@ namespace Settings { node[className][binaryFileBasename.name()] = binaryFileBasename.get(); node[className][samplesToAnalyze.name()] = samplesToAnalyze.get(); node[className][minimalClusterWeight.name()] = minimalClusterWeight.get(); - node[className][maximalNumberOfStructuresToPrint.name()] = maximalNumberOfStructuresToPrint.get(); + node[className][maximalStructuresNumber.name()] = maximalStructuresNumber.get(); node[className][motifThreshold.name()] = motifThreshold.get(); node[className][deleteCoreElectrons.name()] = deleteCoreElectrons.get(); node[className][printAllMaxima.name()] = printAllMaxima.get(); diff --git a/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp b/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp index c85bbc35..ea6d715e 100644 --- a/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp +++ b/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp @@ -193,7 +193,7 @@ void MaximaProcessor::calculateStatistics(const Cluster &cluster, } } - auto maximalNumberOfStructuresToPrint = MaximaProcessing::settings.maximalNumberOfStructuresToPrint(); + auto maximalNumberOfStructuresToPrint = MaximaProcessing::settings.maximalStructuresNumber(); std::vector maxima; if(MaximaProcessing::settings.printAllMaxima()) @@ -201,8 +201,10 @@ void MaximaProcessor::calculateStatistics(const Cluster &cluster, else maxima = subCluster.getAllRepresentativeMaxima(); - if(maxima.size() > maximalNumberOfStructuresToPrint) + if(maxima.size() > maximalNumberOfStructuresToPrint) { maxima.resize(maximalNumberOfStructuresToPrint); + subSubClusterCounts.resize(maximalNumberOfStructuresToPrint); + } // SpinCorrelationDistribution if (calcSpinCorr_) From a60b922286fdc6daa369a755a96b637cef9b5c93 Mon Sep 17 00:00:00 2001 From: Leonard Reuter Date: Tue, 21 Jun 2022 11:55:37 +0200 Subject: [PATCH 18/28] Made Clustering optional for ProcessMaxima. --- src/Executables/ProcessMaxima.cpp | 259 +++++++++++++++--------------- 1 file changed, 132 insertions(+), 127 deletions(-) diff --git a/src/Executables/ProcessMaxima.cpp b/src/Executables/ProcessMaxima.cpp index e2191ae0..dcf35674 100644 --- a/src/Executables/ProcessMaxima.cpp +++ b/src/Executables/ProcessMaxima.cpp @@ -28,44 +28,46 @@ using namespace YAML; void validateClusteringSettings(const YAML::Node &inputYaml) { - auto clusteringNode = inputYaml["Clustering"]; + if (inputYaml["Clustering"]){ + auto clusteringNode = inputYaml["Clustering"]; - for (const auto& node : clusteringNode) { - auto methodName = node.first.as(); + for (const auto& node : clusteringNode) { + auto methodName = node.first.as(); - switch (IProcess::typeFromString(methodName)) { - case IProcess::ProcessType::IdentityClusterer: { - IdentityClusterer::settings = Settings::IdentityClusterer(clusteringNode); - break; - } - case IProcess::ProcessType::DistanceClusterer: { - PreClusterer::settings = Settings::PreClusterer(clusteringNode); - break; - } - case IProcess::ProcessType::DensityBasedClusterer: { - DensityBasedClusterer::settings = Settings::DensityBasedClusterer(clusteringNode); - break; - } - case IProcess::ProcessType::ReferencePositionsClusterer: { - ReferencePositionsClusterer::settings = Settings::ReferencePositionsClusterer(clusteringNode); - break; - } - case IProcess::ProcessType::SOAPClusterer: { - SOAPClusterer::settings = Settings::SOAPClusterer(clusteringNode); - - auto soapSettings = node.second["SOAP"]; - if (soapSettings[SOAP::General::settings.name()]) - SOAP::General::settings = Settings::SOAP::General(soapSettings); - if (soapSettings[SOAP::Radial::settings.name()]) - SOAP::Radial::settings = Settings::SOAP::Radial(soapSettings); - if (soapSettings[SOAP::Angular::settings.name()]) - SOAP::Angular::settings = Settings::SOAP::Angular(soapSettings); - if (soapSettings[SOAP::Cutoff::settings.name()]) - SOAP::Cutoff::settings = Settings::SOAP::Cutoff(soapSettings); - break; + switch (IProcess::typeFromString(methodName)) { + case IProcess::ProcessType::IdentityClusterer: { + IdentityClusterer::settings = Settings::IdentityClusterer(clusteringNode); + break; + } + case IProcess::ProcessType::DistanceClusterer: { + PreClusterer::settings = Settings::PreClusterer(clusteringNode); + break; + } + case IProcess::ProcessType::DensityBasedClusterer: { + DensityBasedClusterer::settings = Settings::DensityBasedClusterer(clusteringNode); + break; + } + case IProcess::ProcessType::ReferencePositionsClusterer: { + ReferencePositionsClusterer::settings = Settings::ReferencePositionsClusterer(clusteringNode); + break; + } + case IProcess::ProcessType::SOAPClusterer: { + SOAPClusterer::settings = Settings::SOAPClusterer(clusteringNode); + + auto soapSettings = node.second["SOAP"]; + if (soapSettings[SOAP::General::settings.name()]) + SOAP::General::settings = Settings::SOAP::General(soapSettings); + if (soapSettings[SOAP::Radial::settings.name()]) + SOAP::Radial::settings = Settings::SOAP::Radial(soapSettings); + if (soapSettings[SOAP::Angular::settings.name()]) + SOAP::Angular::settings = Settings::SOAP::Angular(soapSettings); + if (soapSettings[SOAP::Cutoff::settings.name()]) + SOAP::Cutoff::settings = Settings::SOAP::Cutoff(soapSettings); + break; + } + default: + throw std::invalid_argument("Unknown clustering method \"" + methodName + "\"."); } - default: - throw std::invalid_argument("Unknown clustering method \"" + methodName + "\"."); } } } @@ -135,124 +137,127 @@ int main(int argc, char *argv[]) { auto valueStandardError = results.valueStats_.standardError()(0, 0); // write used settings - YAML::Node usedSettings, usedClusteringSettings; + YAML::Node usedSettings; MaximaProcessing::settings.appendToNode(usedSettings); - auto clusteringNode = inputYaml["Clustering"]; - - maxima.sortAll(); - for (const auto& node : clusteringNode) { - auto methodName = node.first.as(); - spdlog::info("Starting {}...", methodName); + if (inputYaml["Clustering"]){ + YAML::Node usedClusteringSettings; + auto clusteringNode = inputYaml["Clustering"]; - if (usedClusteringSettings[methodName]) - spdlog::warn("Method \"{}\" is being applied multiple times! Overwriting old settings...", methodName); + maxima.sortAll(); + for (const auto& node : clusteringNode) { + auto methodName = node.first.as(); + spdlog::info("Starting {}...", methodName); - switch (IProcess::typeFromString(methodName)) { - case IProcess::ProcessType::IdentityClusterer: { - auto &settings = IdentityClusterer::settings; + if (usedClusteringSettings[methodName]) + spdlog::warn("Method \"{}\" is being applied multiple times! Overwriting old settings...", methodName); - settings = Settings::IdentityClusterer(node.second); + switch (IProcess::typeFromString(methodName)) { + case IProcess::ProcessType::IdentityClusterer: { + auto &settings = IdentityClusterer::settings; - IdentityClusterer identityClusterer(samples); - if (!node.second[settings.valueIncrement.name()]) - settings.valueIncrement = valueStandardError * 1e-4; + settings = Settings::IdentityClusterer(node.second); - identityClusterer.cluster(maxima); + IdentityClusterer identityClusterer(samples); + if (!node.second[settings.valueIncrement.name()]) + settings.valueIncrement = valueStandardError * 1e-4; - settings.appendToNode(usedClusteringSettings); - break; - } - case IProcess::ProcessType::DistanceClusterer: { - auto &settings = PreClusterer::settings; + identityClusterer.cluster(maxima); - settings = Settings::PreClusterer(node.second); - - PreClusterer distanceClusterer(samples); - if (!node.second[settings.valueIncrement.name()]) - settings.valueIncrement = valueStandardError * 1e-2; - distanceClusterer.cluster(maxima); + settings.appendToNode(usedClusteringSettings); + break; + } + case IProcess::ProcessType::DistanceClusterer: { + auto &settings = PreClusterer::settings; - settings.appendToNode(usedClusteringSettings); - break; - } - case IProcess::ProcessType::DensityBasedClusterer: { - auto &settings = DensityBasedClusterer::settings; + settings = Settings::PreClusterer(node.second); - settings = Settings::DensityBasedClusterer(node.second); + PreClusterer distanceClusterer(samples); + if (!node.second[settings.valueIncrement.name()]) + settings.valueIncrement = valueStandardError * 1e-2; + distanceClusterer.cluster(maxima); - if(settings.local()) { - auto electronSelectionSettings = node.second[VARNAME(ElectronSelection)]; - if (electronSelectionSettings) - ElectronSelection::settings = Settings::ElectronSelection(electronSelectionSettings, atoms); + settings.appendToNode(usedClusteringSettings); + break; } + case IProcess::ProcessType::DensityBasedClusterer: { + auto &settings = DensityBasedClusterer::settings; - DensityBasedClusterer densityBasedClusterer(samples); - densityBasedClusterer.cluster(maxima); + settings = Settings::DensityBasedClusterer(node.second); - if(settings.local()) { - ElectronSelection::settings.appendToNode(usedClusteringSettings); // TODO FIX USED SETTINGS APPEND - } + if(settings.local()) { + auto electronSelectionSettings = node.second[VARNAME(ElectronSelection)]; + if (electronSelectionSettings) + ElectronSelection::settings = Settings::ElectronSelection(electronSelectionSettings, atoms); + } - settings.appendToNode(usedClusteringSettings); - break; - } - case IProcess::ProcessType::ReferencePositionsClusterer: { - auto &settings = ReferencePositionsClusterer::settings; + DensityBasedClusterer densityBasedClusterer(samples); + densityBasedClusterer.cluster(maxima); - settings = Settings::ReferencePositionsClusterer(node.second); + if(settings.local()) { + ElectronSelection::settings.appendToNode(usedClusteringSettings); // TODO FIX USED SETTINGS APPEND + } - if(settings.local()) { - auto electronSelectionSettings = node.second[VARNAME(ElectronSelection)]; - if (electronSelectionSettings) - ElectronSelection::settings = Settings::ElectronSelection(electronSelectionSettings, atoms); + settings.appendToNode(usedClusteringSettings); + break; } - ReferencePositionsClusterer ReferencePositionsClusterer(samples); - ReferencePositionsClusterer.cluster(maxima); + case IProcess::ProcessType::ReferencePositionsClusterer: { + auto &settings = ReferencePositionsClusterer::settings; - settings.appendToNode(usedClusteringSettings); + settings = Settings::ReferencePositionsClusterer(node.second); - if(settings.local()) { - ElectronSelection::settings.appendToNode(usedClusteringSettings); // TODO FIX USED SETTINGS APPEND - } + if(settings.local()) { + auto electronSelectionSettings = node.second[VARNAME(ElectronSelection)]; + if (electronSelectionSettings) + ElectronSelection::settings = Settings::ElectronSelection(electronSelectionSettings, atoms); + } + ReferencePositionsClusterer ReferencePositionsClusterer(samples); + ReferencePositionsClusterer.cluster(maxima); - break; - } - case IProcess::ProcessType::SOAPClusterer: { - auto &settings = SOAPClusterer::settings; - - settings = Settings::SOAPClusterer(node.second); - - auto soapSettings = node.second["SOAP"]; //TODO what if node "SOAP" is not present? - if (soapSettings[SOAP::General::settings.name()]) - SOAP::General::settings = Settings::SOAP::General(soapSettings); - if (soapSettings[SOAP::Radial::settings.name()]) - SOAP::Radial::settings = Settings::SOAP::Radial(soapSettings); - if (soapSettings[SOAP::Angular::settings.name()]) - SOAP::Angular::settings = Settings::SOAP::Angular(soapSettings); - if (soapSettings[SOAP::Cutoff::settings.name()]) - SOAP::Cutoff::settings = Settings::SOAP::Cutoff(soapSettings); - - SOAPClusterer sOAPClusterer(atoms, samples); - sOAPClusterer.cluster(maxima); - - settings.appendToNode(usedClusteringSettings); - auto usedSoapSettings = usedClusteringSettings[settings.name()]["SOAP"]; - SOAP::General::settings.appendToNode(usedSoapSettings); - SOAP::Radial::settings.appendToNode(usedSoapSettings); - SOAP::Angular::settings.appendToNode(usedSoapSettings); - SOAP::Cutoff::settings.appendToNode(usedSoapSettings); + settings.appendToNode(usedClusteringSettings); - break; + if(settings.local()) { + ElectronSelection::settings.appendToNode(usedClusteringSettings); // TODO FIX USED SETTINGS APPEND + } + + break; + } + case IProcess::ProcessType::SOAPClusterer: { + auto &settings = SOAPClusterer::settings; + + settings = Settings::SOAPClusterer(node.second); + + auto soapSettings = node.second["SOAP"]; //TODO what if node "SOAP" is not present? + if (soapSettings[SOAP::General::settings.name()]) + SOAP::General::settings = Settings::SOAP::General(soapSettings); + if (soapSettings[SOAP::Radial::settings.name()]) + SOAP::Radial::settings = Settings::SOAP::Radial(soapSettings); + if (soapSettings[SOAP::Angular::settings.name()]) + SOAP::Angular::settings = Settings::SOAP::Angular(soapSettings); + if (soapSettings[SOAP::Cutoff::settings.name()]) + SOAP::Cutoff::settings = Settings::SOAP::Cutoff(soapSettings); + + SOAPClusterer sOAPClusterer(atoms, samples); + sOAPClusterer.cluster(maxima); + + settings.appendToNode(usedClusteringSettings); + auto usedSoapSettings = usedClusteringSettings[settings.name()]["SOAP"]; + SOAP::General::settings.appendToNode(usedSoapSettings); + SOAP::Radial::settings.appendToNode(usedSoapSettings); + SOAP::Angular::settings.appendToNode(usedSoapSettings); + SOAP::Cutoff::settings.appendToNode(usedSoapSettings); + + break; + } + default: + throw std::invalid_argument("Unknown clustering method \"" + methodName + "\"."); } - default: - throw std::invalid_argument("Unknown clustering method \"" + methodName + "\"."); + spdlog::info("number of elements after {}: {}", methodName, maxima.size()); } - spdlog::info("number of elements after {}: {}", methodName, maxima.size()); - } - maxima.sortAll(); + maxima.sortAll(); - usedSettings["Clustering"] = usedClusteringSettings; + usedSettings["Clustering"] = usedClusteringSettings; + } if (inputYaml["VoxelCubeGeneration"]){ VoxelCubeGeneration::settings = Settings::VoxelCubeGeneration(inputYaml); From 8ec7ce750c86319af98c76f30feb7d45f1ec7f8b Mon Sep 17 00:00:00 2001 From: Leonard Reuter Date: Tue, 21 Jun 2022 12:09:20 +0200 Subject: [PATCH 19/28] Made shuffleMaxima optional in ProcessMaxima. --- docs/USER_MANUAL.md | 1 + src/Executables/ProcessMaxima.cpp | 4 +++- .../include/MaximaProcessingSettings.h | 1 + .../MaximaProcessing/include/RawDataReader.h | 4 ++-- .../source/MaximaProcessingSettings.cpp | 2 ++ .../MaximaProcessing/source/RawDataReader.cpp | 24 ++++++++++--------- 6 files changed, 22 insertions(+), 14 deletions(-) diff --git a/docs/USER_MANUAL.md b/docs/USER_MANUAL.md index aeea502a..58045a2c 100644 --- a/docs/USER_MANUAL.md +++ b/docs/USER_MANUAL.md @@ -52,6 +52,7 @@ General settings have to be given under the top-level YAML node `MaximaProcessin * `doEnergyPartitioning` (`bool`): If `true`, values for energy partitioning are calcularted. Default: `false`. * `calculateSpinCorrelations` (`bool`): If `true`, spin correlations are calculated. Has to be true for energy partitioning. Default: `true`. * `maximalStructuresNumber` (`int`): If given, restricts the number of structures, that are saved per cluster. +* `shuffleMaxima` (`bool`): if `true`, all maxima are randomly permuted to avoid method artifacts. Default: `true` #### Clustering The clustering process is specified under the top level YAML node `Clustering` and consists of a list of clusterers. diff --git a/src/Executables/ProcessMaxima.cpp b/src/Executables/ProcessMaxima.cpp index dcf35674..117f096f 100644 --- a/src/Executables/ProcessMaxima.cpp +++ b/src/Executables/ProcessMaxima.cpp @@ -127,7 +127,9 @@ int main(int argc, char *argv[]) { std::vector samples; RawDataReader reader(maxima, samples); - reader.read(MaximaProcessing::settings.binaryFileBasename(), MaximaProcessing::settings.samplesToAnalyze()); + reader.read(MaximaProcessing::settings.binaryFileBasename(), + MaximaProcessing::settings.samplesToAnalyze(), + MaximaProcessing::settings.shuffleMaxima()); auto atoms = reader.getAtoms(); spdlog::info("number of inital refs {}", maxima.size()); diff --git a/src/Methods/MaximaProcessing/include/MaximaProcessingSettings.h b/src/Methods/MaximaProcessing/include/MaximaProcessingSettings.h index eb1ed7d2..64ec2b64 100644 --- a/src/Methods/MaximaProcessing/include/MaximaProcessingSettings.h +++ b/src/Methods/MaximaProcessing/include/MaximaProcessingSettings.h @@ -27,6 +27,7 @@ namespace Settings { Property printAllMaxima = {false, VARNAME(printAllMaxima)}; Property doEnergyPartitioning = {false, VARNAME(doEnergyPartitioning)}; Property calculateSpinCorrelations = {true, VARNAME(calculateSpinCorrelations)}; + Property shuffleMaxima = {true, VARNAME(shuffleMaxima)}; MaximaProcessing(); explicit MaximaProcessing(const YAML::Node &node); diff --git a/src/Methods/MaximaProcessing/include/RawDataReader.h b/src/Methods/MaximaProcessing/include/RawDataReader.h index 8fe81afe..86ed1b16 100644 --- a/src/Methods/MaximaProcessing/include/RawDataReader.h +++ b/src/Methods/MaximaProcessing/include/RawDataReader.h @@ -17,7 +17,7 @@ class RawDataReader : public BinaryFileReader{ void read(const std::string& basename) override; - void read(const std::string& basename, size_t numberOfSamples); + void read(const std::string& basename, size_t numberOfSamples, bool shuffle); std::pair removeNonValenceElectrons(const Sample &sample, const Maximum &reference); @@ -27,7 +27,7 @@ class RawDataReader : public BinaryFileReader{ void readHeader(std::ifstream& input); void readAtomsHeader(std::ifstream &input); void readElectronsHeader(std::ifstream &input); - void readSamplesAndMaxima(std::ifstream &input, int fileLength, size_t numberOfSamples); + void readSamplesAndMaxima(std::ifstream &input, int fileLength, size_t numberOfSamples, bool shuffle); std::string zeroPadNumber(int num); long long int getFileLength(std::ifstream &input) const; std::string getFilename(const std::string &basename, unsigned fileCounter); diff --git a/src/Methods/MaximaProcessing/source/MaximaProcessingSettings.cpp b/src/Methods/MaximaProcessing/source/MaximaProcessingSettings.cpp index f2a522f3..3e02e67a 100644 --- a/src/Methods/MaximaProcessing/source/MaximaProcessingSettings.cpp +++ b/src/Methods/MaximaProcessing/source/MaximaProcessingSettings.cpp @@ -55,6 +55,7 @@ namespace Settings { boolProperty ::decode(node[className], printAllMaxima); boolProperty ::decode(node[className], doEnergyPartitioning); boolProperty ::decode(node[className], calculateSpinCorrelations); + boolProperty ::decode(node[className], shuffleMaxima); if (doEnergyPartitioning.get() and not calculateSpinCorrelations.get()) throw std::invalid_argument("calcSpinCorrelation has to be true, if doEnergyPartitioning is true."); } @@ -70,6 +71,7 @@ namespace Settings { node[className][printAllMaxima.name()] = printAllMaxima.get(); node[className][doEnergyPartitioning.name()] = doEnergyPartitioning.get(); node[className][calculateSpinCorrelations.name()] = calculateSpinCorrelations.get(); + node[className][shuffleMaxima.name()] = shuffleMaxima.get(); } } diff --git a/src/Methods/MaximaProcessing/source/RawDataReader.cpp b/src/Methods/MaximaProcessing/source/RawDataReader.cpp index 4c724b5f..5434ee63 100644 --- a/src/Methods/MaximaProcessing/source/RawDataReader.cpp +++ b/src/Methods/MaximaProcessing/source/RawDataReader.cpp @@ -22,7 +22,7 @@ RawDataReader::RawDataReader( void RawDataReader::read(const std::string &basename) { - read(basename, std::numeric_limits::max()); // read all samples + read(basename, std::numeric_limits::max(), false); // read all samples } void RawDataReader::readAtomsHeader(std::ifstream &input) { @@ -45,7 +45,7 @@ void RawDataReader::readAtomsHeader(std::ifstream &input) { atoms_ = AtomsVector(PositionsVector(atomCoords), elementTypes); } -void RawDataReader::readSamplesAndMaxima(std::ifstream &input, int fileLength, size_t numberOfSamples) { +void RawDataReader::readSamplesAndMaxima(std::ifstream &input, int fileLength, size_t numberOfSamples, bool shuffle) { auto ne = spins_.numberOfEntities(); while (checkEOF(input, fileLength) && id_ < numberOfSamples) { @@ -75,17 +75,19 @@ void RawDataReader::readSamplesAndMaxima(std::ifstream &input, int fileLength, s id_++; } - // Random shuffled vector to remove method artifacts - Eigen::PermutationMatrix perm(ne); - perm.setIdentity(); - for(auto& ref : maxima_){ - std::shuffle(perm.indices().data(), perm.indices().data()+perm.indices().size(), - std::mt19937(MaximaProcessing::settings.seed())); - ref.permuteAll(perm,samples_); + if (shuffle) { + // Random shuffled vector to remove method artifacts + Eigen::PermutationMatrix perm(ne); + perm.setIdentity(); + for (auto &ref: maxima_) { + std::shuffle(perm.indices().data(), perm.indices().data() + perm.indices().size(), + std::mt19937(MaximaProcessing::settings.seed())); + ref.permuteAll(perm, samples_); + } } } -void RawDataReader::read(const std::string &basename, size_t numberOfSamples){ +void RawDataReader::read(const std::string &basename, size_t numberOfSamples, bool shuffle){ unsigned fileCounter = 0; int fileLength; @@ -103,7 +105,7 @@ void RawDataReader::read(const std::string &basename, size_t numberOfSamples){ auto samplesLimit = (numberOfSamples == 0)? std::numeric_limits::max() : numberOfSamples; while(input.good() && maxima_.size() < samplesLimit) { - readSamplesAndMaxima(input, fileLength, samplesLimit); + readSamplesAndMaxima(input, fileLength, samplesLimit, shuffle); input.close(); fileCounter++; From e9377084a9c66d5c69efd79f328e6ec0dec8318c Mon Sep 17 00:00:00 2001 From: Leonard Reuter Date: Tue, 28 Jun 2022 17:03:47 +0200 Subject: [PATCH 20/28] Fixed ProcessMaxima sorting maxima if no Cluster is called. --- src/Executables/ProcessMaxima.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Executables/ProcessMaxima.cpp b/src/Executables/ProcessMaxima.cpp index 117f096f..cdf20c45 100644 --- a/src/Executables/ProcessMaxima.cpp +++ b/src/Executables/ProcessMaxima.cpp @@ -256,10 +256,9 @@ int main(int argc, char *argv[]) { } spdlog::info("number of elements after {}: {}", methodName, maxima.size()); } - maxima.sortAll(); - usedSettings["Clustering"] = usedClusteringSettings; } + maxima.sortAll(); if (inputYaml["VoxelCubeGeneration"]){ VoxelCubeGeneration::settings = Settings::VoxelCubeGeneration(inputYaml); From 222f06d8fb0e50698838a8a6f41fadb1be02d8b4 Mon Sep 17 00:00:00 2001 From: Leonard Reuter Date: Tue, 28 Jun 2022 17:28:41 +0200 Subject: [PATCH 21/28] Added Michel V. Heinz to authors. --- .zenodo.json | 5 +++++ src/BaseLib/include/Logo.h | 3 ++- src/GUI/source/InPsightsWidget.cpp | 5 +++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.zenodo.json b/.zenodo.json index 18be108d..c4868ed7 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -12,6 +12,11 @@ "orcid": "0000-0001-5758-843X", "affiliation": "RWTH Aachen University", "name": "Reuter, Leonard" + }, + { + "orcid": "0000-0002-8179-1435", + "affiliation": "RWTH Aachen University", + "name": "Heinz, Michel V." } ], "keywords": [ diff --git a/src/BaseLib/include/Logo.h b/src/BaseLib/include/Logo.h index a8cd5269..3fc82393 100644 --- a/src/BaseLib/include/Logo.h +++ b/src/BaseLib/include/Logo.h @@ -27,6 +27,7 @@ namespace inPsights { " Michael A. Heuer, RWTH Aachen University\n" "\n" " With contributions from:\n" - " Leonard Reuter, RWTH Aachen University\n"; + " Leonard Reuter, RWTH Aachen University\n" + " Michel V. Heinz, RWTH Aachen University\n"; } #endif //INPSIGHTS_LOGO_H diff --git a/src/GUI/source/InPsightsWidget.cpp b/src/GUI/source/InPsightsWidget.cpp index 03a1cf39..520c09c2 100644 --- a/src/GUI/source/InPsightsWidget.cpp +++ b/src/GUI/source/InPsightsWidget.cpp @@ -768,14 +768,15 @@ void InPsightsWidget::onMoveElectronsCheckBoxChecked(int stateId){ void InPsightsWidget::showSplashScreen() { auto splashScreen = new QSplashScreen(); - auto pixmap = QPixmap(":inPsights.png").scaledToWidth(450, Qt::TransformationMode::SmoothTransformation); + auto pixmap = QPixmap(":inPsights.png").scaledToWidth(550, Qt::TransformationMode::SmoothTransformation); splashScreen->setPixmap(pixmap); splashScreen->show(); std::string message = inPsights::version() + "\n"\ "Copyright © 2016-2021 Michael A. Heuer.\n"\ - "Copyright © 2018-2022 Leonard Reuter."; + "Copyright © 2018-2022 Leonard Reuter.\n"\ + "Copyright © 2022-2022 Michel V. Heinz."; splashScreen->showMessage(message.c_str(), Qt::AlignBottom, Qt::gray); From b89dd34308309f3ad8cb02666f57924cb05d7810 Mon Sep 17 00:00:00 2001 From: Leonard Reuter Date: Mon, 18 Jul 2022 17:29:24 +0200 Subject: [PATCH 22/28] Added "Draw indices" checkbox to inPsights. --- src/GUI/include/InPsightsWidget.h | 5 ++- src/GUI/include/MoleculeWidget.h | 3 ++ src/GUI/source/InPsightsWidget.cpp | 11 ++++++ src/GUI/source/MoleculeWidget.cpp | 56 +++++++++++++++++++++++++++++- 4 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/GUI/include/InPsightsWidget.h b/src/GUI/include/InPsightsWidget.h index f9554581..a85f5f62 100644 --- a/src/GUI/include/InPsightsWidget.h +++ b/src/GUI/include/InPsightsWidget.h @@ -43,13 +43,16 @@ public slots: void addMovedElectronsVector(int clusterId, int structureId, int secondId); bool checkEigenvalues(); void onSampleAverageCheckBoxChanged(int stateId); + void onIndicesChecked(int stateId); + std::vector getTickedStructuresCountVector(); private: std::string filename_; MoleculeWidget *moleculeWidget; QCheckBox *atomsCheckBox, *bondsCheckBox, *axesCheckBox, *sampleAverageCheckBox, *spinCorrelationsCheckBox, - *sedsCheckBox,*maximaHullsCheckBox, *plotAllCheckBox, *coloredCheckBox, *moveElectronsCheckBox; + *sedsCheckBox,*maximaHullsCheckBox, *plotAllCheckBox, *coloredCheckBox, *moveElectronsCheckBox, + *electronsNumberCheckBox; QDoubleSpinBox *spinCorrelationBox, *sedPercentageBox, *bondBox, *scaleVectorBox; QSpinBox *atom1Box, *atom2Box, *electron1Box, *electron2Box, *eigenvectorSpinBox; QPushButton *deselectAllButton; diff --git a/src/GUI/include/MoleculeWidget.h b/src/GUI/include/MoleculeWidget.h index bd9e9288..193129ae 100644 --- a/src/GUI/include/MoleculeWidget.h +++ b/src/GUI/include/MoleculeWidget.h @@ -31,6 +31,7 @@ class MoleculeWidget : public QWidget{ //TODO make base MoleculeWidget and InPsightsMoleculeWidget child void drawAxes(bool drawQ = true); + void drawIndices(bool drawQ = true); void drawEigenvectors(bool drawQ = true, unsigned clusterId = 0, unsigned structureId = 0, unsigned eigenvalueId = 0, float scale = 1.0f); void drawAtoms(bool drawQ = true); @@ -50,6 +51,7 @@ class MoleculeWidget : public QWidget{ void addElectronsVector(const ElectronsVector& electronsVector, int clusterId = 0, int structureId = 0, bool coloredQ = false); void removeElectronsVector(int clusterId = 0, int structureId = 0); void removeEigenvectors(); + void removeIndices(); void addSeds(int clusterId, int structureId, const std::vector &clusterData, double includedPercentage); void removeSeds(int clusterId); @@ -80,6 +82,7 @@ public slots: QPushButton *screenshotButton_, *x3dExportButton_, *resetCameraButton_, *sedsExportButton_; QSpinBox *pan_, *tilt_, *roll_, *zoom_; Qt3DRender::QDirectionalLight *light_; + std::vector indices_; int initPan_, initTilt_, initRoll_,initZoom_; float defaultCameraRadius_; public: diff --git a/src/GUI/source/InPsightsWidget.cpp b/src/GUI/source/InPsightsWidget.cpp index 520c09c2..6d58d02d 100644 --- a/src/GUI/source/InPsightsWidget.cpp +++ b/src/GUI/source/InPsightsWidget.cpp @@ -33,6 +33,7 @@ InPsightsWidget::InPsightsWidget(QWidget *parent, const std::string& filename) plotAllCheckBox(new QCheckBox("All of cluster", this)), coloredCheckBox(new QCheckBox("Multicolored", this)), moveElectronsCheckBox(new QCheckBox("Move electrons", this)), + electronsNumberCheckBox(new QCheckBox("Display indices", this)), spinCorrelationBox(new QDoubleSpinBox(this)), sedPercentageBox(new QDoubleSpinBox(this)), scaleVectorBox(new QDoubleSpinBox(this)), @@ -170,6 +171,9 @@ void InPsightsWidget::createWidget() { checkboxGrid->addWidget(spinCorrelationsCheckBox,5,0); checkboxGrid->addWidget(spinCorrelationBox,5,1); + //seventh row + checkboxGrid->addWidget(electronsNumberCheckBox,6,0); + setupSpinBoxes(); setupLabels(); } @@ -196,6 +200,9 @@ void InPsightsWidget::connectSignals() { connect(spinCorrelationBox, qOverload(&QDoubleSpinBox::valueChanged), this, &InPsightsWidget::onSpinCorrelationsBoxChanged); + connect(electronsNumberCheckBox, &QCheckBox::stateChanged, + this, &InPsightsWidget::onIndicesChecked); + connect(atom1Box, qOverload(&QSpinBox::valueChanged), this, &InPsightsWidget::onAtom1BoxChanged); @@ -592,6 +599,10 @@ void InPsightsWidget::onAtomsChecked(int stateId) { } } +void InPsightsWidget::onIndicesChecked(int stateId) { + moleculeWidget->drawIndices(Qt::CheckState(stateId) == Qt::CheckState::Checked); +} + void InPsightsWidget::onBondsChecked(int stateId) { if (atomsCheckBox->isChecked()) { moleculeWidget->drawBonds(Qt::CheckState(stateId) == Qt::CheckState::Checked, bondBox->value()); diff --git a/src/GUI/source/MoleculeWidget.cpp b/src/GUI/source/MoleculeWidget.cpp index 6474fe22..53142b3f 100644 --- a/src/GUI/source/MoleculeWidget.cpp +++ b/src/GUI/source/MoleculeWidget.cpp @@ -45,6 +45,7 @@ MoleculeWidget::MoleculeWidget(QWidget *parent) zoomText_(new QLabel("Zoom")), atomsVector3D_(nullptr), cartesianAxes_(nullptr), + indices_(), eigenvectors_(), light_(new Qt3DRender::QDirectionalLight(root_)){ @@ -193,6 +194,51 @@ void MoleculeWidget::drawAxes(bool drawQ) { } } +void MoleculeWidget::drawIndices(bool drawQ) { + if (drawQ) { + indices_ = std::vector(); + for (auto &cluster : activeElectronsVectorsMap_) { + for (auto &structure: cluster.second) { + for (int i=0; i < structure.second->particles3D_.size(); i++){ + bool showIndex = true; + for (int j=0; j < structure.second->particles3D_.size(); j++) { + if (j != i) { + if (Metrics::distance(structure.second->particles3D_[i]->position(), + structure.second->particles3D_[j]->position()) < 0.01) { + showIndex = false; + break; + } + } + } + if (showIndex) { + // *index = new Qt3DExtras::QText2DEntity(moleculeEntity_); + // does not work due to bug in Qt: a call to setScene is missing + // https://forum.qt.io/topic/92944/qt3d-how-to-print-text-qtext2dentity/7 + // therefore, index is created with nullptr as parent and the parent is + // set the line after + auto *index = new Qt3DExtras::QText2DEntity(); + index->setParent(moleculeEntity_); + index->setText(QString::number(i)); + index->setHeight(25); + index->setWidth(25); + index->setFont(QFont("monospace")); + index->setColor(GuiHelper::QColorFromType(structure.second->particles3D_[i]->type())); + auto *textTransform = new Qt3DCore::QTransform(index); + textTransform->setRotation(QQuaternion::fromDirection( + qt3DWindow_->camera()->position(), qt3DWindow_->camera()->upVector())); + textTransform->setTranslation(GuiHelper::toQVector3D(structure.second->particles3D_[i]->position())); + textTransform->setScale(1.0 / 92); + index->addComponent(textTransform); + indices_.emplace_back(index); + } + } + } + } + } else { + removeIndices(); + } +} + void MoleculeWidget::drawEigenvectors(bool drawQ, unsigned clusterId, unsigned structureId, unsigned eigenvalueId, float scale) { auto inPsightsWidget = dynamic_cast(parent()); unsigned electronsNumber = inPsightsWidget->clusterCollection_[clusterId].exemplaricStructures_[structureId].numberOfEntities(); @@ -204,7 +250,7 @@ void MoleculeWidget::drawEigenvectors(bool drawQ, unsigned clusterId, unsigned s eigenvectors_ = std::vector(); } for (unsigned i = 0; i < electronsNumber; i++) { - Eigen::Vector3d ePosVector =inPsightsWidget->clusterCollection_[clusterId].exemplaricStructures_[structureId].positionsVector()[i]; + Eigen::Vector3d ePosVector = inPsightsWidget->clusterCollection_[clusterId].exemplaricStructures_[structureId].positionsVector()[i]; Eigen::Vector3d eigenVector = inPsightsWidget->clusterCollection_[clusterId].eigenvectors_[structureId][eigenvalueId * electronsNumber + i] * scale; Eigen::Vector3d tempVector = ePosVector + eigenVector; QString color = "blue"; @@ -227,6 +273,14 @@ void MoleculeWidget::removeEigenvectors() { eigenvectors_ = std::vector(); } +void MoleculeWidget::removeIndices() { + // TODO: fix the segfault + for (auto index : indices_) { + index->deleteLater(); + } + indices_ = std::vector(); +} + void MoleculeWidget::drawAtoms(bool drawQ) { if (drawQ) { atomsVector3D_ = new AtomsVector3D(moleculeEntity_, *sharedAtomsVector_); From 910e7559cafa834caed054238a73452226cf59de Mon Sep 17 00:00:00 2001 From: Leonard Reuter Date: Tue, 19 Jul 2022 20:03:00 +0200 Subject: [PATCH 23/28] Added subValueStats to show sub cluster phi values in GUI. --- src/GUI/include/InPsightsWidget.h | 2 + src/GUI/source/InPsightsWidget.cpp | 53 ++++++++++++------- .../MaximaProcessing/include/ClusterData.h | 5 +- .../include/MaximaProcessor.h | 2 + .../MaximaProcessing/source/ClusterData.cpp | 18 +++++-- .../source/MaximaProcessor.cpp | 20 ++++++- 6 files changed, 75 insertions(+), 25 deletions(-) diff --git a/src/GUI/include/InPsightsWidget.h b/src/GUI/include/InPsightsWidget.h index a85f5f62..69041f1c 100644 --- a/src/GUI/include/InPsightsWidget.h +++ b/src/GUI/include/InPsightsWidget.h @@ -58,6 +58,7 @@ public slots: QPushButton *deselectAllButton; QTreeWidget *maximaList; QLabel *probabilitySum, *eigenvalueLabel; + float globalMinPhi; std::vector lastMovedElectronClusterVector; void showSplashScreen(); @@ -70,6 +71,7 @@ public slots: void redrawSpinDecorations(); double sumProbabilities(); void resetEigenvalueLabel(); + std::pair getPhiStrings(const SingleValueStatistics& valueStats); }; #endif //INPSIGHTS_INPSIGHTSWIDGET_H diff --git a/src/GUI/source/InPsightsWidget.cpp b/src/GUI/source/InPsightsWidget.cpp index 6d58d02d..56f1986c 100644 --- a/src/GUI/source/InPsightsWidget.cpp +++ b/src/GUI/source/InPsightsWidget.cpp @@ -47,7 +47,8 @@ InPsightsWidget::InPsightsWidget(QWidget *parent, const std::string& filename) probabilitySum(new QLabel(this)), eigenvalueLabel(new QLabel(this)), deselectAllButton(new QPushButton("Deselect all", this)), - lastMovedElectronClusterVector({0, 0, -1}) + lastMovedElectronClusterVector({0, 0, -1}), + globalMinPhi(0.0f) { loadData(); @@ -828,7 +829,6 @@ void InPsightsWidget::loadData() { Camera::settings = Settings::Camera(doc); } - float globalMinPhi; if (doc["GlobalMinPhi"]) { globalMinPhi = doc["GlobalMinPhi"].as(); } @@ -840,22 +840,13 @@ void InPsightsWidget::loadData() { clusterCollection_.emplace_back(doc["Clusters"][clusterId].as()); const auto & cluster = clusterCollection_.back(); - - float minPhi = cluster.valueStats_.cwiseMin()[0]/2.0; - auto minPhiString = QString::number(minPhi-globalMinPhi, 'f', 4); - if (minPhi-globalMinPhi >= 0) - minPhiString = QString(' ') + minPhiString; - - float maxPhi = cluster.valueStats_.cwiseMax()[0]/2.0; - auto maxPhiString = QString::number(maxPhi-globalMinPhi, 'f', 4); - if (maxPhi-globalMinPhi >= 0) - maxPhiString = QString(' ') + maxPhiString; + auto phiStrings = getPhiStrings(cluster.valueStats_); auto item = new IntegerSortedTreeWidgetItem( maximaList, {QString::number(clusterId), QString::number(1.0 * cluster.N_ / doc["NSamples"].as(), 'f', 4), - minPhiString.left(7), - maxPhiString.left(7)}); + phiStrings.first, + phiStrings.second}); item->setCheckState(0, Qt::CheckState::Unchecked); @@ -866,12 +857,21 @@ void InPsightsWidget::loadData() { if (structures.size() > 1) { for (int structureId = 0; structureId < static_cast(structures.size()); ++structureId) { - auto subItem = new IntegerSortedTreeWidgetItem(item, QStringList({ - QString::number(structureId), - QString::number(1.0 * - cluster.subN_[structureId] / - cluster.N_, - 'f', 4)})); + if (not cluster.subValueStats_.empty()){ + phiStrings = getPhiStrings(cluster.subValueStats_[structureId]); + }else{ + phiStrings = std::pair(QString(' '),QString(' ')); + } + + auto subItem = new IntegerSortedTreeWidgetItem(item, + QStringList({ + QString::number(structureId), + QString::number(1.0 * + cluster.subN_[structureId] / + cluster.N_, + 'f', 4), + phiStrings.first, + phiStrings.second})); subItem->setCheckState(0, Qt::CheckState::Unchecked); id = {clusterId, structureId}; @@ -887,6 +887,19 @@ void InPsightsWidget::loadData() { } } +std::pair InPsightsWidget::getPhiStrings(const SingleValueStatistics& valueStats){ + float minPhi = valueStats.cwiseMin()[0]/2.0; + auto minPhiString = QString::number(minPhi-globalMinPhi, 'f', 4); + if (minPhi-globalMinPhi >= 0) + minPhiString = QString(' ') + minPhiString; + + float maxPhi = valueStats.cwiseMax()[0]/2.0; + auto maxPhiString = QString::number(maxPhi-globalMinPhi, 'f', 4); + if (maxPhi-globalMinPhi >= 0) + maxPhiString = QString(' ') + maxPhiString; + return std::pair(minPhiString.left(7), maxPhiString.left(7)); +} + double InPsightsWidget::sumProbabilities(){ auto* root = maximaList->invisibleRootItem(); diff --git a/src/Methods/MaximaProcessing/include/ClusterData.h b/src/Methods/MaximaProcessing/include/ClusterData.h index 94ea4140..65135038 100644 --- a/src/Methods/MaximaProcessing/include/ClusterData.h +++ b/src/Methods/MaximaProcessing/include/ClusterData.h @@ -34,6 +34,7 @@ class ClusterData { const std::vector& seds, const Eigen::MatrixXd& sedOverlaps, const std::vector& subCounts, + const std::vector& subValueStats, const std::vector &eigenvalues, const std::vector> &eigenvectors ); @@ -58,13 +59,15 @@ class ClusterData { const Eigen::MatrixXd& sedOverlaps, const SelectionEnergyCalculator::SelectionInteractionEnergies & selectionInteractionEnergies, const std::vector& selections, - const std::vector& subCounts + const std::vector& subCounts, + const std::vector& subValueStats ); ElectronsVector representativeStructure() const; unsigned N_; std::vector subN_; + std::vector subValueStats_; std::vector exemplaricStructures_; ElectronsVector sampleAverage_; Motifs motifs_; diff --git a/src/Methods/MaximaProcessing/include/MaximaProcessor.h b/src/Methods/MaximaProcessing/include/MaximaProcessor.h index 9adb4b7e..493c6af1 100644 --- a/src/Methods/MaximaProcessing/include/MaximaProcessor.h +++ b/src/Methods/MaximaProcessing/include/MaximaProcessor.h @@ -50,6 +50,8 @@ class MaximaProcessor { const std::vector& selections ); + void getValueStats(const Cluster &cluster, SingleValueStatistics &valueStats); + YAML::Node getYamlNode(); std::string getYamlDocumentString(); diff --git a/src/Methods/MaximaProcessing/source/ClusterData.cpp b/src/Methods/MaximaProcessing/source/ClusterData.cpp index 93cf1fd3..77a0ac2b 100644 --- a/src/Methods/MaximaProcessing/source/ClusterData.cpp +++ b/src/Methods/MaximaProcessing/source/ClusterData.cpp @@ -22,6 +22,7 @@ ClusterData::ClusterData(unsigned totalNumberOfStructures, const std::vector &seds, const Eigen::MatrixXd& sedOverlaps, const std::vector& subCounts, + const std::vector& subValueStats, const std::vector &eigenvalues, const std::vector> &eigenvectors ) @@ -42,6 +43,7 @@ ClusterData::ClusterData(unsigned totalNumberOfStructures, voxelCubes_(seds), overlaps_(sedOverlaps), subN_(subCounts), + subValueStats_(subValueStats), eigenvalues_(eigenvalues), eigenvectors_(eigenvectors) {}; @@ -65,7 +67,8 @@ ClusterData::ClusterData(unsigned totalNumberOfStructures, const Eigen::MatrixXd& sedOverlaps, const SelectionEnergyCalculator::SelectionInteractionEnergies & selectionInteractionEnergies, const std::vector& selections, - const std::vector& subCounts + const std::vector& subCounts, + const std::vector& subValueStats ) : N_(totalNumberOfStructures), @@ -86,6 +89,7 @@ ClusterData::ClusterData(unsigned totalNumberOfStructures, selectionInteractionEnergies_(selectionInteractionEnergies), selections_(selections), subN_(subCounts), + subValueStats_(subValueStats), eigenvalues_(), eigenvectors_() {}; @@ -115,6 +119,7 @@ namespace YAML { node["VoxelCubes"] = rhs.voxelCubes_; node["SedOverlaps"] = rhs.overlaps_; node["SubStructureN"] = rhs.subN_; + node["SubStructureValueRange"] = rhs.subValueStats_; return node; } @@ -151,6 +156,10 @@ namespace YAML { subCounts.emplace_back(NAN); } } + std::vector subValueStats; + if (node["SubStructureValueRange"]) { + subValueStats = node["SubStructureValueRange"].as>(); + } std::vector eigenvalues; std::vector> eigenvectors; @@ -215,6 +224,7 @@ namespace YAML { cubes, sedOverlaps, subCounts, + subValueStats, eigenvalues, eigenvectors ); @@ -251,8 +261,10 @@ namespace YAML { if (rhs.overlaps_.size() > 0) out << Key << "SedOverlaps" << Value << rhs.overlaps_; - out << Key << "SubStructureN" << Value << rhs.subN_ - << EndMap; + out << Key << "SubStructureN" << Value << rhs.subN_; + + out << Key << "SubStructureValueRange" << Value << rhs.subValueStats_ + << EndMap; return out; } diff --git a/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp b/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp index ea6d715e..50e218f8 100644 --- a/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp +++ b/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp @@ -146,6 +146,20 @@ size_t MaximaProcessor::addAllMaxima(const Cluster &cluster) { return totalCount; } + +void MaximaProcessor::getValueStats(const Cluster &cluster, SingleValueStatistics &valueStats) { + if(cluster.isLeaf()){ + auto count = unsigned(cluster.representative()->count()); + Eigen::VectorXd value = Eigen::VectorXd::Constant(1, cluster.representative()->value()); + valueStats.add(value, count); + } + else{ + for(const auto &subcluster : cluster) + getValueStats(subcluster, valueStats); + } +} + + void MaximaProcessor::calculateStatistics(const Cluster &cluster, const std::vector>> & nucleiMergeLists, const std::vector &nucleiIndices, @@ -168,6 +182,7 @@ void MaximaProcessor::calculateStatistics(const Cluster &cluster, for (auto& subCluster : cluster) { std::vector subSubClusterCounts; + std::vector subValueStats; valueStats_.reset(); if (calcSpinCorr_) { @@ -190,6 +205,9 @@ void MaximaProcessor::calculateStatistics(const Cluster &cluster, for (auto& subSubCluster : subCluster){ subSubClusterCounts.emplace_back(addAllMaxima(subSubCluster)); // this sets all statistic objects internally totalCount += subSubClusterCounts.back(); + SingleValueStatistics subValueStat; + getValueStats(subSubCluster, subValueStat); + subValueStats.emplace_back(subValueStat); } } @@ -263,7 +281,7 @@ void MaximaProcessor::calculateStatistics(const Cluster &cluster, ReeStats_, RenStats_, voxelCubes, overlaps, selectionEnergyCalculatorPerCluster.selectionInteractions_, selectionEnergyCalculatorPerCluster.molecularSelections_, - subSubClusterCounts + subSubClusterCounts, subValueStats ); } } From a8b36faa8db7422686e8db0501db005281d052ca Mon Sep 17 00:00:00 2001 From: Leonard Reuter Date: Thu, 21 Jul 2022 10:20:10 +0200 Subject: [PATCH 24/28] Improved Qt instruction in README. --- README.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/README.md b/README.md index 0eb43bb4..bba13d86 100644 --- a/README.md +++ b/README.md @@ -78,17 +78,12 @@ Otherwise the default compilers are used. #### Qt5 To build the inPsights GUI, environment variables to the Qt5 libraries are required. -If Qt5 was installed via homebrew, the following environment variable must be exported: +If Qt5 is not found or a wrong Qt5 version is found, the following environment variable must be exported: ```bash export CMAKE_PREFIX_PATH=/usr/local/Cellar/qt/5.XX.X ``` -If Qt5 was download from the webpage and installed via the installer, the following environment variable must be exported: -```bash -export Qt5_DIR=/home//Qt/5.XX.X/gcc_64 -``` - If Qt5 was installed via `apt-get`, CMake should find the library automatically. From 375cfc2b779c9daeb5be268d8596e676e3f8bbed Mon Sep 17 00:00:00 2001 From: Leonard Reuter Date: Thu, 21 Jul 2022 10:24:50 +0200 Subject: [PATCH 25/28] Started Renaming DensityBasedClusterer to SingleLinkageClusterer. --- .../include/{DensityBasedClusterer.h => SingleLinkageClusterer.h} | 0 .../{DensityBasedClusterer.cpp => SingleLinkageClusterer.cpp} | 0 ...sityBasedClustererTest.cpp => ASingleLinkageClustererTest.cpp} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/Methods/MaximaProcessing/include/{DensityBasedClusterer.h => SingleLinkageClusterer.h} (100%) rename src/Methods/MaximaProcessing/source/{DensityBasedClusterer.cpp => SingleLinkageClusterer.cpp} (100%) rename src/Methods/MaximaProcessing/tests/{ADensityBasedClustererTest.cpp => ASingleLinkageClustererTest.cpp} (100%) diff --git a/src/Methods/MaximaProcessing/include/DensityBasedClusterer.h b/src/Methods/MaximaProcessing/include/SingleLinkageClusterer.h similarity index 100% rename from src/Methods/MaximaProcessing/include/DensityBasedClusterer.h rename to src/Methods/MaximaProcessing/include/SingleLinkageClusterer.h diff --git a/src/Methods/MaximaProcessing/source/DensityBasedClusterer.cpp b/src/Methods/MaximaProcessing/source/SingleLinkageClusterer.cpp similarity index 100% rename from src/Methods/MaximaProcessing/source/DensityBasedClusterer.cpp rename to src/Methods/MaximaProcessing/source/SingleLinkageClusterer.cpp diff --git a/src/Methods/MaximaProcessing/tests/ADensityBasedClustererTest.cpp b/src/Methods/MaximaProcessing/tests/ASingleLinkageClustererTest.cpp similarity index 100% rename from src/Methods/MaximaProcessing/tests/ADensityBasedClustererTest.cpp rename to src/Methods/MaximaProcessing/tests/ASingleLinkageClustererTest.cpp From 27e193190e606f518c55a308b7d2c58925376464 Mon Sep 17 00:00:00 2001 From: Leonard Reuter Date: Thu, 21 Jul 2022 10:25:06 +0200 Subject: [PATCH 26/28] Finished Renaming DensityBasedClusterer. --- docs/USER_MANUAL.md | 14 ++++++------- src/Executables/ProcessMaxima.cpp | 16 +++++++-------- src/Methods/MaximaProcessing/CMakeLists.txt | 4 ++-- .../MaximaProcessing/include/IProcess.h | 2 +- .../include/SingleLinkageClusterer.h | 20 +++++++++---------- .../MaximaProcessing/source/IProcess.cpp | 4 ++-- .../source/MaximaProcessor.cpp | 2 +- .../source/SingleLinkageClusterer.cpp | 20 +++++++++---------- .../tests/ASingleLinkageClustererTest.cpp | 20 +++++++++---------- 9 files changed, 51 insertions(+), 51 deletions(-) diff --git a/docs/USER_MANUAL.md b/docs/USER_MANUAL.md index 58045a2c..64344720 100644 --- a/docs/USER_MANUAL.md +++ b/docs/USER_MANUAL.md @@ -24,7 +24,7 @@ MaximaProcessing: Clustering: PreClusterer: radius: 0.01 # [a0] - DensityBasedClusterer: + SingleLinkageClusterer: radius: 0.2 # [a0] VoxelCubeGeneration: generateVoxelCubesQ: true @@ -63,7 +63,7 @@ Example: Clustering: PreClusterer: # 1. spherical pre-clustering with the PreClusterer and a small radius of 0.01 a0 radius: 0.01 # [a0] - DensityBasedClusterer: # 2. density-based clustering with the DensityBasedClusterer and a radius of 0.2 a0 + SingleLinkageClusterer: # 2. single linkage clustering with the SingleLinkageClusterer and a radius of 0.2 a0 radius: 0.2 # [a0] ``` @@ -82,14 +82,14 @@ Spherical clusterer employing a spin-agnostic best-match distance metric. * `local` (`bool`): true unlocks the `ElectronSelection` Options in which the subset of considered electrons can be specified. -##### DensityBasedClusterer -Density-based clusterer employing a spin-agnostic best-match distance metric. +##### SingleLinkageClusterer +Single linkage clusterer employing a spin-agnostic best-match distance metric. * `radius` (`positive float`,`[a0]`): radius in which similar, density connected maxima (irrespective of spin) are clustered together * `local` (`bool`): true unlocks the `ElectronSelection` options in which the subset of considered electrons can be specified. ##### Local Clustering with the `ElectronSelection` Option -`ElectronSelection` is A sub-node that can be added to a `SphericalClusterer` or `DensityBasedClusterer` node. +`ElectronSelection` is A sub-node that can be added to a `SphericalClusterer` or `SingleLinkageClusterer` node. The following options can be specified: * `maximalCount` (`unsigned int`): Maximal number of electrons that are compared for clustering (the subset). * `maximalDistance` (`positive float`,`[a0]`): Maximal distance of electrons from the reference positions to be included in the subset for comparison. @@ -106,12 +106,12 @@ The following options can be specified: * `add`: Give a list of positions (as above) to add them. * `multiply`: Give a list of positions (as above) to multiply them element-wise. -Example: Density-based clustering of the four valence electrons closest to the point in between the 4. and 5. atom and sort the remaining electrons. +Example: Single linkage clustering of the four valence electrons closest to the point in between the 4. and 5. atom and sort the remaining electrons. ```yaml Clustering: PreClusterer: radius: 0.01 - DensityBasedClusterer: + SingleLinkageClusterer: radius: 0.2 local: true sortRemainder: true diff --git a/src/Executables/ProcessMaxima.cpp b/src/Executables/ProcessMaxima.cpp index cdf20c45..8f99efc3 100644 --- a/src/Executables/ProcessMaxima.cpp +++ b/src/Executables/ProcessMaxima.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include @@ -43,8 +43,8 @@ void validateClusteringSettings(const YAML::Node &inputYaml) { PreClusterer::settings = Settings::PreClusterer(clusteringNode); break; } - case IProcess::ProcessType::DensityBasedClusterer: { - DensityBasedClusterer::settings = Settings::DensityBasedClusterer(clusteringNode); + case IProcess::ProcessType::SingleLinkageClusterer: { + SingleLinkageClusterer::settings = Settings::SingleLinkageClusterer(clusteringNode); break; } case IProcess::ProcessType::ReferencePositionsClusterer: { @@ -182,10 +182,10 @@ int main(int argc, char *argv[]) { settings.appendToNode(usedClusteringSettings); break; } - case IProcess::ProcessType::DensityBasedClusterer: { - auto &settings = DensityBasedClusterer::settings; + case IProcess::ProcessType::SingleLinkageClusterer: { + auto &settings = SingleLinkageClusterer::settings; - settings = Settings::DensityBasedClusterer(node.second); + settings = Settings::SingleLinkageClusterer(node.second); if(settings.local()) { auto electronSelectionSettings = node.second[VARNAME(ElectronSelection)]; @@ -193,8 +193,8 @@ int main(int argc, char *argv[]) { ElectronSelection::settings = Settings::ElectronSelection(electronSelectionSettings, atoms); } - DensityBasedClusterer densityBasedClusterer(samples); - densityBasedClusterer.cluster(maxima); + SingleLinkageClusterer singleLinkageClusterer(samples); + singleLinkageClusterer.cluster(maxima); if(settings.local()) { ElectronSelection::settings.appendToNode(usedClusteringSettings); // TODO FIX USED SETTINGS APPEND diff --git a/src/Methods/MaximaProcessing/CMakeLists.txt b/src/Methods/MaximaProcessing/CMakeLists.txt index 15cef580..42454ad9 100644 --- a/src/Methods/MaximaProcessing/CMakeLists.txt +++ b/src/Methods/MaximaProcessing/CMakeLists.txt @@ -14,7 +14,7 @@ set(HEADER_FILES include/ClusterData.h include/IdentityClusterer.h include/PreClusterer.h - include/DensityBasedClusterer.h + include/SingleLinkageClusterer.h include/SOAPClusterer.h include/MaximaProcessor.h include/GeneralStatistics.h @@ -40,7 +40,7 @@ set(SOURCE_FILES source/ClusterData.cpp source/IdentityClusterer.cpp source/PreClusterer.cpp - source/DensityBasedClusterer.cpp + source/SingleLinkageClusterer.cpp source/SOAPClusterer.cpp source/MaximaProcessor.cpp source/GeneralStatistics.cpp diff --git a/src/Methods/MaximaProcessing/include/IProcess.h b/src/Methods/MaximaProcessing/include/IProcess.h index 18e882ff..fe48173b 100644 --- a/src/Methods/MaximaProcessing/include/IProcess.h +++ b/src/Methods/MaximaProcessing/include/IProcess.h @@ -12,7 +12,7 @@ class IProcess{ // Clusterer Processes IdentityClusterer, DistanceClusterer, - DensityBasedClusterer, + SingleLinkageClusterer, SOAPClusterer, ReferencePositionsClusterer, diff --git a/src/Methods/MaximaProcessing/include/SingleLinkageClusterer.h b/src/Methods/MaximaProcessing/include/SingleLinkageClusterer.h index c2b0fa47..3b7f12d9 100644 --- a/src/Methods/MaximaProcessing/include/SingleLinkageClusterer.h +++ b/src/Methods/MaximaProcessing/include/SingleLinkageClusterer.h @@ -1,8 +1,8 @@ // Copyright (C) 2018-2020 Michael Heuer. // SPDX-License-Identifier: GPL-3.0-or-later -#ifndef INPSIGHTS_DENSITYBASEDCLUSTERER_H -#define INPSIGHTS_DENSITYBASEDCLUSTERER_H +#ifndef INPSIGHTS_SINGLELINKAGECLUSTERER_H +#define INPSIGHTS_SINGLELINKAGECLUSTERER_H #include #include @@ -12,26 +12,26 @@ #include "ClusteringMetric.h" namespace Settings { - class DensityBasedClusterer : public ISettings { + class SingleLinkageClusterer : public ISettings { public: Property radius = {0.2, VARNAME(radius)}; Property minimalClusterSize = {1, VARNAME(minimalClusterSize)}; Property local = {false, VARNAME(local)}; // TODO unite all general clusterer settigns in a parent settings class Property sortRemainder = {false, VARNAME(sortRemainder)}; - DensityBasedClusterer(); - explicit DensityBasedClusterer(const YAML::Node &node); + SingleLinkageClusterer(); + explicit SingleLinkageClusterer(const YAML::Node &node); void appendToNode(YAML::Node &node) const override; }; } -YAML_SETTINGS_DECLARATION(Settings::DensityBasedClusterer) +YAML_SETTINGS_DECLARATION(Settings::SingleLinkageClusterer) -class DensityBasedClusterer : public IClusterer { +class SingleLinkageClusterer : public IClusterer { public: - static Settings::DensityBasedClusterer settings; + static Settings::SingleLinkageClusterer settings; - explicit DensityBasedClusterer(std::vector &samples); + explicit SingleLinkageClusterer(std::vector &samples); void cluster(Cluster &group) override; @@ -131,4 +131,4 @@ class DensityBasedClusterer : public IClusterer { } }; -#endif //INPSIGHTS_DENSITYBASEDCLUSTERER_H +#endif //INPSIGHTS_SINGLELINKAGECLUSTERER_H diff --git a/src/Methods/MaximaProcessing/source/IProcess.cpp b/src/Methods/MaximaProcessing/source/IProcess.cpp index 559489f9..91062e1c 100644 --- a/src/Methods/MaximaProcessing/source/IProcess.cpp +++ b/src/Methods/MaximaProcessing/source/IProcess.cpp @@ -9,8 +9,8 @@ IProcess::ProcessType IProcess::typeFromString(const std::string& processName) { return ProcessType::IdentityClusterer; else if(processName == "PreClusterer") return ProcessType::DistanceClusterer; - else if(processName == "DensityBasedClusterer") - return ProcessType::DensityBasedClusterer; + else if(processName == "DensityBasedClusterer" or processName == "SingleLinkageClusterer") + return ProcessType::SingleLinkageClusterer; else if(processName == "ReferencePositionsClusterer") return ProcessType::ReferencePositionsClusterer; else if(processName == "SOAPClusterer") diff --git a/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp b/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp index 50e218f8..5abd6518 100644 --- a/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp +++ b/src/Methods/MaximaProcessing/source/MaximaProcessor.cpp @@ -286,7 +286,7 @@ void MaximaProcessor::calculateStatistics(const Cluster &cluster, } } spdlog::info("Overall count {}. Some structures might be lost " - "by being classified as noise during density-based clustering.", totalCount); + "by being classified as noise during single linkage clustering.", totalCount); spdlog::info("Considered weight: {}, discarded weight: {}", totalWeight, 1.0 - totalWeight); yamlDocument_ << EndSeq; diff --git a/src/Methods/MaximaProcessing/source/SingleLinkageClusterer.cpp b/src/Methods/MaximaProcessing/source/SingleLinkageClusterer.cpp index dae780be..62228a67 100644 --- a/src/Methods/MaximaProcessing/source/SingleLinkageClusterer.cpp +++ b/src/Methods/MaximaProcessing/source/SingleLinkageClusterer.cpp @@ -2,7 +2,7 @@ // Copyright (C) 2018 Leonard Reuter. // SPDX-License-Identifier: GPL-3.0-or-later -#include +#include #include #include #include @@ -10,8 +10,8 @@ #include "ClusteringMetric.h" namespace Settings { - DensityBasedClusterer::DensityBasedClusterer() - : ISettings(VARNAME(DensityBasedClusterer)) { + SingleLinkageClusterer::SingleLinkageClusterer() + : ISettings(VARNAME(SingleLinkageClusterer)) { radius.onChange_.connect( [&](double value) { if(value < ::PreClusterer::settings.radius()) @@ -35,30 +35,30 @@ namespace Settings { }); } - DensityBasedClusterer::DensityBasedClusterer(const YAML::Node &node) - : DensityBasedClusterer() { + SingleLinkageClusterer::SingleLinkageClusterer(const YAML::Node &node) + : SingleLinkageClusterer() { doubleProperty::decode(node, radius); size_tProperty ::decode(node, minimalClusterSize); boolProperty::decode(node, local); boolProperty::decode(node, sortRemainder); } - void DensityBasedClusterer::appendToNode(YAML::Node &node) const { + void SingleLinkageClusterer::appendToNode(YAML::Node &node) const { node[className][radius.name()] = radius(); node[className][minimalClusterSize.name()] = minimalClusterSize(); node[className][local.name()] = local(); node[className][sortRemainder.name()] = sortRemainder(); } } -YAML_SETTINGS_DEFINITION(Settings::DensityBasedClusterer) +YAML_SETTINGS_DEFINITION(Settings::SingleLinkageClusterer) -Settings::DensityBasedClusterer DensityBasedClusterer::settings = Settings::DensityBasedClusterer(); +Settings::SingleLinkageClusterer SingleLinkageClusterer::settings = Settings::SingleLinkageClusterer(); -DensityBasedClusterer::DensityBasedClusterer(std::vector &samples) +SingleLinkageClusterer::SingleLinkageClusterer(std::vector &samples) : IClusterer(samples) {}; -void DensityBasedClusterer::cluster(Cluster& cluster) { +void SingleLinkageClusterer::cluster(Cluster& cluster) { assert(!cluster.empty() && "The cluster cannot be empty."); auto localQ = settings.local(); diff --git a/src/Methods/MaximaProcessing/tests/ASingleLinkageClustererTest.cpp b/src/Methods/MaximaProcessing/tests/ASingleLinkageClustererTest.cpp index 2b8731d9..d1ec11e5 100644 --- a/src/Methods/MaximaProcessing/tests/ASingleLinkageClustererTest.cpp +++ b/src/Methods/MaximaProcessing/tests/ASingleLinkageClustererTest.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include -#include +#include #include #include #include @@ -13,7 +13,7 @@ using namespace testing; -class ADensityBasedClustererTest : public ::testing::Test { +class ASingleLinkageClustererTest : public ::testing::Test { public: void SetUp() override { spdlog::set_level(spdlog::level::off); @@ -58,8 +58,8 @@ class ADensityBasedClustererTest : public ::testing::Test { } }; -TEST_F(ADensityBasedClustererTest, RotationallySymmetricCluster){ - DensityBasedClusterer::settings.radius = 0.1; +TEST_F(ASingleLinkageClustererTest, RotationallySymmetricCluster){ + SingleLinkageClusterer::settings.radius = 0.1; unsigned n = 20; @@ -78,7 +78,7 @@ TEST_F(ADensityBasedClustererTest, RotationallySymmetricCluster){ ASSERT_EQ(references.size(), n); std::shuffle(references.begin(), references.end(), rng); - DensityBasedClusterer globalClusterSorter(samples); + SingleLinkageClusterer globalClusterSorter(samples); globalClusterSorter.cluster(references); ASSERT_EQ(references.size(), 1); @@ -95,8 +95,8 @@ TEST_F(ADensityBasedClustererTest, RotationallySymmetricCluster){ } } -TEST_F(ADensityBasedClustererTest, RotationallySymmetricAndPointLikeCluster){ - DensityBasedClusterer::settings.radius = 0.1; +TEST_F(ASingleLinkageClustererTest, RotationallySymmetricAndPointLikeCluster){ + SingleLinkageClusterer::settings.radius = 0.1; unsigned n = 20; unsigned m = 5; @@ -117,7 +117,7 @@ TEST_F(ADensityBasedClustererTest, RotationallySymmetricAndPointLikeCluster){ references.emplace_back(Maximum(ionic.atoms(), 10, ionic.electrons(), 0)); for (unsigned i = 1; i < m; ++i) { auto evCopy = ionic.electrons(); - evCopy.positionsVector().shake(DensityBasedClusterer::settings.radius.get(), rng); + evCopy.positionsVector().shake(SingleLinkageClusterer::settings.radius.get(), rng); // random permutation evCopy.permute(evCopy.randomPermutation(rng)); @@ -131,7 +131,7 @@ TEST_F(ADensityBasedClustererTest, RotationallySymmetricAndPointLikeCluster){ std::shuffle(references.begin(), references.end(), rng); - DensityBasedClusterer globalClusterSorter(samples); + SingleLinkageClusterer globalClusterSorter(samples); globalClusterSorter.cluster(references); ASSERT_EQ(references.size(), 2); @@ -149,7 +149,7 @@ TEST_F(ADensityBasedClustererTest, RotationallySymmetricAndPointLikeCluster){ // since every particle can be displaced by radius, the distance between // two particles can change by 2*radius ASSERT_TRUE(distanceMatrix.isApprox(referenceDistanceMatrix, - 2 * DensityBasedClusterer::settings.radius.get())); + 2 * SingleLinkageClusterer::settings.radius.get())); } } } From 63995b15e0c2d7456a8b822637ea7183bf550a71 Mon Sep 17 00:00:00 2001 From: Leonard Reuter Date: Fri, 25 Nov 2022 12:42:36 +0100 Subject: [PATCH 27/28] Fixed Hessian eigenvalue. --- src/GUI/source/InPsightsWidget.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/GUI/source/InPsightsWidget.cpp b/src/GUI/source/InPsightsWidget.cpp index 56f1986c..48a907a8 100644 --- a/src/GUI/source/InPsightsWidget.cpp +++ b/src/GUI/source/InPsightsWidget.cpp @@ -373,7 +373,7 @@ void InPsightsWidget::selectedStructure(QTreeWidgetItem *item, int column) { } if (not clusterCollection_[0].eigenvalues_.empty()) { if (checkEigenvalues() and eigenvectorSpinBox->value() != -1) { - eigenvalueLabel->setText(QString::number(clusterCollection_[clusterId].eigenvalues_[structureId][eigenvectorSpinBox->value()], 'f', 4)); + eigenvalueLabel->setText(QString::number(clusterCollection_[clusterId].eigenvalues_[structureId][eigenvectorSpinBox->value()] / 2, 'f', 4)); moleculeWidget->drawEigenvectors(true, clusterId, structureId, eigenvectorSpinBox->value(), scaleVectorBox->value()); } else { @@ -432,7 +432,7 @@ void InPsightsWidget::selectedStructure(QTreeWidgetItem *item, int column) { } } } - eigenvalueLabel->setText(QString::number(clusterCollection_[cluId].eigenvalues_[strId][eigenvectorSpinBox->value()], 'f', 4)); + eigenvalueLabel->setText(QString::number(clusterCollection_[cluId].eigenvalues_[strId][eigenvectorSpinBox->value()] / 2, 'f', 4)); moleculeWidget->drawEigenvectors(true, cluId, strId, eigenvectorSpinBox->value(), scaleVectorBox->value()); } else { @@ -696,7 +696,7 @@ void InPsightsWidget::onEigenvectorSpinBoxChanged(int value) { spdlog::warn("Chose only one structure for eigenvalues"); } else if (count == 1){ - eigenvalueLabel->setText(QString::number(clusterCollection_[id].eigenvalues_[structureId][value], 'f', 4)); + eigenvalueLabel->setText(QString::number(clusterCollection_[id].eigenvalues_[structureId][value] / 2, 'f', 4)); moleculeWidget->drawEigenvectors(true, id, structureId, value, scaleVectorBox->value()); if (moveElectronsCheckBox->isChecked()) { moveElectronsCheckBox->setCheckState(Qt::Unchecked); From 6b162a1027400e4b43d98822b679555e6694c8c7 Mon Sep 17 00:00:00 2001 From: Leonard Reuter Date: Tue, 29 Nov 2022 17:42:52 +0100 Subject: [PATCH 28/28] Removed author names and years from splash screen. --- src/GUI/source/InPsightsWidget.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/GUI/source/InPsightsWidget.cpp b/src/GUI/source/InPsightsWidget.cpp index 48a907a8..814b815f 100644 --- a/src/GUI/source/InPsightsWidget.cpp +++ b/src/GUI/source/InPsightsWidget.cpp @@ -780,15 +780,13 @@ void InPsightsWidget::onMoveElectronsCheckBoxChecked(int stateId){ void InPsightsWidget::showSplashScreen() { auto splashScreen = new QSplashScreen(); - auto pixmap = QPixmap(":inPsights.png").scaledToWidth(550, Qt::TransformationMode::SmoothTransformation); + auto pixmap = QPixmap(":inPsights.png").scaledToWidth(400, Qt::TransformationMode::SmoothTransformation); splashScreen->setPixmap(pixmap); splashScreen->show(); std::string message = inPsights::version() + "\n"\ - "Copyright © 2016-2021 Michael A. Heuer.\n"\ - "Copyright © 2018-2022 Leonard Reuter.\n"\ - "Copyright © 2022-2022 Michel V. Heinz."; + "LuFG Theoretical Chemistry, RWTH Aachen University"; splashScreen->showMessage(message.c_str(), Qt::AlignBottom, Qt::gray);