Commit b7700f3f authored by Tobias WEBER's avatar Tobias WEBER
Browse files

continued with symmetric positions

parent 04924b21
......@@ -2,7 +2,7 @@
* future math library, developed from scratch to eventually replace tlibs(2)
* container-agnostic math algorithms
* @author Tobias Weber <tweber@ill.fr>
* @date dec-2017 -- 2018
* @date dec-2017 -- 2019
* @license GPLv3, see 'LICENSE' file
* @desc The present version was forked on 8-Nov-2018 from the privately developed "magtools" project (https://github.com/t-weber/magtools).
*/
......@@ -3017,6 +3017,50 @@ requires is_basic_vec<t_vec>
}
/**
* create positions using the given symmetry operations
*/
template<class t_vec, class t_mat, class t_real = typename t_vec::value_type>
std::vector<t_vec> apply_ops_hom(const t_vec& _atom, const std::vector<t_mat>& ops,
t_real eps=std::numeric_limits<t_real>::epsilon(), bool bKeepInUnitCell=true)
requires is_vec<t_vec> && is_mat<t_mat>
{
// in homogeneous coordinates
t_vec atom = _atom;
if(atom.size() == 3)
atom = create<t_vec>({atom[0], atom[1], atom[2], 1});
std::vector<t_vec> newatoms;
for(const auto& op : ops)
{
auto newatom = op*atom;
newatom.resize(3);
if(bKeepInUnitCell)
{
for(std::size_t i=0; i<newatom.size(); ++i)
{
newatom[i] = std::fmod(newatom[i], 1.);
while(newatom[i] < -0.5) newatom[i] += 1.;
while(newatom[i] >= 0.5) newatom[i] -= 1.;
}
}
// position already occupied?
if(std::find_if(newatoms.begin(), newatoms.end(), [&newatom, eps](const t_vec& vec)->bool
{
return m::equals<t_vec>(vec, newatom, eps);
}) == newatoms.end())
{
newatoms.emplace_back(std::move(newatom));
}
}
return newatoms;
}
// ----------------------------------------------------------------------------
......
......@@ -22,6 +22,7 @@
using namespace m_ops;
template<class t_real=double>
struct Lattice
{
......@@ -30,6 +31,7 @@ struct Lattice
};
/**
* gets the symmetry operations from the CIF
*/
......@@ -57,6 +59,7 @@ std::vector<t_mat> get_cif_ops(gemmi::cif::Block& block)
}
/**
* gets the symmetry operations from the CIF's space group
*/
......@@ -97,6 +100,7 @@ std::vector<t_mat> get_cif_sg_ops(gemmi::cif::Block& block)
}
/**
* loads the lattice parameters and the atom positions from a CIF
*/
......@@ -158,32 +162,7 @@ load_cif(const std::string& filename)
// make homogeneuous 4-vector
if(atom.size() == 3) atom.push_back(1);
std::vector<t_vec> newatoms;
for(const auto& op : ops)
{
auto newatom = op*atom;
newatom.resize(3);
for(int i=0; i<3; ++i)
{
newatom[i] = std::fmod(newatom[i], 1);
while(newatom[i] < 0) newatom[i] += 1;
while(newatom[i] >= 1) newatom[i] -= 1;
newatom[i] -= 0.5;
}
// position already occupied?
if(std::find_if(newatoms.begin(), newatoms.end(), [&newatom](const t_vec& vec)->bool
{
return m::equals<t_vec>(vec, newatom);
}) == newatoms.end())
{
newatoms.emplace_back(std::move(newatom));
}
}
std::vector<t_vec> newatoms = m::apply_ops_hom<t_vec, t_mat, t_real>(atom, ops);
// if no ops are given, just output the raw atom position
if(!ops.size())
......
......@@ -34,15 +34,11 @@ namespace pt = boost::property_tree;
#include "loadcif.h"
#include "libs/algos.h"
#include "libs/helper.h"
#include "libs/_cxx20/math_algos.h"
//using namespace m;
using namespace m_ops;
using t_vec = std::vector<t_real>;
using t_vec_cplx = std::vector<t_cplx>;
using t_mat = m::mat<t_real, std::vector>;
using t_mat_cplx = m::mat<t_cplx, std::vector>;
enum : int
{
......@@ -154,6 +150,7 @@ StructFactDlg::StructFactDlg(QWidget* pParent) : QDialog{pParent},
for(auto [sgnum, descr, ops] : get_sgs<t_mat>())
{
m_comboSG->addItem(descr.c_str(), m_comboSG->count());
m_SGops.emplace_back(std::move(ops));
}
......@@ -195,13 +192,13 @@ StructFactDlg::StructFactDlg(QWidget* pParent) : QDialog{pParent},
m_pTabContextMenu->addAction("Add Nucleus Before", this, [this]() { this->AddTabItem(-2); });
m_pTabContextMenu->addAction("Add Nucleus After", this, [this]() { this->AddTabItem(-3); });
m_pTabContextMenu->addAction("Clone Nucleus", this, [this]() { this->AddTabItem(-4); });
m_pTabContextMenu->addAction("Delete Nucleus", this, &StructFactDlg::DelTabItem);
m_pTabContextMenu->addAction("Delete Nucleus", this, [this]() { StructFactDlg::DelTabItem(); });
// table CustomContextMenu in case nothing is selected
m_pTabContextMenuNoItem = new QMenu(m_nuclei);
m_pTabContextMenuNoItem->addAction("Add Nucleus", this, [this]() { this->AddTabItem(); });
m_pTabContextMenuNoItem->addAction("Delete Nucleus", this, &StructFactDlg::DelTabItem);
m_pTabContextMenuNoItem->addAction("Delete Nucleus", this, [this]() { StructFactDlg::DelTabItem(); });
//m_pTabContextMenuNoItem->addSeparator();
......@@ -210,7 +207,7 @@ StructFactDlg::StructFactDlg(QWidget* pParent) : QDialog{pParent},
connect(edit, &QLineEdit::textEdited, this, [this]() { this->Calc(); });
connect(pTabBtnAdd, &QToolButton::clicked, this, [this]() { this->AddTabItem(-1); });
connect(pTabBtnDel, &QToolButton::clicked, this, &StructFactDlg::DelTabItem);
connect(pTabBtnDel, &QToolButton::clicked, this, [this]() { StructFactDlg::DelTabItem(); });
connect(pTabBtnUp, &QToolButton::clicked, this, &StructFactDlg::MoveTabItemUp);
connect(pTabBtnDown, &QToolButton::clicked, this, &StructFactDlg::MoveTabItemDown);
connect(pTabBtnLoad, &QToolButton::clicked, this, &StructFactDlg::Load);
......@@ -470,12 +467,12 @@ void StructFactDlg::Add3DItem(int row)
}
void StructFactDlg::DelTabItem(bool clearAll)
void StructFactDlg::DelTabItem(int begin, int end)
{
m_ignoreChanges = 1;
// if nothing is selected, clear all items
if(clearAll || m_nuclei->selectedItems().count() == 0)
if(begin == -1 || m_nuclei->selectedItems().count() == 0)
{
if(m_plot)
{
......@@ -488,7 +485,7 @@ void StructFactDlg::DelTabItem(bool clearAll)
m_nuclei->clearContents();
m_nuclei->setRowCount(0);
}
else // clear selected
else if(begin == -2) // clear selected
{
for(int row : GetSelectedRows(true))
{
......@@ -503,6 +500,21 @@ void StructFactDlg::DelTabItem(bool clearAll)
m_nuclei->removeRow(row);
}
}
else if(begin >= 0 && end >= 0) // clear given range
{
for(int row=end-1; row>=begin; --row)
{
// remove 3d object
if(m_plot)
{
if(std::size_t obj = m_nuclei->item(row, COL_NAME)->data(Qt::UserRole).toUInt(); obj)
m_plot->GetImpl()->RemoveObject(obj);
m_plot->update();
}
m_nuclei->removeRow(row);
}
}
m_ignoreChanges = 0;
Calc();
......@@ -707,7 +719,7 @@ void StructFactDlg::Load()
// clear old nuclei
DelTabItem(true);
DelTabItem(-1);
if(auto opt = node.get_optional<t_real>("sfact.xtal.a"); opt)
{
......@@ -743,6 +755,10 @@ void StructFactDlg::Load()
{
m_maxBZ->setValue(*opt);
}
if(auto opt = node.get_optional<int>("sfact.sg_idx"); opt)
{
m_comboSG->setCurrentIndex(*opt);
}
// nuclei
......@@ -800,11 +816,12 @@ void StructFactDlg::Save()
node.put<t_real>("sfact.xtal.beta", beta);
node.put<t_real>("sfact.xtal.gamma", gamma);
node.put<int>("sfact.order", m_maxBZ->value());
node.put<int>("sfact.sg_idx", m_comboSG->currentIndex());
// nucleus list
for(int row=0; row<m_nuclei->rowCount(); ++row)
{
t_real bRe,bIm, x,y,z, scale;
t_real bRe{},bIm{}, x{},y{},z{}, scale{};
std::istringstream{m_nuclei->item(row, COL_SCATLEN_RE)->text().toStdString()} >> bRe;
std::istringstream{m_nuclei->item(row, COL_SCATLEN_IM)->text().toStdString()} >> bIm;
std::istringstream{m_nuclei->item(row, COL_X)->text().toStdString()} >> x;
......@@ -847,7 +864,7 @@ void StructFactDlg::ImportCIF()
// clear old nuclei
DelTabItem(true);
DelTabItem(-1);
// lattice
{
......@@ -904,6 +921,40 @@ void StructFactDlg::ImportCIF()
*/
void StructFactDlg::GenerateFromSG()
{
// symops of current space group
auto sgidx = m_comboSG->itemData(m_comboSG->currentIndex()).toInt();
if(sgidx < 0 || sgidx >= m_SGops.size())
{
QMessageBox::critical(this, "Structure Factors", "Invalid space group selected.");
return;
}
auto ops = m_SGops[sgidx];
// iterate nuclei
int orgRowCnt = m_nuclei->rowCount();
for(int row=0; row<orgRowCnt; ++row)
{
t_real bRe{}, bIm{}, x{},y{},z{}, scale{};
std::istringstream{m_nuclei->item(row, COL_SCATLEN_RE)->text().toStdString()} >> bRe;
std::istringstream{m_nuclei->item(row, COL_SCATLEN_IM)->text().toStdString()} >> bIm;
std::istringstream{m_nuclei->item(row, COL_X)->text().toStdString()} >> x;
std::istringstream{m_nuclei->item(row, COL_Y)->text().toStdString()} >> y;
std::istringstream{m_nuclei->item(row, COL_Z)->text().toStdString()} >> z;
std::istringstream{m_nuclei->item(row, COL_RAD)->text().toStdString()} >> scale;
std::string name = m_nuclei->item(row, COL_NAME)->text().toStdString();
std::string col = m_nuclei->item(row, COL_COL)->text().toStdString();
t_vec nucl = m::create<t_vec>({x, y, z, 1});
auto newnuclei = m::apply_ops_hom<t_vec, t_mat, t_real>(nucl, ops);
for(const auto& newnucl : newnuclei)
AddTabItem(-1, name, bRe, bIm, newnucl[0], newnucl[1], newnucl[2], scale, col);
}
// remove original nuclei
DelTabItem(0, orgRowCnt);
}
......
......@@ -23,11 +23,17 @@
#include <sstream>
#include <complex>
#include "../glplot/glplot.h"
#include "tools/glplot/glplot.h"
#include "libs/_cxx20/math_algos.h"
using t_real = double;
using t_cplx = std::complex<t_real>;
using t_vec = std::vector<t_real>;
using t_vec_cplx = std::vector<t_cplx>;
using t_mat = m::mat<t_real, std::vector>;
using t_mat_cplx = m::mat<t_cplx, std::vector>;
template<class T = t_real>
......@@ -98,6 +104,7 @@ protected:
QLineEdit *m_editGamma = nullptr;
QComboBox *m_comboSG = nullptr;
std::vector<std::vector<t_mat>> m_SGops;
QSpinBox *m_maxBZ = nullptr;
......@@ -107,7 +114,7 @@ protected:
protected:
void AddTabItem(int row=-1, const std::string& name="n/a", t_real bRe=0., t_real bIm=0.,
t_real x=0., t_real y=0., t_real z=0., t_real scale=1., const std::string &col="#ff0000");
void DelTabItem(bool clearAll=false);
void DelTabItem(int begin=-2, int end=-2);
void MoveTabItemUp();
void MoveTabItemDown();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment