Verified Commit 2dd6d692 authored by Tobias WEBER's avatar Tobias WEBER
Browse files

bz tool: started with formulas

parent 2996bb83
......@@ -72,6 +72,7 @@ add_executable(takin_bz
bz.cpp bz_file.cpp bz_calc.cpp
bz_plot.cpp bz_main.cpp
bz_ops.cpp bz.h globals.h
bz_formulas.cpp
plot_cut.cpp plot_cut.h
../../tlibs2/libs/qt/recent.cpp ../../tlibs2/libs/qt/recent.h
../../tlibs2/libs/qt/gl.cpp ../../tlibs2/libs/qt/gl.h
......
......@@ -71,7 +71,7 @@ BZDlg::BZDlg(QWidget* pParent) : QDialog{pParent},
fontMetrics().lineSpacing()*4 + 4);
m_symops->verticalHeader()->setVisible(false);
m_symops->setAlternatingRowColors(true);
m_symops->setColumnCount(NUM_COLS);
m_symops->setColumnCount(NUM_SYMOP_COLS);
m_symops->setHorizontalHeaderItem(COL_OP,
new QTableWidgetItem{"Symmetry Operation"});
m_symops->setHorizontalHeaderItem(COL_PROP,
......@@ -147,34 +147,32 @@ BZDlg::BZDlg(QWidget* pParent) : QDialog{pParent},
// table CustomContextMenu
m_tabContextMenu = new QMenu(m_symops);
m_tabContextMenu->addAction("Add SymOp Before", this, [this]() { this->AddTabItem(-2); });
m_tabContextMenu->addAction("Add SymOp After", this, [this]() { this->AddTabItem(-3); });
m_tabContextMenu->addAction("Clone SymOp", this, [this]() { this->AddTabItem(-4); });
m_tabContextMenu->addAction("Delete SymOp", this, [this]() { BZDlg::DelTabItem(); });
m_symOpContextMenu = new QMenu(m_symops);
m_symOpContextMenu->addAction("Add SymOp Before", this, [this]() { this->AddSymOpTabItem(-2); });
m_symOpContextMenu->addAction("Add SymOp After", this, [this]() { this->AddSymOpTabItem(-3); });
m_symOpContextMenu->addAction("Clone SymOp", this, [this]() { this->AddSymOpTabItem(-4); });
m_symOpContextMenu->addAction("Delete SymOp", this, [this]() { BZDlg::DelSymOpTabItem(); });
// table CustomContextMenu in case nothing is selected
m_tabContextMenuNoItem = new QMenu(m_symops);
m_tabContextMenuNoItem->addAction("Add SymOp", this, [this]() { this->AddTabItem(); });
m_tabContextMenuNoItem->addAction("Delete SymOp", this, [this]() { BZDlg::DelTabItem(); });
//m_tabContextMenuNoItem->addSeparator();
m_symOpContextMenuNoItem = new QMenu(m_symops);
m_symOpContextMenuNoItem->addAction("Add SymOp", this, [this]() { this->AddSymOpTabItem(); });
m_symOpContextMenuNoItem->addAction("Delete SymOp", this, [this]() { BZDlg::DelSymOpTabItem(); });
//m_symOpContextMenuNoItem->addSeparator();
// signals
for(auto* edit : std::vector<QLineEdit*>{{ m_editA, m_editB, m_editC, m_editAlpha, m_editBeta, m_editGamma }})
connect(edit, &QLineEdit::textEdited, this, [this]() { this->CalcB(); });
connect(btnAdd, &QToolButton::clicked, this, [this]() { this->AddTabItem(-1); });
connect(btnDel, &QToolButton::clicked, this, [this]() { BZDlg::DelTabItem(); });
connect(btnUp, &QToolButton::clicked, this, &BZDlg::MoveTabItemUp);
connect(btnDown, &QToolButton::clicked, this, &BZDlg::MoveTabItemDown);
connect(btnAdd, &QToolButton::clicked, this, [this]() { this->AddSymOpTabItem(-1); });
connect(btnDel, &QToolButton::clicked, this, [this]() { BZDlg::DelSymOpTabItem(); });
connect(btnUp, &QToolButton::clicked, this, &BZDlg::MoveSymOpTabItemUp);
connect(btnDown, &QToolButton::clicked, this, &BZDlg::MoveSymOpTabItemDown);
connect(btnSG, &QPushButton::clicked, this, &BZDlg::GetSymOpsFromSG);
connect(m_symops, &QTableWidget::currentCellChanged, this, &BZDlg::TableCurCellChanged);
connect(m_symops, &QTableWidget::entered, this, &BZDlg::TableCellEntered);
connect(m_symops, &QTableWidget::itemChanged, this, &BZDlg::TableItemChanged);
connect(m_symops, &QTableWidget::customContextMenuRequested, this, &BZDlg::ShowTableContextMenu);
connect(m_symops, &QTableWidget::itemChanged, this, &BZDlg::SymOpTableItemChanged);
connect(m_symops, &QTableWidget::customContextMenuRequested, this, &BZDlg::ShowSymOpTableContextMenu);
tabs->addTab(symopspanel, "Crystal");
}
......@@ -257,6 +255,75 @@ BZDlg::BZDlg(QWidget* pParent) : QDialog{pParent},
}
{ // formulas panel
QWidget *formulaspanel = new QWidget(this);
m_formulas = new QTableWidget(formulaspanel);
m_formulas->setShowGrid(true);
m_formulas->setSortingEnabled(true);
m_formulas->setMouseTracking(true);
m_formulas->setSelectionBehavior(QTableWidget::SelectRows);
m_formulas->setSelectionMode(QTableWidget::ContiguousSelection);
m_formulas->setContextMenuPolicy(Qt::CustomContextMenu);
m_formulas->verticalHeader()->setVisible(false);
m_formulas->setAlternatingRowColors(true);
m_formulas->setColumnCount(NUM_FORMULAS_COLS);
m_formulas->setHorizontalHeaderItem(COL_FORMULA, new QTableWidgetItem{"Formula to Plot"});
m_formulas->setColumnWidth(COL_FORMULA, 500);
QToolButton *btnAdd = new QToolButton(formulaspanel);
QToolButton *btnDel = new QToolButton(formulaspanel);
QToolButton *btnUp = new QToolButton(formulaspanel);
QToolButton *btnDown = new QToolButton(formulaspanel);
m_formulas->setSizePolicy(QSizePolicy{QSizePolicy::Expanding, QSizePolicy::Expanding});
btnAdd->setSizePolicy(QSizePolicy{QSizePolicy::Expanding, QSizePolicy::Fixed});
btnDel->setSizePolicy(QSizePolicy{QSizePolicy::Expanding, QSizePolicy::Fixed});
btnUp->setSizePolicy(QSizePolicy{QSizePolicy::Expanding, QSizePolicy::Fixed});
btnDown->setSizePolicy(QSizePolicy{QSizePolicy::Expanding, QSizePolicy::Fixed});
btnAdd->setText("Add Formula");
btnDel->setText("Delete Formula");
btnUp->setText("Move Formula Up");
btnDown->setText("Move Formula Down");
auto tabGrid = new QGridLayout(formulaspanel);
tabGrid->setSpacing(2);
tabGrid->setContentsMargins(4,4,4,4);
int y=0;
tabGrid->addWidget(m_formulas, y,0,1,4);
tabGrid->addWidget(btnAdd, ++y,0,1,1);
tabGrid->addWidget(btnDel, y,1,1,1);
tabGrid->addWidget(btnUp, y,2,1,1);
tabGrid->addWidget(btnDown, y,3,1,1);
// table CustomContextMenu
m_formulasContextMenu = new QMenu(m_formulas);
m_formulasContextMenu->addAction("Add Formula Before", this, [this]() { this->AddFormulaTabItem(-2); });
m_formulasContextMenu->addAction("Add Formula After", this, [this]() { this->AddFormulaTabItem(-3); });
m_formulasContextMenu->addAction("Clone Formula", this, [this]() { this->AddFormulaTabItem(-4); });
m_formulasContextMenu->addAction("Delete Formula", this, [this]() { BZDlg::DelFormulaTabItem(); });
// table CustomContextMenu in case nothing is selected
m_formulasContextMenuNoItem = new QMenu(m_formulas);
m_formulasContextMenuNoItem->addAction("Add Formula", this, [this]() { this->AddFormulaTabItem(); });
m_formulasContextMenuNoItem->addAction("Delete Formula", this, [this]() { BZDlg::DelFormulaTabItem(); });
// signals
connect(btnAdd, &QToolButton::clicked, this, [this]() { this->AddFormulaTabItem(-1); });
connect(btnDel, &QToolButton::clicked, this, [this]() { BZDlg::DelFormulaTabItem(); });
connect(btnUp, &QToolButton::clicked, this, &BZDlg::MoveFormulaTabItemUp);
connect(btnDown, &QToolButton::clicked, this, &BZDlg::MoveFormulaTabItemDown);
connect(m_formulas, &QTableWidget::itemChanged, this, &BZDlg::FormulaTableItemChanged);
connect(m_formulas, &QTableWidget::customContextMenuRequested, this, &BZDlg::ShowFormulaTableContextMenu);
tabs->addTab(formulaspanel, "Formulas");
}
{ // brillouin zone calculation results panel
auto resultspanel = new QWidget(this);
auto grid = new QGridLayout(resultspanel);
......@@ -512,7 +579,8 @@ BZDlg::BZDlg(QWidget* pParent) : QDialog{pParent},
m_recent.SetRecentFiles(m_sett->value("recent_files").toStringList());
}
m_ignoreChanges = 0;
m_symOpIgnoreChanges = 0;
m_formulaIgnoreChanges = 0;
}
......
......@@ -52,13 +52,26 @@
#include "tlibs2/libs/qt/numerictablewidgetitem.h"
// sg table column indices
/**
* symmetry operation table column indices
*/
enum : int
{
COL_OP = 0,
COL_PROP,
NUM_COLS
NUM_SYMOP_COLS
};
/**
* formulas table column indices
*/
enum : int
{
COL_FORMULA = 0,
NUM_FORMULAS_COLS
};
......@@ -93,6 +106,8 @@ protected:
QLineEdit *m_editGamma = nullptr;
QTableWidget *m_symops = nullptr;
QComboBox *m_comboSG = nullptr;
QMenu *m_symOpContextMenu = nullptr; // menu in case a symop is selected
QMenu *m_symOpContextMenuNoItem = nullptr; // menu if nothing is selected
// brillouin zone and cuts panel
BZCutScene *m_bzscene = nullptr;
......@@ -107,6 +122,11 @@ protected:
QSpinBox *m_BZDrawOrder = nullptr;
QSpinBox *m_BZCalcOrder = nullptr;
// formulas panel
QTableWidget *m_formulas = nullptr;
QMenu *m_formulasContextMenu = nullptr; // menu in case a symop is selected
QMenu *m_formulasContextMenuNoItem = nullptr; // menu if nothing is selected
// results panel
QPlainTextEdit *m_bzresults = nullptr;
std::string m_descrBZ, m_descrBZCut; // text description of the results
......@@ -124,9 +144,6 @@ protected:
return this->Load(filename);
};
QMenu *m_tabContextMenu = nullptr; // menu in case a symop is selected
QMenu *m_tabContextMenuNoItem = nullptr; // menu if nothing is selected
t_mat m_crystA = tl2::unit<t_mat>(3); // crystal A matrix
t_mat m_crystB = tl2::unit<t_mat>(3); // crystal B matrix
t_mat m_cut_plane = tl2::unit<t_mat>(3); // cutting plane
......@@ -138,15 +155,25 @@ protected:
protected:
// for space group / symops tab
void AddTabItem(int row = -1, const t_mat& op = tl2::unit<t_mat>(4));
void DelTabItem(int begin=-2, int end=-2);
void MoveTabItemUp();
void MoveTabItemDown();
void TableCurCellChanged(int rowNew, int colNew, int rowOld, int colOld);
void TableCellEntered(const QModelIndex& idx);
void TableItemChanged(QTableWidgetItem *item);
void ShowTableContextMenu(const QPoint& pt);
// space group / symops tab
void AddSymOpTabItem(int row = -1, const t_mat& op = tl2::unit<t_mat>(4));
void DelSymOpTabItem(int begin=-2, int end=-2);
void MoveSymOpTabItemUp();
void MoveSymOpTabItemDown();
void SymOpTableItemChanged(QTableWidgetItem *item);
void ShowSymOpTableContextMenu(const QPoint& pt);
std::vector<t_mat> GetSymOps(bool only_centring = false) const;
std::vector<int> GetSelectedSymOpRows(bool sort_reversed = false) const;
// formulas tab
void AddFormulaTabItem(int row = -1, const std::string& formula = "");
void DelFormulaTabItem(int begin=-2, int end=-2);
void MoveFormulaTabItemUp();
void MoveFormulaTabItemDown();
void FormulaTableItemChanged(QTableWidgetItem *item);
void ShowFormulaTableContextMenu(const QPoint& pt);
std::vector<std::string> GetFormulas() const;
std::vector<int> GetSelectedFormulaRows(bool sort_reversed = false) const;
// menu functions
void NewFile();
......@@ -160,10 +187,10 @@ protected:
bool Save(const QString& filename);
// calculation functions
std::vector<t_mat> GetSymOps(bool only_centring = false) const;
void CalcB(bool full_recalc = true);
void CalcBZ(bool full_recalc = true);
void CalcBZCut();
void CalcFormulas();
// 3d bz cut plot
void BZCutMouseMoved(t_real x, t_real y);
......@@ -197,16 +224,14 @@ protected:
private:
int m_cursorRow = -1; // current sg row
bool m_ignoreChanges = 1; // ignore sg changes
int m_symOpCursorRow = -1; // current sg row
int m_formulaCursorRow = -1; // current sg row
bool m_symOpIgnoreChanges = 1; // ignore sg changes
bool m_formulaIgnoreChanges = 1; // ignore sg changes
bool m_ignoreCalc = 0; // ignore bz calculation
long m_curPickedObj = -1; // current 3d bz object
std::vector<std::size_t> m_plotObjs; // 3d bz plot objects
private:
std::vector<int> GetSelectedRows(bool sort_reversed = false) const;
};
......
......@@ -35,6 +35,7 @@
#include "../structfact/loadcif.h"
#include "tlibs2/libs/phys.h"
#include "tlibs2/libs/algos.h"
#include "tlibs2/libs/expr.h"
#include "tlibs2/libs/qt/helper.h"
#include "pathslib/libs/voronoi.h"
......@@ -386,6 +387,35 @@ void BZDlg::CalcBZCut()
PlotSetPlane(norm, d_invA);
UpdateBZDescription();
CalcFormulas();
}
/**
* evaluate the formulas in the table and plot them
*/
void BZDlg::CalcFormulas()
{
std::vector<std::string> formulas = GetFormulas();
for(const std::string& formula : formulas)
{
try
{
tl2::ExprParser<t_real> parser;
parser.SetAutoregisterVariables(false);
parser.register_var("x", 0.);
if(bool ok = parser.parse(formula); !ok)
continue;
// TODO
//t_real result = parser.eval();
}
catch(const std::exception& ex)
{
m_status->setText(ex.what());
}
}
}
......@@ -408,5 +438,5 @@ void BZDlg::BZCutMouseMoved(t_real x, t_real y)
ostr << "Q = (" << QinvA[0] << ", " << QinvA[1] << ", " << QinvA[2] << ") Å⁻¹";
ostr << " = (" << Qrlu[0] << ", " << Qrlu[1] << ", " << Qrlu[2] << ") rlu.";
m_status->setText(ostr.str().c_str());
m_status->setText(ostr.str().c_str());
}
......@@ -52,8 +52,9 @@ void BZDlg::NewFile()
{
m_ignoreCalc = 1;
// clear old table
DelTabItem(-1);
// clear old tables
DelSymOpTabItem(-1);
DelFormulaTabItem(-1);
// set some defaults
m_comboSG->setCurrentIndex(0);
......@@ -102,7 +103,7 @@ bool BZDlg::Load(const QString& filename)
// clear old items
DelTabItem(-1);
DelSymOpTabItem(-1);
if(auto opt = node.get_optional<t_real>("bz.xtal.a"); opt)
{
......@@ -179,14 +180,22 @@ bool BZDlg::Load(const QString& filename)
// symops
if(auto symops = node.get_child_optional("bz.symops"); symops)
{
std::size_t opidx = 0;
for(const auto &symop : *symops)
{
auto optOp = symop.second.get<std::string>(
"op", "1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1");
AddTabItem(-1, StrToOp(optOp));
++opidx;
AddSymOpTabItem(-1, StrToOp(optOp));
}
}
// formulas
if(auto formulas = node.get_child_optional("bz.formulas"); formulas)
{
for(const auto &formula : *formulas)
{
std::string expr = formula.second.get<std::string>("expr", "");
AddFormulaTabItem(-1, expr);
}
}
}
......@@ -200,6 +209,7 @@ bool BZDlg::Load(const QString& filename)
m_ignoreCalc = 0;
CalcB(true);
return true;
}
......@@ -249,6 +259,17 @@ bool BZDlg::Save(const QString& filename)
node.add_child("bz.symops.symop", itemNode);
}
// formula list
for(int row=0; row<m_formulas->rowCount(); ++row)
{
std::string opstr = m_formulas->item(row, COL_FORMULA)->text().toStdString();
algo::replace_all(opstr, "\n", " ");
pt::ptree itemNode;
itemNode.put<std::string>("expr", opstr);
node.add_child("bz.formulas.formula", itemNode);
}
std::ofstream ofstr{filename.toStdString()};
if(!ofstr)
{
......@@ -320,7 +341,7 @@ void BZDlg::ImportCIF()
// clear old symops
DelTabItem(-1);
DelSymOpTabItem(-1);
// lattice
{
......@@ -352,7 +373,7 @@ void BZDlg::ImportCIF()
// symops
for(std::size_t opnum=0; opnum<symops.size(); ++opnum)
{
AddTabItem(-1, symops[opnum]);
AddSymOpTabItem(-1, symops[opnum]);
}
}
catch(const std::exception& ex)
......
/**
* brillouin zone tool
* @author Tobias Weber <tweber@ill.fr>
* @date June-2022
* @license GPLv3, see 'LICENSE' file
* @desc The present version was forked on 28-Dec-2018 from my privately developed "misc" project (https://github.com/t-weber/misc).
*
* ----------------------------------------------------------------------------
* mag-core (part of the Takin software suite)
* Copyright (C) 2018-2022 Tobias WEBER (Institut Laue-Langevin (ILL),
* Grenoble, France).
* "misc" project
* Copyright (C) 2017-2021 Tobias WEBER (privately developed).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ----------------------------------------------------------------------------
*/
#include "bz.h"
#include <QtWidgets/QTabWidget>
#include <QtWidgets/QMessageBox>
#include <iostream>
#include <tuple>
#include "tlibs2/libs/phys.h"
#include "tlibs2/libs/algos.h"
#include "tlibs2/libs/qt/helper.h"
using namespace tl2_ops;
void BZDlg::AddFormulaTabItem(int row, const std::string& formula)
{
bool bclone = 0;
m_formulaIgnoreChanges = 1;
if(row == -1) // append to end of table
row = m_formulas->rowCount();
else if(row == -2 && m_formulaCursorRow >= 0) // use row from member variable
row = m_formulaCursorRow;
else if(row == -3 && m_formulaCursorRow >= 0) // use row from member variable +1
row = m_formulaCursorRow + 1;
else if(row == -4 && m_formulaCursorRow >= 0) // use row from member variable +1
{
row = m_formulaCursorRow + 1;
bclone = 1;
}
//bool sorting = m_formulas->isSortingEnabled();
m_formulas->setSortingEnabled(false);
m_formulas->insertRow(row);
if(bclone)
{
for(int thecol=0; thecol<NUM_FORMULAS_COLS; ++thecol)
m_formulas->setItem(row, thecol,
m_formulas->item(m_formulaCursorRow, thecol)->clone());
}
else
{
m_formulas->setItem(row, COL_FORMULA,
new QTableWidgetItem(formula.c_str()));
}
m_formulas->scrollToItem(m_formulas->item(row, 0));
m_formulas->setCurrentCell(row, 0);
m_formulas->setSortingEnabled(/*sorting*/ true);
m_formulaIgnoreChanges = 0;
CalcFormulas();
}
void BZDlg::DelFormulaTabItem(int begin, int end)
{
m_formulaIgnoreChanges = 1;
// if nothing is selected, clear all items
if(begin == -1 || m_formulas->selectedItems().count() == 0)
{
m_formulas->clearContents();
m_formulas->setRowCount(0);
}
else if(begin == -2) // clear selected
{
for(int row : GetSelectedFormulaRows(true))
m_formulas->removeRow(row);
}
else if(begin >= 0 && end >= 0) // clear given range
{
for(int row=end-1; row>=begin; --row)
m_formulas->removeRow(row);
}
m_formulaIgnoreChanges = 0;
CalcFormulas();
}
void BZDlg::MoveFormulaTabItemUp()
{
m_formulaIgnoreChanges = 1;
m_formulas->setSortingEnabled(false);
auto selected = GetSelectedFormulaRows(false);
for(int row : selected)
{
if(row == 0)
continue;
auto *item = m_formulas->item(row, 0);
if(!item || !item->isSelected())
continue;
m_formulas->insertRow(row-1);
for(int col=0; col<m_formulas->columnCount(); ++col)
m_formulas->setItem(row-1, col, m_formulas->item(row+1, col)->clone());
m_formulas->removeRow(row+1);
}
for(int row=0; row<m_formulas->rowCount(); ++row)
{
if(auto *item = m_formulas->item(row, 0);
item && std::find(selected.begin(), selected.end(), row+1)
!= selected.end())
{
for(int col=0; col<m_formulas->columnCount(); ++col)
m_formulas->item(row, col)->setSelected(true);
}
}
m_formulaIgnoreChanges = 0;
}
void BZDlg::MoveFormulaTabItemDown()
{
m_formulaIgnoreChanges = 1;
m_formulas->setSortingEnabled(false);
auto selected = GetSelectedFormulaRows(true);
for(int row : selected)
{
if(row == m_formulas->rowCount()-1)
continue;
auto *item = m_formulas->item(row, 0);
if(!item || !item->isSelected())
continue;
m_formulas->insertRow(row+2);
for(int col=0; col<m_formulas->columnCount(); ++col)
m_formulas->setItem(row+2, col, m_formulas->item(row, col)->clone());
m_formulas->removeRow(row);
}
for(int row=0; row<m_formulas->rowCount(); ++row)
{
if(auto *item = m_formulas->item(row, 0);
item && std::find(selected.begin(), selected.end(), row-1)
!= selected.end())
{
for(int col=0; col<m_formulas->columnCount(); ++col)
m_formulas->item(row, col)->setSelected(true);
}
}
m_formulaIgnoreChanges = 0;
}
std::vector<int> BZDlg::GetSelectedFormulaRows(bool sort_reversed) const
{
std::vector<int> vec;
vec.reserve(m_formulas->selectedItems().size());
for(int row=0; row<m_formulas->rowCount(); ++row)
{
if(auto *item = m_formulas->item(row, 0); item && item->isSelected())
vec.push_back(row);
}