diff --git a/avogadro/core/avospglib.cpp b/avogadro/core/avospglib.cpp index 530969f9e7..159703f8b3 100644 --- a/avogadro/core/avospglib.cpp +++ b/avogadro/core/avospglib.cpp @@ -31,7 +31,7 @@ extern "C" { namespace Avogadro { namespace Core { -unsigned short AvoSpglib::getHallNumber(const Molecule& mol, double cartTol) +unsigned short AvoSpglib::getHallNumber(Molecule& mol, double cartTol) { if (!mol.unitCell()) return 0; @@ -80,6 +80,7 @@ unsigned short AvoSpglib::getHallNumber(const Molecule& mol, double cartTol) delete[] positions; delete[] types; + mol.setHallNumber(hallNumber); return hallNumber; } @@ -175,6 +176,9 @@ bool AvoSpglib::standardizeCell(Molecule& mol, double cartTol, bool toPrimitive, // Set the new molecule mol = newMol; + + // Set the space group in the molecule + getHallNumber(mol, cartTol); return true; } diff --git a/avogadro/core/avospglib.h b/avogadro/core/avospglib.h index bcb20f395d..e499138190 100644 --- a/avogadro/core/avospglib.h +++ b/avogadro/core/avospglib.h @@ -38,11 +38,13 @@ class AVOGADROCORE_EXPORT AvoSpglib * Use spglib to find the Hall number for a crystal. If the unit cell does not * exist or if the algorithm fails, 0 will be returned. * + * If the algorithm succeeds, the hall number will be set in the molecule. + * * @param mol The molecule to be handled. * @param cartTol The cartesian tolerance for spglib. * @return The Hall number for the crystal. */ - static unsigned short getHallNumber(const Molecule& mol, + static unsigned short getHallNumber(Molecule& mol, double cartTol = 1e-5); /** @@ -50,6 +52,8 @@ class AVOGADROCORE_EXPORT AvoSpglib * is missing its unit cell, it will be edited by spglib. Positions are * not idealized. * + * If the algorithm succeeds, the hall number will be set in the molecule. + * * @param mol The molecule to be reduced to its primitive cell. * @param cartTol The cartesian tolerance for spglib. * @return False if the molecule has no unit cell or if the @@ -62,6 +66,8 @@ class AVOGADROCORE_EXPORT AvoSpglib * molecule is missing its unit cell, it will be edited by spglib. Positions * are idealized. * + * If the algorithm succeeds, the hall number will be set in the molecule. + * * @param mol The molecule to be conventionalized. * @param cartTol The cartesian tolerance for spglib. * @return False if the molecule has no unit cell or if the @@ -74,6 +80,8 @@ class AVOGADROCORE_EXPORT AvoSpglib * its unit cell, it will be edited by spglib. It will be reduced * to its primitive form, and positions will be idealized. * + * If the algorithm succeeds, the hall number will be set in the molecule. + * * @param mol The molecule to be conventionalized. * @param cartTol The cartesian tolerance for spglib. * @return False if the molecule has no unit cell or if the diff --git a/avogadro/core/molecule.h b/avogadro/core/molecule.h index d664ed3cce..72683bf144 100644 --- a/avogadro/core/molecule.h +++ b/avogadro/core/molecule.h @@ -577,6 +577,15 @@ class AVOGADROCORE_EXPORT Molecule const UnitCell* unitCell() const { return m_unitCell; } /** @} */ + /** + * The space group for this molecule. It is updated after every + * space group operation. + * @{ + */ + void setHallNumber(unsigned short hallNumber) { m_hallNumber = hallNumber; } + unsigned short hallNumber() const { return m_hallNumber; } + /** @} */ + Array vibrationFrequencies() const; void setVibrationFrequencies(const Array& freq); Array vibrationIntensities() const; @@ -676,6 +685,9 @@ class AVOGADROCORE_EXPORT Molecule UnitCell* m_unitCell; Array m_residues; + // This will be stored from the last space group operation + unsigned short m_hallNumber = 0; + /** Update the graph to correspond to the current molecule. */ void updateGraph() const; }; diff --git a/avogadro/qtplugins/CMakeLists.txt b/avogadro/qtplugins/CMakeLists.txt index 599f087f34..9944946b59 100644 --- a/avogadro/qtplugins/CMakeLists.txt +++ b/avogadro/qtplugins/CMakeLists.txt @@ -125,10 +125,14 @@ add_subdirectory(surfaces) add_subdirectory(spectra) add_subdirectory(vrml) +# Plugins that require VTK if(USE_VTK) add_subdirectory(plotpdf) add_subdirectory(plotrmsd) add_subdirectory(plotxrd) + if(BUILD_YAEHMOP_PLUGIN) + add_subdirectory(yaehmop) + endif() add_subdirectory(coloropacitymap) endif() diff --git a/avogadro/qtplugins/yaehmop/CMakeLists.txt b/avogadro/qtplugins/yaehmop/CMakeLists.txt new file mode 100644 index 0000000000..15ca6e8ad1 --- /dev/null +++ b/avogadro/qtplugins/yaehmop/CMakeLists.txt @@ -0,0 +1,22 @@ + +set(yaehmop_srcs + banddialog.cpp + specialkpoints.cpp + yaehmop.cpp + yaehmopout.cpp +) + +set(yaehmop_uis + banddialog.ui +) + +avogadro_plugin(Yaehmop + "Use yaehmop to perform extended Hückel calculations." + ExtensionPlugin + yaehmop.h + Yaehmop + "${yaehmop_srcs}" + "${yaehmop_uis}" +) + +target_link_libraries(Yaehmop LINK_PRIVATE AvogadroVtk) diff --git a/avogadro/qtplugins/yaehmop/banddialog.cpp b/avogadro/qtplugins/yaehmop/banddialog.cpp new file mode 100644 index 0000000000..4dc85eb937 --- /dev/null +++ b/avogadro/qtplugins/yaehmop/banddialog.cpp @@ -0,0 +1,71 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2018 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#include "banddialog.h" +#include "ui_banddialog.h" + +#include + +namespace Avogadro { +namespace QtPlugins { + +BandDialog::BandDialog(QWidget* aParent, YaehmopSettings& yaehmopSettings) + : QDialog(aParent), m_ui(new Ui::BandDialog), + m_yaehmopSettings(yaehmopSettings) +{ + m_ui->setupUi(this); +} + +BandDialog::~BandDialog() = default; + +int BandDialog::exec() +{ + // Load the settings then exec + m_ui->spin_numKPoints->setValue(m_yaehmopSettings.numBandKPoints); + m_ui->edit_specialKPoints->setText(m_yaehmopSettings.specialKPoints); + m_ui->cb_displayYaehmopInput->setChecked( + m_yaehmopSettings.displayYaehmopInput); + m_ui->cb_limitY->setChecked(m_yaehmopSettings.limitY); + m_ui->spin_minY->setValue(m_yaehmopSettings.minY); + m_ui->spin_maxY->setValue(m_yaehmopSettings.maxY); + m_ui->cb_plotFermi->setChecked(m_yaehmopSettings.plotFermi); + m_ui->spin_fermi->setValue(m_yaehmopSettings.fermi); + m_ui->cb_zeroFermi->setChecked(m_yaehmopSettings.zeroFermi); + m_ui->spin_numDim->setValue(m_yaehmopSettings.numDim); + + return QDialog::exec(); +} + +void BandDialog::accept() +{ + // Save the settings and accept + m_yaehmopSettings.numBandKPoints = m_ui->spin_numKPoints->value(); + m_yaehmopSettings.specialKPoints = m_ui->edit_specialKPoints->toPlainText(); + m_yaehmopSettings.displayYaehmopInput = + m_ui->cb_displayYaehmopInput->isChecked(); + m_yaehmopSettings.limitY = m_ui->cb_limitY->isChecked(); + m_yaehmopSettings.minY = m_ui->spin_minY->value(); + m_yaehmopSettings.maxY = m_ui->spin_maxY->value(); + m_yaehmopSettings.plotFermi = m_ui->cb_plotFermi->isChecked(); + m_yaehmopSettings.fermi = m_ui->spin_fermi->value(); + m_yaehmopSettings.zeroFermi = m_ui->cb_zeroFermi->isChecked(); + m_yaehmopSettings.numDim = m_ui->spin_numDim->value(); + + QDialog::accept(); +} + +} // namespace QtPlugins +} // namespace Avogadro diff --git a/avogadro/qtplugins/yaehmop/banddialog.h b/avogadro/qtplugins/yaehmop/banddialog.h new file mode 100644 index 0000000000..078a562b1b --- /dev/null +++ b/avogadro/qtplugins/yaehmop/banddialog.h @@ -0,0 +1,57 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2018 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#ifndef AVOGADRO_QTPLUGINS_YAEHMOPBANDDIALOG_H +#define AVOGADRO_QTPLUGINS_YAEHMOPBANDDIALOG_H + +#include + +#include + +#include "yaehmopsettings.h" + +namespace Avogadro { +namespace QtPlugins { + +namespace Ui { +class BandDialog; +} + +/** + * @brief Dialog to perform a band structure calculation with yaehmop. + */ +class BandDialog : public QDialog +{ + Q_OBJECT + +public: + explicit BandDialog(QWidget* parent, YaehmopSettings& yaehmopSettings); + ~BandDialog(); + +public slots: + int exec() override; + +protected slots: + void accept() override; + +private: + std::unique_ptr m_ui; + YaehmopSettings& m_yaehmopSettings; +}; + +} // namespace QtPlugins +} // namespace Avogadro +#endif // AVOGADRO_QTPLUGINS_YAEHMOPBANDDIALOG_H diff --git a/avogadro/qtplugins/yaehmop/banddialog.ui b/avogadro/qtplugins/yaehmop/banddialog.ui new file mode 100644 index 0000000000..43f8e85fd9 --- /dev/null +++ b/avogadro/qtplugins/yaehmop/banddialog.ui @@ -0,0 +1,337 @@ + + + Avogadro::QtPlugins::BandDialog + + + + 0 + 0 + 599 + 406 + + + + Yaehmop Band + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + false + + + Min y: + + + eV + + + 5 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + + + + + <html><head/><body><p>The Fermi level should be known before checking this box. You can discover the Fermi level by performing a density of states calculation and displaying the data (it will be at the top of the data). In addition, if a density of states calculation is performed, the Fermi level here will automatically be set to what was detected during the density of states calculation.</p><p>If this box is checked, be sure the correct Fermi level is set in the spinbox on the right.</p><p>Default: off</p></body></html> + + + Qt::RightToLeft + + + Plot Fermi? + + + + + + + false + + + <html><head/><body><p>Adjust the energies so that the zero is the Fermi? Only available if we are plotting the Fermi level.</p><p><br/></p><p>Default: off</p></body></html> + + + Qt::RightToLeft + + + Zero Fermi? + + + + + + + Num k-points connecting special k-points: + + + + + + + Special k-points + + + + + + + false + + + Max y: + + + eV + + + 5 + + + -1000.000000000000000 + + + 1000.000000000000000 + + + + + + + false + + + <html><head/><body><p>The Fermi Level</p></body></html> + + + eV + + + 5 + + + -10000.000000000000000 + + + 10000.000000000000000 + + + 0.100000000000000 + + + + + + + <html><head/><body><p>Enter special k-points as such:</p><p>L 0.5 0.5 0.5</p><p>G 0.0 0.0 0.0</p><p>X 0.5 0.0 0.5</p><p>That is, &lt;symbol&gt; &lt;x&gt; &lt;y&gt; &lt;z&gt; where x, y, and z are fractional reciprocal space coordinates. Lines will be drawn connecting these k-points on the graph in the order you put them in. Please note that the orientation of your cell may have an effect on the locations of these reciprocal space points.</p><p>If the space group of the crystal has been perceived or set, the special k points will be automatically filled up with the primitive cell high symmetry points for that space group. There are a few space groups will different high symmetry points depending on the lattice (such as if a &gt; b or a &lt; b) - that is taken into account automatically.</p></body></html> + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Cantarell'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Ubuntu';">GM 0.0 0.0 0.0</span></p></body></html> + + + + + + + <html><head/><body><p>Enter the number of k-points that will be connecting the special k-points. More of these k-points will smooth out the graph, but the calculation may take longer.</p><p>Default: 40</p></body></html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + 0 + + + 999999 + + + 40 + + + + + + + <html><head/><body><p>Limit the y-range in the plot?</p><p>Default: off</p></body></html> + + + Limit y-range? + + + + + + + <html><head/><body><p>The number of periodic dimensions.</p><p><br/></p><p>If this is set to 1, the material will be periodic only along the A vector of the crystal.</p><p><br/></p><p>If this is set to 2, the material will be periodic along both the A and B vectors of the crystal.</p><p><br/></p><p>If this is set to 3, the material will be periodic along the A, B, and C vectors of the crystal.</p><p><br/></p></body></html> + + + Qt::LeftToRight + + + Num Dimensions: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <html><head/><body><p>The number of periodic dimensions.</p><p><br/></p><p>If this is set to 1, the material will be periodic only along the A vector of the crystal.</p><p><br/></p><p>If this is set to 2, the material will be periodic along both the A and B vectors of the crystal.</p><p><br/></p><p>If this is set to 3, the material will be periodic along the A, B, and C vectors of the crystal.</p><p><br/></p></body></html> + + + 1 + + + 3 + + + 3 + + + + + + + Display Yaehmop Input? + + + + + + + spin_numKPoints + edit_specialKPoints + cb_displayYaehmopInput + cb_limitY + spin_minY + spin_maxY + cb_plotFermi + spin_fermi + cb_zeroFermi + spin_numDim + + + + + buttonBox + accepted() + Avogadro::QtPlugins::BandDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Avogadro::QtPlugins::BandDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + cb_limitY + toggled(bool) + spin_minY + setEnabled(bool) + + + 449 + 180 + + + 449 + 211 + + + + + cb_limitY + toggled(bool) + spin_maxY + setEnabled(bool) + + + 449 + 180 + + + 449 + 244 + + + + + cb_plotFermi + toggled(bool) + spin_fermi + setEnabled(bool) + + + 170 + 250 + + + 449 + 251 + + + + + cb_plotFermi + toggled(bool) + cb_zeroFermi + setEnabled(bool) + + + 170 + 225 + + + 170 + 255 + + + + + diff --git a/avogadro/qtplugins/yaehmop/specialkpoints.cpp b/avogadro/qtplugins/yaehmop/specialkpoints.cpp new file mode 100644 index 0000000000..b62172704c --- /dev/null +++ b/avogadro/qtplugins/yaehmop/specialkpoints.cpp @@ -0,0 +1,238 @@ +/******************************************************************************* + + This source file is part of the Avogadro project. + + Copyright 2018 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*******************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include + +#include "specialkpoints.h" +#include "specialkpointsdata.h" + +using Avogadro::Vector3; +using Avogadro::Core::AvoSpglib; +using Avogadro::Core::Molecule; +using Avogadro::Core::SpaceGroups; +using Avogadro::Core::UnitCell; + +namespace Avogadro { +namespace QtPlugins { + +QString SpecialKPoints::getSpecialKPoints(Molecule& mol) +{ + UnitCell* cell = mol.unitCell(); + if (cell) { + // Check to see if the space group is set. + unsigned short hallNumber = mol.hallNumber(); + // Try to find the space group if it is not set + if (!hallNumber) { + hallNumber = AvoSpglib::getHallNumber(mol); + // If we still can't find the hall number, just return + if (!hallNumber) + return QString(); + } + + unsigned short spgNum = SpaceGroups::internationalNumber(hallNumber); + if (spgNum != 0 && spgNum < 231) { + QString specialKPoints = special_k_points[spgNum]; + if (specialKPoints.contains("#")) + processConditionKPoints(specialKPoints, mol, spgNum); + return specialKPoints.replace(',', '\n'); + } + } + + // If we made it here, we failed + return QString(); +} + +void SpecialKPoints::processConditionKPoints(QString& specialKPoints, + Molecule& mol, + unsigned short spgNum) +{ + // Check to see if the space group is set. + UnitCell* cell = mol.unitCell(); + + if (!cell) { + qDebug() << "Error in " << __FUNCTION__ << ": cell is NULL!"; + specialKPoints = ""; + return; + } + + // Ensure the space group number is valid + if (spgNum == 0 || spgNum > 230) { + qDebug() << "Error in " << __FUNCTION__ << ": spg is invalid!"; + specialKPoints = ""; + return; + } + + QStringList stringSplit = specialKPoints.split("#"); + + switch (spgNum) { + // a > b or a < b + case 20: + case 21: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + case 63: + case 64: + case 65: + case 66: + case 67: + case 68: { + if (stringSplit.size() != 2) { + qDebug() << "Error in " << __FUNCTION__ << ": for spgNum " + << QString::number(spgNum) << ", size is not correct!"; + specialKPoints = ""; + } else { + unsigned short ind = 0; + // a > b? + if (cell->a() >= cell->b()) + ind = 0; + else + ind = 1; + specialKPoints = stringSplit[ind]; + } + return; + } + // a^-2 > b^-2 + c^-2, c^-2 > a^-2 + b^-2, or other + case 22: + case 42: + case 43: + case 69: + case 70: { + if (stringSplit.size() != 3) { + qDebug() << "Error in " << __FUNCTION__ << ": for spgNum " + << QString::number(spgNum) << ", size is not correct!"; + specialKPoints = ""; + } else { + unsigned short ind = 0; + double a = cell->a(); + double b = cell->b(); + double c = cell->c(); + if (pow(a, -2.0) >= pow(b, -2.0) + pow(c, -2.0)) + ind = 0; + else if (pow(c, -2.0) >= pow(a, -2.0) + pow(b, -2.0)) + ind = 1; + else + ind = 2; + specialKPoints = stringSplit[ind]; + } + return; + } + // (b > a > c or b > c > a) or other + case 23: + case 24: + case 44: + case 45: + case 46: + case 71: + case 72: + case 73: + case 74: { + if (stringSplit.size() != 2) { + qDebug() << "Error in " << __FUNCTION__ << ": for spgNum " + << QString::number(spgNum) << ", size is not correct!"; + specialKPoints = ""; + } else { + unsigned short ind = 0; + double a = cell->a(); + double b = cell->b(); + double c = cell->c(); + if ((b >= a && a >= c) || (b >= c && c >= a)) + ind = 0; + else + ind = 1; + specialKPoints = stringSplit[ind]; + } + return; + } + // c/a > 1 or other + case 79: + case 80: + case 82: + case 87: + case 88: + case 97: + case 98: + case 107: + case 108: + case 109: + case 110: + case 119: + case 120: + case 121: + case 122: + case 139: + case 140: + case 141: + case 142: { + if (stringSplit.size() != 2) { + qDebug() << "Error in " << __FUNCTION__ << ": for spgNum " + << QString::number(spgNum) << ", size is not correct!"; + specialKPoints = ""; + } else { + unsigned short ind = 0; + if (cell->c() / cell->a() >= 1) + ind = 0; + else + ind = 1; + specialKPoints = stringSplit[ind]; + } + return; + } + // sqrt3a > sqrt2c or other + case 146: + case 148: + case 155: + case 160: + case 161: + case 166: + case 167: { + if (stringSplit.size() != 2) { + qDebug() << "Error in " << __FUNCTION__ << ": for spgNum " + << QString::number(spgNum) << ", size is not correct!"; + specialKPoints = ""; + } else { + unsigned short ind = 0; + if (sqrt(3.0 * cell->a()) >= sqrt(2.0 * cell->c())) + ind = 0; + else + ind = 1; + specialKPoints = stringSplit[ind]; + } + return; + } + // This shouldn't happen + default: { + qDebug() << "Error in" << __FUNCTION__ << ": failed to process spg " + << QString::number(spgNum); + specialKPoints = ""; + return; + } + } +} + +} // namespace QtPlugins +} // namespace Avogadro diff --git a/avogadro/qtplugins/yaehmop/specialkpoints.h b/avogadro/qtplugins/yaehmop/specialkpoints.h new file mode 100644 index 0000000000..be8d80cf20 --- /dev/null +++ b/avogadro/qtplugins/yaehmop/specialkpoints.h @@ -0,0 +1,66 @@ +/******************************************************************************* + + This source file is part of the Avogadro project. + + Copyright 2018 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*******************************************************************************/ + +#ifndef AVOGADRO_QTPLUGINS_YAEHMOP_SPECIALKPOINTS_H +#define AVOGADRO_QTPLUGINS_YAEHMOP_SPECIALKPOINTS_H + +namespace Avogadro { +namespace Core { +class Molecule; +} +} // namespace Avogadro + +namespace Avogadro { +namespace QtPlugins { + +#include + +class SpecialKPoints +{ +public: + /* Get the special k points for a particular space group. It will + * be returned like the following: + * + * GM 0 0 0 + * Y 0 0.5 0 + * etc. + * + * @param mol The molecule for which to get special k points. If the + * space group is cached, that will be used. If not, this + * function will attempt to determine the space group via + * avospglib. If that fails, an empty string is returned. + * + * @return A QString containing the data for the special kpoint. + */ + static QString getSpecialKPoints(Core::Molecule& mol); + +private: + /* Process a special k point with a condition. These special k points + * are separated in specialkpointsdata.h by a '#' symbol. This function + * has stored in it all of the cases for different conditions. It will + * process and change the @param specialKPoints to be the correct + * QString for the @param molecule. + * + */ + static void processConditionKPoints(QString& specialKPoints, + Core::Molecule& mol, + unsigned short spgNum); +}; + +} // namespace QtPlugins +} // namespace Avogadro + +#endif diff --git a/avogadro/qtplugins/yaehmop/specialkpointsdata.h b/avogadro/qtplugins/yaehmop/specialkpointsdata.h new file mode 100644 index 0000000000..7d2f3ccbb8 --- /dev/null +++ b/avogadro/qtplugins/yaehmop/specialkpointsdata.h @@ -0,0 +1,409 @@ +/******************************************************************************* + + This source file is part of the Avogadro project. + + Copyright 2018 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*******************************************************************************/ + +#ifndef AVOGADRO_QTPLUGINS_YAEHMOP_SPECIALKPOINTSDATA_H +#define AVOGADRO_QTPLUGINS_YAEHMOP_SPECIALKPOINTSDATA_H + +namespace Avogadro { +namespace QtPlugins { + +// There are 230 of these (not including the first value, which is null) +// One point for each space group. +// If there are multiple ways to express a space group's special k points +// depending on some conditions like if a > b or a < b, there is a # +// separating the different conditions +const char* special_k_points[] = { + "", + "GM 0 0 0", // 1 + "GM 0 0 0,Z 0 0 0.5,Y 0 0.5 0,X 0.5 0 0,V 0.5 0.5 0,U 0.5 0 0.5,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 2 + "GM 0 0 0,Z 0 0.5 0,B 0 0 0.5,D 0 0.5 0.5,Y 0.5 0 0,C 0.5 0.5 0,A -0.5 0 " + "0.5,E -0.5 0.5 0.5", // 3 + "GM 0 0 0,Z 0 0.5 0,B 0 0 0.5,D 0 0.5 0.5,Y 0.5 0 0,C 0.5 0.5 0,A -0.5 0 " + "0.5,E -0.5 0.5 0.5", // 4 + "GM 0 0 0,Y 0.5 0.5 0,A 0 0 0.5,M 0.5 0.5 0.5", // 5 + "GM 0 0 0,B 0 0 0.5,Y 0.5 0 0,A -0.5 0 0.5,Z 0 0.5 0,C 0.5 0.5 0,D 0 0.5 " + "0.5,E -0.5 0.5 0.5", // 6 + "GM 0 0 0,B 0 0 0.5,Y 0.5 0 0,A -0.5 0 0.5,Z 0 0.5 0,C 0.5 0.5 0,D 0 0.5 " + "0.5,E -0.5 0.5 0.5", // 7 + "GM 0 0 0,Y 0.5 0.5 0,A 0 0 0.5,M 0.5 0.5 0.5", // 8 + "GM 0 0 0,Y 0.5 0.5 0,A 0 0 0.5,M 0.5 0.5 0.5", // 9 + "GM 0 0 0,Z 0 0.5 0,B 0 0 0.5,Y 0.5 0 0,C 0.5 0.5 0,D 0 0.5 0.5,A -0.5 0 " + "0.5,E -0.5 0.5 0.5", // 10 + "GM 0 0 0,Z 0 0.5 0,B 0 0 0.5,Y 0.5 0 0,C 0.5 0.5 0,D 0 0.5 0.5,A -0.5 0 " + "0.5,E -0.5 0.5 0.5", // 11 + "GM 0 0 0,Y 0.5 0.5 0,A 0 0 0.5,M 0.5 0.5 0.5,V 0.5 0 0,L 0.5 0 0.5", // 12 + "GM 0 0 0,Z 0 0.5 0,B 0 0 0.5,Y 0.5 0 0,C 0.5 0.5 0,D 0 0.5 0.5,A -0.5 0 " + "0.5,E -0.5 0.5 0.5", // 13 + "GM 0 0 0,Z 0 0.5 0,B 0 0 0.5,Y 0.5 0 0,C 0.5 0.5 0,D 0 0.5 0.5,A -0.5 0 " + "0.5,E -0.5 0.5 0.5", // 14 + "GM 0 0 0,Y 0.5 0.5 0,A 0 0 0.5,M 0.5 0.5 0.5,V 0.5 0 0,L 0.5 0 0.5", // 15 + "GM 0 0 0,X 0.5 0 0,Y 0 0.5 0,Z 0 0 0.5,S 0.5 0.5 0,U 0.5 0 0.5,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 16 + "GM 0 0 0,X 0.5 0 0,Y 0 0.5 0,Z 0 0 0.5,S 0.5 0.5 0,U 0.5 0 0.5,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 17 + "GM 0 0 0,X 0.5 0 0,Y 0 0.5 0,Z 0 0 0.5,S 0.5 0.5 0,U 0.5 0 0.5,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 18 + "GM 0 0 0,X 0.5 0 0,Y 0 0.5 0,Z 0 0 0.5,S 0.5 0.5 0,U 0.5 0 0.5,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 19 + "GM 0 0 0,Y 0.5 0.5 0,T 0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5#GM 0 0 " + "0,Y -0.5 0.5 0,T -0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5", // 20 + "GM 0 0 0,Y 0.5 0.5 0,T 0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5#GM 0 0 " + "0,Y -0.5 0.5 0,T -0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5", // 21 + "GM 0 0 0,T 1 0.5 0.5,Z 0.5 0.5 0,Y 0.5 0 0.5#GM 0 0 0,T 0 0.5 0.5,Z 0.5 0.5 " + "1,Y 0.5 0 0.5#GM 0 0 0,T 0 0.5 0.5,Z 0.5 0.5 0,Y 0.5 0 0.5", // 22 + "GM 0 0 0,X 0.5 -0.5 0.5,W 0.25 0.25 0.25,WA -0.25 -0.25 0.75,T 0 0 0.5,R 0 " + "0.5 0,S 0.5 0 0#GM 0 0 0,X 0.5 0.5 -0.5,W 0.25 0.25 0.25,WA -0.25 -0.25 " + "0.75,T 0 0 0.5,R 0 0.5 0,S 0.5 0 0", // 23 + "GM 0 0 0,X 0.5 -0.5 0.5,W 0.25 0.25 0.25,WA -0.25 -0.25 0.75,T 0 0 0.5,R 0 " + "0.5 0,S 0.5 0 0#GM 0 0 0,X 0.5 0.5 -0.5,W 0.25 0.25 0.25,WA -0.25 -0.25 " + "0.75,T 0 0 0.5,R 0 0.5 0,S 0.5 0 0", // 24 + "GM 0 0 0,Z 0 0 0.5,Y 0 0.5 0,T 0 0.5 0.5,X 0.5 0 0,U 0.5 0 0.5,S 0.5 0.5 " + "0,R 0.5 0.5 0.5", // 25 + "GM 0 0 0,Z 0 0 0.5,Y 0 0.5 0,T 0 0.5 0.5,X 0.5 0 0,U 0.5 0 0.5,S 0.5 0.5 " + "0,R 0.5 0.5 0.5", // 26 + "GM 0 0 0,Z 0 0 0.5,Y 0 0.5 0,T 0 0.5 0.5,X 0.5 0 0,U 0.5 0 0.5,S 0.5 0.5 " + "0,R 0.5 0.5 0.5", // 27 + "GM 0 0 0,Z 0 0 0.5,Y 0 0.5 0,T 0 0.5 0.5,X 0.5 0 0,U 0.5 0 0.5,S 0.5 0.5 " + "0,R 0.5 0.5 0.5", // 28 + "GM 0 0 0,Z 0 0 0.5,Y 0 0.5 0,T 0 0.5 0.5,X 0.5 0 0,U 0.5 0 0.5,S 0.5 0.5 " + "0,R 0.5 0.5 0.5", // 29 + "GM 0 0 0,Z 0 0 0.5,Y 0 0.5 0,T 0 0.5 0.5,X 0.5 0 0,U 0.5 0 0.5,S 0.5 0.5 " + "0,R 0.5 0.5 0.5", // 30 + "GM 0 0 0,Z 0 0 0.5,Y 0 0.5 0,T 0 0.5 0.5,X 0.5 0 0,U 0.5 0 0.5,S 0.5 0.5 " + "0,R 0.5 0.5 0.5", // 31 + "GM 0 0 0,Z 0 0 0.5,Y 0 0.5 0,T 0 0.5 0.5,X 0.5 0 0,U 0.5 0 0.5,S 0.5 0.5 " + "0,R 0.5 0.5 0.5", // 32 + "GM 0 0 0,Z 0 0 0.5,Y 0 0.5 0,T 0 0.5 0.5,X 0.5 0 0,U 0.5 0 0.5,S 0.5 0.5 " + "0,R 0.5 0.5 0.5", // 33 + "GM 0 0 0,Z 0 0 0.5,Y 0 0.5 0,T 0 0.5 0.5,X 0.5 0 0,U 0.5 0 0.5,S 0.5 0.5 " + "0,R 0.5 0.5 0.5", // 34 + "GM 0 0 0,Z 0 0 0.5,Y 0.5 0.5 0,T 0.5 0.5 0.5,S 0 0.5 0,R 0 0.5 0.5#GM 0 0 " + "0,Z 0 0 0.5,Y -0.5 0.5 0,T -0.5 0.5 0.5,S 0 0.5 0,R 0 0.5 0.5", // 35 + "GM 0 0 0,Z 0 0 0.5,Y 0.5 0.5 0,T 0.5 0.5 0.5,S 0 0.5 0,R 0 0.5 0.5#GM 0 0 " + "0,Z 0 0 0.5,Y -0.5 0.5 0,T -0.5 0.5 0.5,S 0 0.5 0,R 0 0.5 0.5", // 36 + "GM 0 0 0,Z 0 0 0.5,Y 0.5 0.5 0,T 0.5 0.5 0.5,S 0 0.5 0,R 0 0.5 0.5#GM 0 0 " + "0,Z 0 0 0.5,Y -0.5 0.5 0,T -0.5 0.5 0.5,S 0 0.5 0,R 0 0.5 0.5", // 37 + "GM 0 0 0,Y 0.5 0.5 0,T 0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5#GM 0 0 " + "0,Y -0.5 0.5 0,T -0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5", // 38 + "GM 0 0 0,Y 0.5 0.5 0,T 0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5#GM 0 0 " + "0,Y -0.5 0.5 0,T -0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5", // 39 + "GM 0 0 0,Y 0.5 0.5 0,T 0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5#GM 0 0 " + "0,Y -0.5 0.5 0,T -0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5", // 40 + "GM 0 0 0,Y 0.5 0.5 0,T 0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5#GM 0 0 " + "0,Y -0.5 0.5 0,T -0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5", // 41 + "GM 0 0 0,Z 0.5 0.5 0,T 1 0.5 0.5,Y 0.5 0 0.5#GM 0 0 0,Z 0.5 0.5 1,T 0 0.5 " + "0.5,Y 0.5 0 0.5#GM 0 0 0,Z 0.5 0.5 0,T 0 0.5 0.5,Y 0.5 0 0.5", // 42 + "GM 0 0 0,Z 0.5 0.5 0,T 1 0.5 0.5,Y 0.5 0 0.5#GM 0 0 0,Z 0.5 0.5 1,T 0 0.5 " + "0.5,Y 0.5 0 0.5#GM 0 0 0,Z 0.5 0.5 0,T 0 0.5 0.5,Y 0.5 0 0.5", // 43 + "GM 0 0 0,X 0.5 -0.5 0.5,T 0 0 0.5,W 0.25 0.25 0.25,S 0.5 0 0,R 0 0.5 0#GM 0 " + "0 0,X 0.5 0.5 -0.5,T 0 0 0.5,W 0.25 0.25 0.25,S 0.5 0 0,R 0 0.5 0", // 44 + "GM 0 0 0,X 0.5 -0.5 0.5,T 0 0 0.5,W 0.25 0.25 0.25,S 0.5 0 0,R 0 0.5 0#GM 0 " + "0 0,X 0.5 0.5 -0.5,T 0 0 0.5,W 0.25 0.25 0.25,S 0.5 0 0,R 0 0.5 0", // 45 + "GM 0 0 0,X 0.5 -0.5 0.5,T 0 0 0.5,W 0.25 0.25 0.25,S 0.5 0 0,R 0 0.5 0#GM 0 " + "0 0,X 0.5 0.5 -0.5,T 0 0 0.5,W 0.25 0.25 0.25,S 0.5 0 0,R 0 0.5 0", // 46 + "GM 0 0 0,X 0.5 0 0,Z 0 0 0.5,U 0.5 0 0.5,Y 0 0.5 0,S 0.5 0.5 0,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 47 + "GM 0 0 0,X 0.5 0 0,Z 0 0 0.5,U 0.5 0 0.5,Y 0 0.5 0,S 0.5 0.5 0,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 48 + "GM 0 0 0,X 0.5 0 0,Z 0 0 0.5,U 0.5 0 0.5,Y 0 0.5 0,S 0.5 0.5 0,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 49 + "GM 0 0 0,X 0.5 0 0,Z 0 0 0.5,U 0.5 0 0.5,Y 0 0.5 0,S 0.5 0.5 0,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 50 + "GM 0 0 0,X 0.5 0 0,Z 0 0 0.5,U 0.5 0 0.5,Y 0 0.5 0,S 0.5 0.5 0,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 51 + "GM 0 0 0,X 0.5 0 0,Z 0 0 0.5,U 0.5 0 0.5,Y 0 0.5 0,S 0.5 0.5 0,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 52 + "GM 0 0 0,X 0.5 0 0,Z 0 0 0.5,U 0.5 0 0.5,Y 0 0.5 0,S 0.5 0.5 0,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 53 + "GM 0 0 0,X 0.5 0 0,Z 0 0 0.5,U 0.5 0 0.5,Y 0 0.5 0,S 0.5 0.5 0,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 54 + "GM 0 0 0,X 0.5 0 0,Z 0 0 0.5,U 0.5 0 0.5,Y 0 0.5 0,S 0.5 0.5 0,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 55 + "GM 0 0 0,X 0.5 0 0,Z 0 0 0.5,U 0.5 0 0.5,Y 0 0.5 0,S 0.5 0.5 0,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 56 + "GM 0 0 0,X 0.5 0 0,Z 0 0 0.5,U 0.5 0 0.5,Y 0 0.5 0,S 0.5 0.5 0,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 57 + "GM 0 0 0,X 0.5 0 0,Z 0 0 0.5,U 0.5 0 0.5,Y 0 0.5 0,S 0.5 0.5 0,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 58 + "GM 0 0 0,X 0.5 0 0,Z 0 0 0.5,U 0.5 0 0.5,Y 0 0.5 0,S 0.5 0.5 0,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 59 + "GM 0 0 0,X 0.5 0 0,Z 0 0 0.5,U 0.5 0 0.5,Y 0 0.5 0,S 0.5 0.5 0,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 60 + "GM 0 0 0,X 0.5 0 0,Z 0 0 0.5,U 0.5 0 0.5,Y 0 0.5 0,S 0.5 0.5 0,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 61 + "GM 0 0 0,X 0.5 0 0,Z 0 0 0.5,U 0.5 0 0.5,Y 0 0.5 0,S 0.5 0.5 0,T 0 0.5 " + "0.5,R 0.5 0.5 0.5", // 62 + "GM 0 0 0,Y 0.5 0.5 0,T 0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5#GM 0 0 " + "0,Y -0.5 0.5 0,T -0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5", // 63 + "GM 0 0 0,Y 0.5 0.5 0,T 0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5#GM 0 0 " + "0,Y -0.5 0.5 0,T -0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5", // 64 + "GM 0 0 0,Y 0.5 0.5 0,T 0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5#GM 0 0 " + "0,Y -0.5 0.5 0,T -0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5", // 65 + "GM 0 0 0,Y 0.5 0.5 0,T 0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5#GM 0 0 " + "0,Y -0.5 0.5 0,T -0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5", // 66 + "GM 0 0 0,Y 0.5 0.5 0,T 0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5#GM 0 0 " + "0,Y -0.5 0.5 0,T -0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5", // 67 + "GM 0 0 0,Y 0.5 0.5 0,T 0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5#GM 0 0 " + "0,Y -0.5 0.5 0,T -0.5 0.5 0.5,Z 0 0 0.5,S 0 0.5 0,R 0 0.5 0.5", // 68 + "GM 0 0 0,T 1 0.5 0.5,Z 0.5 0.5 0,Y 0.5 0 0.5,L 0.5 0.5 0.5#GM 0 0 0,T 0 0.5 " + "0.5,Z 0.5 0.5 1,Y 0.5 0 0.5,L 0.5 0.5 0.5#GM 0 0 0,T 0 0.5 0.5,Z 0.5 0.5 " + "0,Y 0.5 0 0.5,L 0.5 0.5 0.5", // 69 + "GM 0 0 0,T 1 0.5 0.5,Z 0.5 0.5 0,Y 0.5 0 0.5,L 0.5 0.5 0.5#GM 0 0 0,T 0 0.5 " + "0.5,Z 0.5 0.5 1,Y 0.5 0 0.5,L 0.5 0.5 0.5#GM 0 0 0,T 0 0.5 0.5,Z 0.5 0.5 " + "0,Y 0.5 0 0.5,L 0.5 0.5 0.5", // 70 + "GM 0 0 0,X 0.5 -0.5 0.5,S 0.5 0 0,R 0 0.5 0,T 0 0 0.5,W 0.25 0.25 0.25#GM 0 " + "0 0,X 0.5 0.5 -0.5,S 0.5 0 0,R 0 0.5 0,T 0 0 0.5,W 0.25 0.25 0.25", // 71 + "GM 0 0 0,X 0.5 -0.5 0.5,S 0.5 0 0,R 0 0.5 0,T 0 0 0.5,W 0.25 0.25 0.25#GM 0 " + "0 0,X 0.5 0.5 -0.5,S 0.5 0 0,R 0 0.5 0,T 0 0 0.5,W 0.25 0.25 0.25", // 72 + "GM 0 0 0,X 0.5 -0.5 0.5,S 0.5 0 0,R 0 0.5 0,T 0 0 0.5,W 0.25 0.25 0.25#GM 0 " + "0 0,X 0.5 0.5 -0.5,S 0.5 0 0,R 0 0.5 0,T 0 0 0.5,W 0.25 0.25 0.25", // 73 + "GM 0 0 0,X 0.5 -0.5 0.5,S 0.5 0 0,R 0 0.5 0,T 0 0 0.5,W 0.25 0.25 0.25#GM 0 " + "0 0,X 0.5 0.5 -0.5,S 0.5 0 0,R 0 0.5 0,T 0 0 0.5,W 0.25 0.25 0.25", // 74 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 75 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 76 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 77 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 78 + "GM 0 0 0,M 0.5 0.5 -0.5,X 0 0 0.5,P 0.25 0.25 0.25#GM 0 0 0,M -0.5 0.5 " + "0.5,X 0 0 0.5,P 0.25 0.25 0.25", // 79 + "GM 0 0 0,M 0.5 0.5 -0.5,X 0 0 0.5,P 0.25 0.25 0.25#GM 0 0 0,M -0.5 0.5 " + "0.5,X 0 0 0.5,P 0.25 0.25 0.25", // 80 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 81 + "GM 0 0 0,M 0.5 0.5 -0.5,P 0.25 0.25 0.25,PA -0.25 -0.25 0.75,X 0 0 0.5#GM 0 " + "0 0,M -0.5 0.5 0.5,P 0.25 0.25 0.25,PA -0.25 -0.25 0.75,X 0 0 0.5", // 82 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 83 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 84 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 85 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 86 + "GM 0 0 0,M 0.5 0.5 -0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0#GM 0 0 0,M " + "-0.5 0.5 0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0", // 87 + "GM 0 0 0,M 0.5 0.5 -0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0#GM 0 0 0,M " + "-0.5 0.5 0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0", // 88 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 89 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 90 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 91 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 92 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 93 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 94 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 95 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 96 + "GM 0 0 0,M 0.5 0.5 -0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0#GM 0 0 0,M " + "-0.5 0.5 0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0", // 97 + "GM 0 0 0,M 0.5 0.5 -0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0#GM 0 0 0,M " + "-0.5 0.5 0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0", // 98 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 99 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 100 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 101 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 102 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 103 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 104 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 105 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,X 0 0.5 0,R 0 0.5 0.5", // 106 + "GM 0 0 0,M 0.5 0.5 -0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0#GM 0 0 0,M " + "-0.5 0.5 0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0", // 107 + "GM 0 0 0,M 0.5 0.5 -0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0#GM 0 0 0,M " + "-0.5 0.5 0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0", // 108 + "GM 0 0 0,M 0.5 0.5 -0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0#GM 0 0 0,M " + "-0.5 0.5 0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0", // 109 + "GM 0 0 0,M 0.5 0.5 -0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0#GM 0 0 0,M " + "-0.5 0.5 0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0", // 110 + "GM 0 0 0,A 0.5 0.5 0.5,Z 0 0 0.5,M 0.5 0.5 0,X 0 0.5 0,R 0 0.5 0.5", // 111 + "GM 0 0 0,A 0.5 0.5 0.5,Z 0 0 0.5,M 0.5 0.5 0,X 0 0.5 0,R 0 0.5 0.5", // 112 + "GM 0 0 0,A 0.5 0.5 0.5,Z 0 0 0.5,M 0.5 0.5 0,X 0 0.5 0,R 0 0.5 0.5", // 113 + "GM 0 0 0,A 0.5 0.5 0.5,Z 0 0 0.5,M 0.5 0.5 0,X 0 0.5 0,R 0 0.5 0.5", // 114 + "GM 0 0 0,M 0.5 0.5 0,A 0.5 0.5 0.5,Z 0 0 0.5,X 0 0.5 0,R 0 0.5 0.5", // 115 + "GM 0 0 0,M 0.5 0.5 0,A 0.5 0.5 0.5,Z 0 0 0.5,X 0 0.5 0,R 0 0.5 0.5", // 116 + "GM 0 0 0,M 0.5 0.5 0,A 0.5 0.5 0.5,Z 0 0 0.5,X 0 0.5 0,R 0 0.5 0.5", // 117 + "GM 0 0 0,M 0.5 0.5 0,A 0.5 0.5 0.5,Z 0 0 0.5,X 0 0.5 0,R 0 0.5 0.5", // 118 + "GM 0 0 0,M 0.5 0.5 -0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0#GM 0 0 0,M " + "-0.5 0.5 0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0", // 119 + "GM 0 0 0,M 0.5 0.5 -0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0#GM 0 0 0,M " + "-0.5 0.5 0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0", // 120 + "GM 0 0 0,M 0.5 0.5 -0.5,P 0.25 0.25 0.25,PA -0.25 -0.25 0.75,X 0 0 0.5,N 0 " + "0.5 0#GM 0 0 0,M -0.5 0.5 0.5,P 0.25 0.25 0.25,PA -0.25 -0.25 0.75,X 0 0 " + "0.5,N 0 0.5 0", // 121 + "GM 0 0 0,M 0.5 0.5 -0.5,P 0.25 0.25 0.25,PA -0.25 -0.25 0.75,X 0 0 0.5,N 0 " + "0.5 0#GM 0 0 0,M -0.5 0.5 0.5,P 0.25 0.25 0.25,PA -0.25 -0.25 0.75,X 0 0 " + "0.5,N 0 0.5 0", // 122 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,R 0 0.5 0.5,X 0 0.5 0", // 123 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,R 0 0.5 0.5,X 0 0.5 0", // 124 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,R 0 0.5 0.5,X 0 0.5 0", // 125 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,R 0 0.5 0.5,X 0 0.5 0", // 126 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,R 0 0.5 0.5,X 0 0.5 0", // 127 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,R 0 0.5 0.5,X 0 0.5 0", // 128 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,R 0 0.5 0.5,X 0 0.5 0", // 129 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,R 0 0.5 0.5,X 0 0.5 0", // 130 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,R 0 0.5 0.5,X 0 0.5 0", // 131 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,R 0 0.5 0.5,X 0 0.5 0", // 132 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,R 0 0.5 0.5,X 0 0.5 0", // 133 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,R 0 0.5 0.5,X 0 0.5 0", // 134 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,R 0 0.5 0.5,X 0 0.5 0", // 135 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,R 0 0.5 0.5,X 0 0.5 0", // 136 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,R 0 0.5 0.5,X 0 0.5 0", // 137 + "GM 0 0 0,Z 0 0 0.5,M 0.5 0.5 0,A 0.5 0.5 0.5,R 0 0.5 0.5,X 0 0.5 0", // 138 + "GM 0 0 0,M 0.5 0.5 -0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0#GM 0 0 0,M " + "-0.5 0.5 0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0", // 139 + "GM 0 0 0,M 0.5 0.5 -0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0#GM 0 0 0,M " + "-0.5 0.5 0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0", // 140 + "GM 0 0 0,M 0.5 0.5 -0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0#GM 0 0 0,M " + "-0.5 0.5 0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0", // 141 + "GM 0 0 0,M 0.5 0.5 -0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0#GM 0 0 0,M " + "-0.5 0.5 0.5,X 0 0 0.5,P 0.25 0.25 0.25,N 0 0.5 0", // 142 + "GM 0 0 0,A 0 0 0.5,KA 0.666667 -0.333333 0,HA 0.666667 -0.333333 0.5,K " + "0.333333 0.333333 0,H 0.333333 0.333333 0.5", // 143 + "GM 0 0 0,A 0 0 0.5,KA 0.666667 -0.333333 0,HA 0.666667 -0.333333 0.5,K " + "0.333333 0.333333 0,H 0.333333 0.333333 0.5", // 144 + "GM 0 0 0,A 0 0 0.5,KA 0.666667 -0.333333 0,HA 0.666667 -0.333333 0.5,K " + "0.333333 0.333333 0,H 0.333333 0.333333 0.5", // 145 + "GM 0 0 0,T 0.5 0.5 -0.5#GM 0 0 0,T 0.5 0.5 0.5", // 146 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 147 + "GM 0 0 0,T 0.5 0.5 -0.5,L 0 0.5 0,FA 0 0.5 -0.5#GM 0 0 0,T 0.5 0.5 -0.5,L 0 " + "0.5 0,FB 0.5 0.5 0", // 148 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 149 + "GM 0 0 0,A 0 0 0.5,KA 0.666667 -0.333333 0,HA 0.666667 -0.333333 0.5,K " + "0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 0,L 0.5 0 0.5", // 150 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 151 + "GM 0 0 0,A 0 0 0.5,KA 0.666667 -0.333333 0,HA 0.666667 -0.333333 0.5,K " + "0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 0,L 0.5 0 0.5", // 152 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 153 + "GM 0 0 0,A 0 0 0.5,KA 0.666667 -0.333333 0,HA 0.666667 -0.333333 0.5,K " + "0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 0,L 0.5 0 0.5", // 154 + "GM 0 0 0,T 0.5 0.5 -0.5,FA 0 0.5 -0.5,L 0 0.5 0#GM 0 0 0,T 0.5 0.5 0.5,FB " + "0.5 0.5 0,L 0 0.5 0", // 155 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 156 + "GM 0 0 0,A 0 0 0.5,KA 0.666667 -0.333333 0,HA 0.666667 -0.333333 0.5,K " + "0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 0,L 0.5 0 0.5", // 157 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 158 + "GM 0 0 0,A 0 0 0.5,KA 0.666667 -0.333333 0,HA 0.666667 -0.333333 0.5,K " + "0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 0,L 0.5 0 0.5", // 159 + "GM 0 0 0,T 0.5 0.5 -0.5,L 0 0.5 0,FA 0 0.5 -0.5#GM 0 0 0,T 0.5 0.5 -0.5,L 0 " + "0.5 0,FB 0.5 0.5 0", // 160 + "GM 0 0 0,T 0.5 0.5 -0.5,L 0 0.5 0,FA 0 0.5 -0.5#GM 0 0 0,T 0.5 0.5 -0.5,L 0 " + "0.5 0,FB 0.5 0.5 0", // 161 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 162 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 163 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 164 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 165 + "GM 0 0 0,T 0.5 0.5 -0.5,L 0 0.5 0,FA 0 0.5 -0.5#GM 0 0 0,T 0.5 0.5 0.5,L 0 " + "0.5 0,FB 0 0.5 0.5", // 166 + "GM 0 0 0,T 0.5 0.5 -0.5,L 0 0.5 0,FA 0 0.5 -0.5#GM 0 0 0,T 0.5 0.5 0.5,L 0 " + "0.5 0,FB 0 0.5 0.5", // 167 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 168 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 169 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 170 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 171 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 172 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 173 + "GM 0 0 0,A 0 0 0.5,KA 0.666667 -0.333333 0,HA 0.666667 -0.333333 0.5,K " + "0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 0,L 0.5 0 0.5", // 174 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 175 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 176 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 177 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 178 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 179 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 180 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 181 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 182 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 183 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 184 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 185 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 186 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 187 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 188 + "GM 0 0 0,A 0 0 0.5,KA 0.666667 -0.333333 0,HA 0.666667 -0.333333 0.5,K " + "0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 0,L 0.5 0 0.5", // 189 + "GM 0 0 0,A 0 0 0.5,KA 0.666667 -0.333333 0,HA 0.666667 -0.333333 0.5,K " + "0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 0,L 0.5 0 0.5", // 190 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 191 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 192 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 193 + "GM 0 0 0,A 0 0 0.5,K 0.333333 0.333333 0,H 0.333333 0.333333 0.5,M 0.5 0 " + "0,L 0.5 0 0.5", // 194 + "GM 0 0 0,R 0.5 0.5 0.5,M 0.5 0.5 0,X 0 0.5 0", // 195 + "GM 0 0 0,X 0.5 0 0.5,L 0.5 0.5 0.5,W 0.5 0.25 0.75", // 196 + "GM 0 0 0,H 0.5 -0.5 0.5,P 0.25 0.25 0.25,PA -0.25 -0.25 0.75,N 0 0 0.5", // 197 + "GM 0 0 0,R 0.5 0.5 0.5,M 0.5 0.5 0,X 0 0.5 0", // 198 + "GM 0 0 0,H 0.5 -0.5 0.5,P 0.25 0.25 0.25,PA -0.25 -0.25 0.75,N 0 0 0.5", // 199 + "GM 0 0 0,R 0.5 0.5 0.5,M 0.5 0.5 0,X 0 0.5 0", // 200 + "GM 0 0 0,R 0.5 0.5 0.5,M 0.5 0.5 0,X 0 0.5 0", // 201 + "GM 0 0 0,X 0.5 0 0.5,L 0.5 0.5 0.5,W 0.5 0.25 0.75", // 202 + "GM 0 0 0,X 0.5 0 0.5,L 0.5 0.5 0.5,W 0.5 0.25 0.75", // 203 + "GM 0 0 0,H 0.5 -0.5 0.5,P 0.25 0.25 0.25,N 0 0 0.5", // 204 + "GM 0 0 0,R 0.5 0.5 0.5,M 0.5 0.5 0,X 0 0.5 0", // 205 + "GM 0 0 0,H 0.5 -0.5 0.5,P 0.25 0.25 0.25,N 0 0 0.5", // 206 + "GM 0 0 0,R 0.5 0.5 0.5,M 0.5 0.5 0,X 0 0.5 0", // 207 + "GM 0 0 0,R 0.5 0.5 0.5,M 0.5 0.5 0,X 0 0.5 0", // 208 + "GM 0 0 0,X 0.5 0 0.5,L 0.5 0.5 0.5,W 0.5 0.25 0.75", // 209 + "GM 0 0 0,X 0.5 0 0.5,L 0.5 0.5 0.5,W 0.5 0.25 0.75", // 210 + "GM 0 0 0,H 0.5 -0.5 0.5,P 0.25 0.25 0.25,N 0 0 0.5", // 211 + "GM 0 0 0,R 0.5 0.5 0.5,M 0.5 0.5 0,X 0 0.5 0", // 212 + "GM 0 0 0,R 0.5 0.5 0.5,M 0.5 0.5 0,X 0 0.5 0", // 213 + "GM 0 0 0,H 0.5 -0.5 0.5,P 0.25 0.25 0.25,N 0 0 0.5", // 214 + "GM 0 0 0,R 0.5 0.5 0.5,M 0.5 0.5 0,X 0 0.5 0", // 215 + "GM 0 0 0,X 0.5 0 0.5,L 0.5 0.5 0.5,W 0.5 0.25 0.75", // 216 + "GM 0 0 0,H 0.5 -0.5 0.5,P 0.25 0.25 0.25,PA -0.25 -0.25 0.75,N 0 0 0.5", // 217 + "GM 0 0 0,R 0.5 0.5 0.5,M 0.5 0.5 0,X 0 0.5 0", // 218 + "GM 0 0 0,X 0.5 0 0.5,L 0.5 0.5 0.5,W 0.5 0.25 0.75", // 219 + "GM 0 0 0,H 0.5 -0.5 0.5,P 0.25 0.25 0.25,PA -0.25 -0.25 0.75,N 0 0 0.5", // 220 + "GM 0 0 0,R 0.5 0.5 0.5,M 0.5 0.5 0,X 0 0.5 0", // 221 + "GM 0 0 0,R 0.5 0.5 0.5,M 0.5 0.5 0,X 0 0.5 0", // 222 + "GM 0 0 0,R 0.5 0.5 0.5,M 0.5 0.5 0,X 0 0.5 0", // 223 + "GM 0 0 0,R 0.5 0.5 0.5,M 0.5 0.5 0,X 0 0.5 0", // 224 + "GM 0 0 0,X 0.5 0 0.5,L 0.5 0.5 0.5,W 0.5 0.25 0.75", // 225 + "GM 0 0 0,X 0.5 0 0.5,L 0.5 0.5 0.5,W 0.5 0.25 0.75", // 226 + "GM 0 0 0,X 0.5 0 0.5,L 0.5 0.5 0.5,W 0.5 0.25 0.75", // 227 + "GM 0 0 0,X 0.5 0 0.5,L 0.5 0.5 0.5,W 0.5 0.25 0.75", // 228 + "GM 0 0 0,H 0.5 -0.5 0.5,P 0.25 0.25 0.25,N 0 0 0.5", // 229 + "GM 0 0 0,H 0.5 -0.5 0.5,P 0.25 0.25 0.25,N 0 0 0.5" // 230 +}; + +} // namespace QtPlugins +} // namespace Avogadro + +#endif diff --git a/avogadro/qtplugins/yaehmop/yaehmop.cpp b/avogadro/qtplugins/yaehmop/yaehmop.cpp new file mode 100644 index 0000000000..dc05c5ec9c --- /dev/null +++ b/avogadro/qtplugins/yaehmop/yaehmop.cpp @@ -0,0 +1,607 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2018 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "banddialog.h" +#include "specialkpoints.h" +#include "yaehmopout.h" + +#include "yaehmop.h" + +using Avogadro::Vector3; +using Avogadro::Vector3i; +using Avogadro::Core::Array; +using Avogadro::Core::Elements; +using Avogadro::Core::UnitCell; +using Avogadro::QtGui::Molecule; + +namespace Avogadro { +namespace QtPlugins { + +Yaehmop::Yaehmop(QObject* parent_) + : Avogadro::QtGui::ExtensionPlugin(parent_), m_actions(QList()), + m_molecule(nullptr), m_yaehmopSettings(), + m_bandDialog( + new BandDialog(qobject_cast(parent()), m_yaehmopSettings)), + m_displayBandDialogAction(new QAction(this)) +{ + m_displayBandDialogAction->setText(tr("Calculate band structure...")); + connect(m_displayBandDialogAction.get(), &QAction::triggered, this, + &Yaehmop::displayBandDialog); + m_actions.push_back(m_displayBandDialogAction.get()); + m_displayBandDialogAction->setProperty("menu priority", 90); + + updateActions(); + + readSettings(); +} + +Yaehmop::~Yaehmop() = default; + +QList Yaehmop::actions() const +{ + return m_actions; +} + +QStringList Yaehmop::menuPath(QAction*) const +{ + return QStringList() << tr("&Extensions") << tr("&Yaehmop"); +} + +void Yaehmop::setMolecule(QtGui::Molecule* mol) +{ + if (m_molecule == mol) + return; + + if (m_molecule) + m_molecule->disconnect(this); + + m_molecule = mol; + + if (m_molecule) + connect(m_molecule, SIGNAL(changed(uint)), SLOT(moleculeChanged(uint))); + + updateActions(); +} + +void Yaehmop::moleculeChanged(unsigned int c) +{ + Q_ASSERT(m_molecule == qobject_cast(sender())); + + Molecule::MoleculeChanges changes = static_cast(c); + + if (changes & Molecule::UnitCell) { + if (changes & Molecule::Added || changes & Molecule::Removed) + updateActions(); + } +} + +void Yaehmop::updateActions() +{ + // Disable everything for nullptr molecules. + if (!m_molecule) { + foreach (QAction* action, m_actions) + action->setEnabled(false); + return; + } + + // Only display the actions if there is a unit cell + if (m_molecule->unitCell()) { + foreach (QAction* action, m_actions) + action->setEnabled(true); + } else { + foreach (QAction* action, m_actions) + action->setEnabled(false); + } +} + +void Yaehmop::readSettings() +{ + QSettings settings; + m_yaehmopSettings.numBandKPoints = + settings.value("yaehmop/bandOptions/numBandKPoints", 40).toUInt(); + m_yaehmopSettings.displayYaehmopInput = + settings.value("yaehmop/general/displayYaehmopInput", false).toBool(); + m_yaehmopSettings.limitY = + settings.value("yaehmop/general/limitY", false).toBool(); + m_yaehmopSettings.minY = + settings.value("yaehmop/general/minY", 0.0).toDouble(); + m_yaehmopSettings.maxY = + settings.value("yaehmop/general/maxY", 0.0).toDouble(); + m_yaehmopSettings.plotFermi = + settings.value("yaehmop/general/plotFermi", false).toBool(); + m_yaehmopSettings.fermi = + settings.value("yaehmop/general/fermi", 0.0).toDouble(); + m_yaehmopSettings.zeroFermi = + settings.value("yaehmop/general/zeroFermi", false).toBool(); + m_yaehmopSettings.numDim = + settings.value("yaehmop/general/numDim", 3).toUInt(); +} + +void Yaehmop::writeSettings() +{ + QSettings settings; + settings.setValue("yaehmop/bandOptions/numBandKPoints", + m_yaehmopSettings.numBandKPoints); + settings.setValue("yaehmop/general/displayYaehmopInput", + m_yaehmopSettings.displayYaehmopInput); + settings.setValue("yaehmop/general/limitY", m_yaehmopSettings.limitY); + settings.setValue("yaehmop/general/minY", m_yaehmopSettings.minY); + settings.setValue("yaehmop/general/maxY", m_yaehmopSettings.maxY); + settings.setValue("yaehmop/general/plotFermi", m_yaehmopSettings.plotFermi); + settings.setValue("yaehmop/general/fermi", m_yaehmopSettings.fermi); + settings.setValue("yaehmop/general/zeroFermi", m_yaehmopSettings.zeroFermi); + settings.setValue("yaehmop/general/numDim", m_yaehmopSettings.numDim); +} + +void Yaehmop::displayBandDialog() +{ + if (!m_molecule) { + qDebug() << "Error in " << __FUNCTION__ << ": the molecule is not set"; + return; + } + + if (!m_molecule->unitCell()) { + QMessageBox::warning(nullptr, tr("Avogadro2"), + tr("Cannot calculate band structure: no unit cell!")); + qDebug() << "Error in " << __FUNCTION__ << ": there is no unit cell"; + return; + } + + // Generate the special k points before displaying the dialog + m_yaehmopSettings.specialKPoints = + SpecialKPoints::getSpecialKPoints(*m_molecule); + + if (m_yaehmopSettings.specialKPoints.isEmpty()) + m_yaehmopSettings.specialKPoints = YAEHMOP_DEFAULT_SPECIAL_KPOINTS; + + // Do nothing if the user cancels + if (m_bandDialog->exec() != QDialog::Accepted) + return; + + // Save the settings for future use + writeSettings(); + + calculateBandStructure(); +} + +// Get the distance between two k points +double Yaehmop::kpointDistance(const Vector3& a, const Vector3& b) +{ + if (!m_molecule) { + qDebug() << "Error in" << __FUNCTION__ << ": the molecule is not set"; + return -1.0; + } + + UnitCell* cell = m_molecule->unitCell(); + if (!cell) { + qDebug() << "Error in " << __FUNCTION__ << ": there is no unit cell"; + return -1.0; + } + + // We need to find the reciprocal space basis vectors, and we + // need to find the actual k point location in reciprocal space. + const Vector3& aVec = cell->aVector(); + const Vector3& bVec = cell->bVector(); + const Vector3& cVec = cell->cVector(); + + Vector3 b1 = bVec.cross(cVec); + Vector3 b2 = cVec.cross(aVec); + Vector3 b3 = aVec.cross(bVec); + + // This is how VASP does it. + // If it's good enough for VASP, it's good enough for me! + double omega = aVec[0] * b1[0] + aVec[1] * b1[1] + aVec[2] * b1[2]; + + b1 /= omega; + b2 /= omega; + b3 /= omega; + + // Calculate the reciprocal points + const Vector3& recA(a[0] * b1 + a[1] * b2 + a[2] * b3); + const Vector3& recB(b[0] * b1 + b[1] * b2 + b[2] * b3); + return (recA - recB).norm(); +} + +void Yaehmop::calculateBandStructure() +{ + // First, create the input + QString input; + input += "Title\n"; // Title + input += createGeometryAndLatticeInput(); + + // Here we describe the number of k points connecting each special + // k point, the number of special k points, and their locations + // in reciprocal space. This is something we will let the user change + input += "Band\n"; + + // This is the number of kpoints connecting each special k point + input += (QString::number(m_yaehmopSettings.numBandKPoints) + "\n"); + + // Num special k points + int numSK = m_yaehmopSettings.specialKPoints + .split(QRegExp("[\r\n]"), QString::SkipEmptyParts) + .size(); + input += (QString::number(numSK) + "\n"); // num special k points + + // Add the whole string from user input + input += m_yaehmopSettings.specialKPoints; + + // Perform the yaehmop calculation + QByteArray output; + QString err; + if (!executeYaehmop(input.toLocal8Bit(), output, err)) { + QMessageBox::warning( + nullptr, tr("Avogadro2"), + tr("Yaehmop execution failed with the following error:\n") + err); + qDebug() << "Yaehmop execution failed with the following error:\n" << err; + return; + } + + // Now, read the output + QVector> bands; + QVector kpoints; + QVector specialKPoints; + if (!YaehmopOut::readBandData(output, bands, kpoints, specialKPoints)) { + QString message = tr("Failed to read band structure output from Yaehmop!"); + QMessageBox::warning(nullptr, tr("Avogadro2"), message); + qDebug() << message; + } + + int numKPoints = kpoints.size(); + int numOrbitals = bands.size(); + int numSpecialKPoints = specialKPoints.size(); + + // If there is only one special k point, there is nothing to graph. Just + // return. + if (numSpecialKPoints <= 1) { + QString message = + tr("Only one special k point was found in Yaehmop output! Two or more " + "are required!"); + QMessageBox::warning(nullptr, tr("Avogadro2"), message); + qDebug() << message; + return; + } + + // Calculate the k-space distances + std::vector xVals{ 0.0 }; + for (int i = 1; i < numKPoints; ++i) + xVals.push_back(kpointDistance(kpoints[i - 1], kpoints[i]) + xVals.back()); + + // Calculate the special k point distances + std::vector specialKPointVals{ 0.0 }; + for (int i = 1; i < numSpecialKPoints; ++i) { + specialKPointVals.push_back( + kpointDistance(specialKPoints[i - 1].coords, specialKPoints[i].coords) + + specialKPointVals.back()); + } + + // This is to make sure vtk shows the symbols on the far left and right + specialKPointVals.front() += 0.0001; + specialKPointVals.back() -= 0.0001; + + // Make a vector of labels for the special k points + std::vector specialKPointLabels; + for (int i = 0; i < numSpecialKPoints; ++i) { + std::string label = specialKPoints[i].label.toStdString(); + specialKPointLabels.push_back(label); + } + + // Now generate a plot with the data + std::vector> data; + data.push_back(xVals); + + using VtkPlot = VTK::VtkPlot; + + // Make some labels + std::vector lineLabels; + + // Set the color + std::array color = { 255, 0, 0, 255 }; + std::vector> lineColors; + + // Set the line styles. Most should be solid + VtkPlot::LineStyle style = VtkPlot::LineStyle::solidLine; + std::vector lineStyles; + + size_t curBandNum = 1; + for (const auto& band : bands) { + data.push_back(band.toStdVector()); + lineLabels.push_back("Band " + std::to_string(curBandNum)); + lineColors.push_back(color); + lineStyles.push_back(style); + ++curBandNum; + } + + // Should we plot the fermi level? + if (m_yaehmopSettings.plotFermi) { + // Adjust all the energies if we are to zero the fermi level + double fermi = m_yaehmopSettings.fermi; + if (m_yaehmopSettings.zeroFermi) { + // Skip the first vector because that is the x values + for (size_t i = 1; i < data.size(); ++i) { + for (auto& datum : data[i]) + datum -= fermi; + } + // Fermi is now zero + fermi = 0.0; + } + + // Create a horizontal, black, dashed line for the fermi level + lineLabels.push_back("Fermi Level"); + lineColors.push_back({ 0, 0, 0, 255 }); + lineStyles.push_back(VtkPlot::LineStyle::dashLine); + + std::vector fermiVals(xVals.size(), fermi); + data.push_back(std::move(fermiVals)); + } + + const char* xTitle = ""; + const char* yTitle = "Energy (eV)"; + const char* windowName = "YAeHMOP Band Structure"; + + m_bandPlot.reset(new VtkPlot); + m_bandPlot->setData(data); + m_bandPlot->setWindowName(windowName); + m_bandPlot->setXTitle(xTitle); + m_bandPlot->setYTitle(yTitle); + m_bandPlot->setLineLabels(lineLabels); + m_bandPlot->setLineColors(lineColors); + m_bandPlot->setLineStyles(lineStyles); + m_bandPlot->setCustomTickLabels(VtkPlot::Axis::xAxis, specialKPointVals, + specialKPointLabels); + + // It makes more sense to stop the x axis exactly at its limits + m_bandPlot->setAxisLimits(VtkPlot::Axis::xAxis, xVals.front(), xVals.back()); + + if (m_yaehmopSettings.limitY) { + m_bandPlot->setAxisLimits(VtkPlot::Axis::yAxis, m_yaehmopSettings.minY, + m_yaehmopSettings.maxY); + } + + m_bandPlot->show(); + + // Show the yaehmop input if we are to do so + if (m_yaehmopSettings.displayYaehmopInput) + showYaehmopInput(input); +} + +QString Yaehmop::createGeometryAndLatticeInput() const +{ + if (!m_molecule) { + qDebug() << "Error in " << __FUNCTION__ << ": the molecule is not set"; + return ""; + } + + UnitCell* cell = m_molecule->unitCell(); + if (!cell) { + QMessageBox::warning(nullptr, tr("Avogadro2"), + tr("Cannot calculate band structure: no unit cell!")); + qDebug() << "Error in " << __FUNCTION__ << ": there is no unit cell"; + return ""; + } + + const Array& atomicNumbers = m_molecule->atomicNumbers(); + const Array& atomicPositions = m_molecule->atomPositions3d(); + + // This is the minimum number we allow doubles. If a number's float + // absolute value is smaller than this, we will round it to 0. + double minNum = 1e-8; + + QString input; + input += "Geometry\n"; // Begin geometry section + int numAtoms = atomicNumbers.size(); + // Num atoms plus (numDimensions + 1) dummies. + // Dummies are for defining the lattice + unsigned short numDim = m_yaehmopSettings.numDim; + input += (QString::number(numAtoms + numDim + 1) + QString("\n")); + + // Now loop through atom positions and add them + for (int i = 0; i < numAtoms; ++i) { + QString symbol = Elements::symbol(atomicNumbers[i]); + const Vector3& pos = atomicPositions[i]; + input += (QString::number(i + 1) + " "); + input += (symbol + " "); + for (size_t j = 0; j < 3; ++j) + // If the position is small, just use 0 + input += (QString::number((fabs(pos[j]) > 1e-8 ? pos[j] : 0)) + " "); + input += "\n"; + } + + // Get the cell matrix + const Matrix3& cellMatrix = cell->cellMatrix(); + + // Add the dummy atoms - these tell the program where the lattice is + for (unsigned short i = 0; i <= numDim; ++i) { + input += (QString::number(numAtoms + i + 1) + " "); + // Symbol for dummy atoms + input += "& "; + // First dummy is at 0,0,0, the other dummies are at the ends of the + // lattice + if (i == 0) { + input += "0 0 0\n"; + } else { + // We only get here if i > 0. + // i - 1 is equal to the index of the vector we are looking at. + for (unsigned short j = 0; j < 3; ++j) { + double val = cellMatrix(i - 1, j); + if (fabs(val) < minNum) + val = 0.0; + input += (QString::number(val) + " "); + } + input += "\n"; + } + } + + // Let's calculate the number of overlaps to use + // The manual says that numOverlaps * latticeVecLength should be between + // 10 and 20 Angstroms. Let's always use a numOverlaps of at least 3 and + // then use more if numOverlaps * latticeVecLength < 20. + Vector3i overlaps(3, 3, 3); + Vector3 latticeLengths(cell->a(), cell->b(), cell->c()); + + for (unsigned short i = 0; i < 3; ++i) { + while (overlaps[i] * latticeLengths[i] < 20) + ++overlaps[i]; + } + + // Lattice section to define the lattice + input += "lattice\n"; + input += QString::number(numDim) + "\n"; + // Add numbers of overlaps + for (size_t i = 0; i < numDim; ++i) + input += (QString::number(overlaps[i]) + " "); + input += "\n"; + // If we have "4 5" here, that means the vector is defined + // from atom 4 to atom 5. We use dummy atoms for this. The first dummy + // atom (numAtoms + 1) is always at the origin, and the other dummy atoms + // are at the ends of the a, b, and c axes. + for (size_t i = 0; i < numDim; ++i) { + input += (QString::number(numAtoms + 1) + " " + + QString::number(numAtoms + i + 2) + "\n"); + } + + return input; +} + +// Uncomment this for executeYaehmop debugging +//#define AVOGADRO_YAEHMOP_EXECUTE_DEBUG + +bool Yaehmop::executeYaehmop(const QByteArray& input, QByteArray& output, + QString& err) +{ +#ifdef AVOGADRO_YAEHMOP_EXECUTE_DEBUG + qDebug() << "executeYaehmop() input is:\n" << qPrintable(input); +#endif + + QString program; + // If the YAEHMOP_EXECUTABLE environment variable is set, then + // use that + QByteArray yaehmopExec = qgetenv("YAEHMOP_EXECUTABLE"); + if (!yaehmopExec.isEmpty()) { + program = yaehmopExec; + } else { +// Otherwise, search in the current directory, and then ../bin +#ifdef _WIN32 + QString executable = "yaehmop.exe"; +#else + QString executable = "yaehmop"; +#endif + QString path = QCoreApplication::applicationDirPath(); + if (QFile::exists(path + "/" + executable)) + program = path + "/" + executable; + else if (QFile::exists(path + "/../bin/" + executable)) + program = path + "/../bin/" + executable; + else { + err = tr("Error: could not find yaehmop executable!"); + qDebug() << err; + return false; + } + } + + QStringList args; + args << "--use_stdin_stdout"; + + QProcess p; + p.start(program, args); + + if (!p.waitForStarted()) { + err = tr("Error: " + program.toLocal8Bit() + " failed to start"); + qDebug() << err; + return false; + } + + // Give it the input! + p.write(input.data()); + + // Close the write channel + p.closeWriteChannel(); + + if (!p.waitForFinished()) { + err = tr("Error: " + program.toLocal8Bit() + " failed to finish"); + qDebug() << err; + output = p.readAll(); + qDebug() << "Output is as follows:\n" << qPrintable(output); + return false; + } + + int exitStatus = p.exitStatus(); + output = p.readAll(); + + if (exitStatus == QProcess::CrashExit) { + err = tr("Error: " + program.toLocal8Bit() + " crashed!"); + qDebug() << err; + qDebug() << "Output is as follows:\n" << qPrintable(output); + return false; + } + + if (exitStatus != QProcess::NormalExit) { + err = tr("Error: " + program.toLocal8Bit() + + " finished abnormally with exit code " + + QString::number(exitStatus).toLocal8Bit()); + qDebug() << err; + qDebug() << "Output is as follows:\n" << qPrintable(output); + return false; + } + +#ifdef AVOGADRO_YAEHMOP_EXECUTE_DEBUG + qDebug() << "executeYaehmop() output is:\n" << qPrintable(output); +#endif + + // We did it! + return true; +} + +void Yaehmop::showYaehmopInput(const QString& input) +{ + QDialog* dialog = new QDialog; + + // Make sure this gets deleted upon closing + dialog->setAttribute(Qt::WA_DeleteOnClose); + + QVBoxLayout* layout = new QVBoxLayout(dialog); + dialog->setLayout(layout); + dialog->setWindowTitle(tr("Yaehmop Input")); + QTextEdit* edit = new QTextEdit(dialog); + layout->addWidget(edit); + dialog->resize(500, 500); + + edit->setText(input); + + dialog->show(); +} + +} // namespace QtPlugins +} // namespace Avogadro diff --git a/avogadro/qtplugins/yaehmop/yaehmop.h b/avogadro/qtplugins/yaehmop/yaehmop.h new file mode 100644 index 0000000000..421fdfb151 --- /dev/null +++ b/avogadro/qtplugins/yaehmop/yaehmop.h @@ -0,0 +1,105 @@ +/******************************************************************************* + + This source file is part of the Avogadro project. + + Copyright 2018 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*******************************************************************************/ + +#ifndef AVOGADRO_QTPLUGINS_YAEHMOP_H +#define AVOGADRO_QTPLUGINS_YAEHMOP_H + +#include + +#include + +#include + +#include "yaehmopsettings.h" + +// Forward declarations +class QByteArray; +class QStringList; + +namespace VTK { +class VtkPlot; +} + +namespace Avogadro { +namespace QtPlugins { + +class BandDialog; + +/** + * @brief Perform extended Hückel calculations with yaehmop. + */ +class Yaehmop : public Avogadro::QtGui::ExtensionPlugin +{ + Q_OBJECT +public: + explicit Yaehmop(QObject* parent_ = 0); + ~Yaehmop(); + + QString name() const { return tr("Yaehmop"); } + QString description() const; + QList actions() const; + QStringList menuPath(QAction*) const; + +public slots: + void setMolecule(QtGui::Molecule* mol); + + void moleculeChanged(unsigned int changes); + +private slots: + void updateActions(); + + void displayBandDialog(); + +private: + void readSettings(); + void writeSettings(); + + // This pops up a dialog box with the yaehmop input inside + void showYaehmopInput(const QString& input); + + // Get the distance between two k points + double kpointDistance(const Avogadro::Vector3& a, const Avogadro::Vector3& b); + + void calculateBandStructure(); + + QString createGeometryAndLatticeInput() const; + + // Use QProcess to execute yaehmop + // If the YAEHMOP_EXECUTABLE environment variable is set, that will be + // used for the executable. Otherwise, it will search for the executable in + // some common places and use it if it can be found. + static bool executeYaehmop(const QByteArray& input, QByteArray& output, + QString& err); + + QList m_actions; + QtGui::Molecule* m_molecule; + + YaehmopSettings m_yaehmopSettings; + + std::unique_ptr m_bandDialog; + std::unique_ptr m_displayBandDialogAction; + std::unique_ptr m_bandPlot; +}; + +inline QString Yaehmop::description() const +{ + return tr("Perform extended Hückel calculations with yaehmop."); +} + +} // namespace QtPlugins +} // namespace Avogadro + +#endif // AVOGADRO_QTPLUGINS_YAEHMOPEXTENSION_H diff --git a/avogadro/qtplugins/yaehmop/yaehmopout.cpp b/avogadro/qtplugins/yaehmop/yaehmopout.cpp new file mode 100644 index 0000000000..3a867f1abb --- /dev/null +++ b/avogadro/qtplugins/yaehmop/yaehmopout.cpp @@ -0,0 +1,146 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2018 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#include +#include +#include + +#include + +#include "yaehmopout.h" + +namespace Avogadro { +namespace QtPlugins { + +inline bool printAndReturnFalse(const QString& error) +{ + qDebug() << "Error in YaehmopOut:" << error; + return false; +} + +bool YaehmopOut::readBandData(const QString& data, + QVector>& bands, + QVector& kpoints, + QVector& specialKPoints) +{ + bands.clear(); + kpoints.clear(); + specialKPoints.clear(); + + QStringList lines = data.split(QRegExp("[\r\n]"), QString::SkipEmptyParts); + + while (!lines.isEmpty() && !lines[0].contains("#BAND_DATA")) + lines.removeFirst(); + + if (lines.isEmpty()) + return printAndReturnFalse("Band Data not found in readBandData()!"); + + // These get printed from the status file and are not needed... + foreach (const QString& line, lines) { + if (line.contains("Error value from Diagonalization")) + lines.removeOne(line); + } + + // Right here, lines.size() must be at least 8 + if (lines.size() < 8) + return printAndReturnFalse("Band data is too few lines!"); + + long long ind = 2; + if (!lines[ind].contains("Special points")) + return printAndReturnFalse("Special points missing"); + int numSpecialPoints = lines[ind].split(" ")[0].toInt(); + + // Now we know more details about how many lines should be here + if (lines.size() < 7 + numSpecialPoints) + return printAndReturnFalse("Too few lines of data in band data!"); + + ++ind; + if (!lines[ind].contains("k points")) + return printAndReturnFalse("k points missing"); + size_t numKPoints = lines[ind].split(" ")[0].toInt(); + + ++ind; + if (!lines[ind].contains("orbitals in")) + return printAndReturnFalse("orbitals in missing"); + ; + size_t numOrbitals = lines[ind].split(" ")[0].toInt(); + + for (int i = 0; i < numSpecialPoints; ++i) { + ++ind; + specialKPoint kp; + if (lines[ind].split(" ").size() < 4) + return printAndReturnFalse("Special points line too small"); + + kp.label = lines[ind].split(" ")[0]; + // If the label is "GM", use "Γ" instead + // FIXME: our vtk can't currently display a unicode gamma like this. When + // we add a font that can, we can uncomment this. +// if (kp.label.toLower() == "gm") +// kp.label = QString::fromUtf8("Γ"); + kp.coords = Vector3(lines[ind].split(" ")[1].toDouble(), + lines[ind].split(" ")[2].toDouble(), + lines[ind].split(" ")[3].toDouble()); + specialKPoints.append(kp); + } + + ++ind; + if (!lines[ind].contains("Begin band data")) + return printAndReturnFalse("Begin band data missing"); + + // This should be equal in size to the number of orbitals + bands.reserve(numOrbitals); + for (size_t i = 0; i < numOrbitals; ++i) { + bands.append(QVector()); + // This is how many points we should have in total + bands[i].reserve(numKPoints * (numSpecialPoints - 1) + 1); + } + // This is how many points we should have in total + kpoints.reserve(numKPoints * (numSpecialPoints - 1) + 1); + + ++ind; + while (true) { + // Did we make it to the end without finishing the band data? + if (ind >= lines.size()) + return printAndReturnFalse("END_BAND_DATA is missing!"); + + // Did we make it to the end? + if (lines[ind].contains("END_BAND_DATA")) + break; + + // Read the k-point info + if (!lines[ind].contains("K point") || lines[ind].split(" ").size() < 6) { + return printAndReturnFalse("K point missing"); + } + + Vector3 kp = Vector3(lines[ind].split(" ")[3].toDouble(), + lines[ind].split(" ")[4].toDouble(), + lines[ind].split(" ")[5].toDouble()); + kpoints.append(kp); + + // Get the orbital energies + for (size_t j = 0; j < numOrbitals; ++j) { + ++ind; + bands[j].append(lines[ind].trimmed().toDouble()); + } + ++ind; + } + + // We made it! + return true; +} + +} // namespace QtPlugins +} // namespace Avogadro diff --git a/avogadro/qtplugins/yaehmop/yaehmopout.h b/avogadro/qtplugins/yaehmop/yaehmopout.h new file mode 100644 index 0000000000..8dfa0285d2 --- /dev/null +++ b/avogadro/qtplugins/yaehmop/yaehmopout.h @@ -0,0 +1,51 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2018 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#ifndef AVOGADRO_QTPLUGINS_YAEHMOP_OUT_H +#define AVOGADRO_QTPLUGINS_YAEHMOP_OUT_H + +#include +#include + +#include + +namespace Avogadro { +namespace QtPlugins { + +typedef struct +{ + QString label; + Vector3 coords; +} specialKPoint; + +// Static class for Yaehmop output +class YaehmopOut +{ +public: + // Pass the yaehmop output in as 'data'. It would be faster if this only + // included the section from BAND_DATA to END_BAND_DATA, but it is not + // necessary. This sets bands, kpoints, and specialKPoints to be the + // bands, the kpoints, and the special k points. Returns true if the + // read was successful, and false if the read failed + static bool readBandData(const QString& data, QVector>& bands, + QVector& kpoints, + QVector& specialKPoints); +}; + +} // namespace QtPlugins +} // namespace Avogadro + +#endif // AVOGADRO_QTPLUGINS_YAEHMOPOUT_H diff --git a/avogadro/qtplugins/yaehmop/yaehmopsettings.h b/avogadro/qtplugins/yaehmop/yaehmopsettings.h new file mode 100644 index 0000000000..92545db573 --- /dev/null +++ b/avogadro/qtplugins/yaehmop/yaehmopsettings.h @@ -0,0 +1,48 @@ +/****************************************************************************** + + This source file is part of the Avogadro project. + + Copyright 2018 Kitware, Inc. + + This source code is released under the New BSD License, (the "License"). + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************/ + +#ifndef AVOGADRO_QTPLUGINS_YAEHMOPSETTINGS_H +#define AVOGADRO_QTPLUGINS_YAEHMOPSETTINGS_H + +#include + +namespace Avogadro { +namespace QtPlugins { + +static const char* YAEHMOP_DEFAULT_SPECIAL_KPOINTS = "GM 0 0 0"; + +struct YaehmopSettings +{ + YaehmopSettings() + : numBandKPoints(40), specialKPoints(YAEHMOP_DEFAULT_SPECIAL_KPOINTS), + displayYaehmopInput(false), limitY(false), minY(0.0), maxY(0.0), + plotFermi(false), fermi(0.0), zeroFermi(false), numDim(3){}; + + unsigned long long numBandKPoints; + QString specialKPoints; + bool displayYaehmopInput; + bool limitY; + double minY; + double maxY; + bool plotFermi; + double fermi; + bool zeroFermi; + unsigned short numDim; +}; + +} // namespace QtPlugins +} // namespace Avogadro +#endif // AVOGADRO_QTPLUGINS_YAEHMOPSETTINGS_H diff --git a/avogadro/vtk/vtkplot.cpp b/avogadro/vtk/vtkplot.cpp index 496b780fff..c76a5bf6cb 100644 --- a/avogadro/vtk/vtkplot.cpp +++ b/avogadro/vtk/vtkplot.cpp @@ -21,19 +21,21 @@ #include #include #include +#include #include #include #include +#include #include #include #include +#include #include #include +#include #include -#include - #include "vtkplot.h" using std::array; @@ -126,6 +128,59 @@ void VtkPlot::setYTitle(const char* yTitle) leftAxis->SetTitle(yTitle); } +void VtkPlot::setCustomTickLabels(Axis _axis, + const vector& customTickPositions, + const vector& customTickLabels) +{ + vtkAxis* axis = getAxis(_axis); + if (!axis) { + std::cerr << "Error in " << __FUNCTION__ << ": invalid axis\n"; + return; + } + + // These must be equal in size + if (customTickPositions.size() != customTickLabels.size()) { + std::cerr << "Error in " << __FUNCTION__ << ": custom tick labels " + << "must be equal in size to custom tick positions!\n"; + return; + } + + vtkNew doubleArray; + doubleArray->SetName("Custom Tick Positions"); + for (const auto& pos : customTickPositions) + doubleArray->InsertNextValue(pos); + + vtkNew stringArray; + stringArray->SetName("Custom Tick Labels"); + + for (const auto& label : customTickLabels) + stringArray->InsertNextValue(label); + + axis->SetCustomTickPositions(doubleArray, stringArray); +} + +static int convertLineStyleEnum(VTK::VtkPlot::LineStyle style) +{ + using LineStyle = VTK::VtkPlot::LineStyle; + + if (style == LineStyle::noLine) + return vtkPen::NO_PEN; + else if (style == LineStyle::solidLine) + return vtkPen::SOLID_LINE; + else if (style == LineStyle::dashLine) + return vtkPen::DASH_LINE; + else if (style == LineStyle::dotLine) + return vtkPen::DOT_LINE; + else if (style == LineStyle::dashDotLine) + return vtkPen::DASH_DOT_LINE; + else if (style == LineStyle::dashDotDotLine) + return vtkPen::DASH_DOT_DOT_LINE; + + std::cerr << "Error in " << __FUNCTION__ << ": unknown line style.\n"; + std::cerr << "Defaulting to solid line.\n"; + return vtkPen::SOLID_LINE; +} + void VtkPlot::show() { // First, clear all previous plots @@ -146,11 +201,40 @@ void VtkPlot::show() m_lineColors[i - 1][2], m_lineColors[i - 1][3]); } + // If we have a line style for this line, set it + if (i <= m_lineStyles.size() && line->GetPen()) + line->GetPen()->SetLineType(convertLineStyleEnum(m_lineStyles[i - 1])); + line->SetWidth(2.0); } m_widget->show(); } +void VtkPlot::setAxisLimits(Axis _axis, double min, double max) +{ + vtkAxis* axis = getAxis(_axis); + if (!axis) { + std::cerr << "Error in " << __FUNCTION__ << ": invalid axis\n"; + return; + } + + axis->SetMinimumLimit(min); + axis->SetMaximumLimit(max); +} + +vtkAxis* VtkPlot::getAxis(Axis axis) +{ + if (axis == Axis::xAxis) { + return m_chart->GetAxis(vtkAxis::BOTTOM); + } else if (axis == Axis::yAxis) { + return m_chart->GetAxis(vtkAxis::LEFT); + } + + // If we get here, there is an error... + std::cerr << "Error in " << __FUNCTION__ << ": unknown axis\n"; + return nullptr; +} + } // namespace VTK } // namespace Avogadro diff --git a/avogadro/vtk/vtkplot.h b/avogadro/vtk/vtkplot.h index 916f1b2196..ef2150ac4d 100644 --- a/avogadro/vtk/vtkplot.h +++ b/avogadro/vtk/vtkplot.h @@ -27,6 +27,7 @@ #include class QVTKOpenGLWidget; +class vtkAxis; class vtkChartXY; class vtkContextView; class vtkGenericOpenGLRenderWindow; @@ -44,6 +45,24 @@ class AVOGADROVTK_EXPORT VtkPlot explicit VtkPlot(); ~VtkPlot(); + // Enum for the different axes + enum class Axis + { + xAxis, + yAxis + }; + + // Enum for the different line styles + enum class LineStyle + { + noLine, + solidLine, + dashLine, + dotLine, + dashDotLine, + dashDotDotLine + }; + // data[0] is the x data, and data[i] for i != 0 is the y data for the // line i != 0. void setData(const std::vector>& data); @@ -61,9 +80,25 @@ class AVOGADROVTK_EXPORT VtkPlot { m_lineColors = colors; } + void setLineStyles(const std::vector& styles) + { + m_lineStyles = styles; + } + void show(); + // customTickPositions must be equal in size to customTickLabels + void setCustomTickLabels(Axis axis, + const std::vector& customTickPositions, + const std::vector& customTickLabels); + + // Set the limits for a particular axis + void setAxisLimits(Axis axis, double min, double max); + private: + // Get a pointer to a particular axis. Returns nullptr if invalid. + vtkAxis* getAxis(Axis axis); + std::unique_ptr m_widget; vtkNew m_table; vtkNew m_renderWindow; @@ -71,6 +106,7 @@ class AVOGADROVTK_EXPORT VtkPlot vtkNew m_chart; std::vector m_lineLabels; std::vector> m_lineColors; + std::vector m_lineStyles; }; } // namespace VTK