Skip to content

Commit 150e6e0

Browse files
authored
Fix the wrong symmetry analysis at nspin=2 (#5926)
* analyze magnetic group without time-reversal symmetry * fix: need to calculate direct coordinates again
1 parent e6245a6 commit 150e6e0

File tree

3 files changed

+82
-51
lines changed

3 files changed

+82
-51
lines changed

source/module_cell/module_symmetry/symmetry.cpp

Lines changed: 74 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
#include <memory>
22
#include <array>
3+
#include <set>
34
#include "module_parameter/parameter.h"
45
#include "symmetry.h"
56
#include "module_parameter/parameter.h"
67
#include "module_base/libm/libm.h"
78
#include "module_base/mathzone.h"
89
#include "module_base/constants.h"
910
#include "module_base/timer.h"
10-
11+
#include "module_io/output.h"
1112
namespace ModuleSymmetry
1213
{
1314
int Symmetry::symm_flag = 0;
@@ -124,57 +125,16 @@ void Symmetry::analy_sys(const Lattice& lat, const Statistics& st, Atom* atoms,
124125
}
125126

126127
if (!pricell_loop && PARAM.inp.nspin == 2)
127-
{//analyze symmetry for spin-up atoms only
128-
std::vector<double> pos_spinup;
129-
for (int it = 0;it < ntype;++it)
130-
{
131-
int na_spinup = 0;
132-
for (int ia = 0; ia < atoms[it].na; ++ia) {
133-
if (atoms[it].mag[ia] > -this->epsilon) {
134-
++na_spinup;
135-
}
136-
}
137-
this->na[it] = na_spinup;
138-
//update newpos
139-
for (int ia = 0;ia < atoms[it].na;++ia)
140-
{
141-
if (atoms[it].mag[ia] > -this->epsilon)
142-
{
143-
pos_spinup.push_back(this->newpos[3 * (istart[it] + ia)]);
144-
pos_spinup.push_back(this->newpos[3 * (istart[it] + ia) + 1]);
145-
pos_spinup.push_back(this->newpos[3 * (istart[it] + ia) + 2]);
146-
}
147-
}
148-
// update start to spin-up configuration
149-
if (it > 0) {
150-
istart[it] = istart[it - 1] + na[it - 1];
151-
}
152-
if (na[it] < na[itmin_type])
153-
{
154-
this->itmin_type = it;
155-
this->itmin_start = istart[it];
156-
}
157-
}
158-
this->getgroup(nrot_out, nrotk_out, ofs_running, this->nop, this->symop, this->gmatrix, this->gtrans,
159-
pos_spinup.data(), this->rotpos, this->index, this->itmin_type, this->itmin_start, this->istart, this->na);
160-
// recover na and istart
161-
for (int it = 0;it < ntype;++it)
162-
{
163-
this->na[it] = atoms[it].na;
164-
if (it > 0) {
165-
istart[it] = istart[it - 1] + na[it - 1];
166-
}
167-
}
168-
// For AFM analysis End
169-
//------------------------------------------------------------
128+
{
129+
this->analyze_magnetic_group(atoms, st, nrot_out, nrotk_out);
170130
}
171131
else
172132
{
173133
// get the real symmetry operations according to the input structure
174134
// nrot_out: the number of pure point group rotations
175135
// nrotk_out: the number of all space group operations
176136
this->getgroup(nrot_out, nrotk_out, ofs_running, this->nop, this->symop, this->gmatrix, this->gtrans,
177-
this->newpos, this->rotpos, this->index, this->itmin_type, this->itmin_start, this->istart, this->na);
137+
this->newpos, this->rotpos, this->index, this->ntype, this->itmin_type, this->itmin_start, this->istart, this->na);
178138
}
179139
};
180140

@@ -889,7 +849,7 @@ void Symmetry::lattice_type(
889849

890850
void Symmetry::getgroup(int& nrot, int& nrotk, std::ofstream& ofs_running, const int& nop,
891851
const ModuleBase::Matrix3* symop, ModuleBase::Matrix3* gmatrix, ModuleBase::Vector3<double>* gtrans,
892-
double* pos, double* rotpos, int* index, const int itmin_type, const int itmin_start, int* istart, int* na)const
852+
double* pos, double* rotpos, int* index, const int ntype, const int itmin_type, const int itmin_start, int* istart, int* na)const
893853
{
894854
ModuleBase::TITLE("Symmetry", "getgroup");
895855

@@ -913,7 +873,7 @@ void Symmetry::getgroup(int& nrot, int& nrotk, std::ofstream& ofs_running, const
913873
//std::cout << "nop = " <<nop <<std::endl;
914874
for (int i = 0; i < nop; ++i)
915875
{
916-
bool s_flag = this->checksym(symop[i], gtrans[i], pos, rotpos, index, itmin_type, itmin_start, istart, na);
876+
bool s_flag = this->checksym(symop[i], gtrans[i], pos, rotpos, index, ntype, itmin_type, itmin_start, istart, na);
917877
if (s_flag == 1)
918878
{
919879
//------------------------------
@@ -992,7 +952,7 @@ void Symmetry::getgroup(int& nrot, int& nrotk, std::ofstream& ofs_running, const
992952
}
993953

994954
bool Symmetry::checksym(const ModuleBase::Matrix3& s, ModuleBase::Vector3<double>& gtrans,
995-
double* pos, double* rotpos, int* index, const int itmin_type, const int itmin_start, int* istart, int* na)const
955+
double* pos, double* rotpos, int* index, const int ntype, const int itmin_type, const int itmin_start, int* istart, int* na)const
996956
{
997957
//----------------------------------------------
998958
// checks whether a point group symmetry element
@@ -2297,4 +2257,70 @@ bool Symmetry::is_all_movable(const Atom* atoms, const Statistics& st)const
22972257
}
22982258
return all_mbl;
22992259
}
2260+
2261+
void Symmetry::analyze_magnetic_group(const Atom* atoms, const Statistics& st, int& nrot_out, int& nrotk_out)
2262+
{
2263+
// 1. classify atoms with different magmom
2264+
// (use symmetry_prec to judge if two magmoms are the same)
2265+
std::vector<std::set<int>> mag_type_atoms;
2266+
for (int it = 0;it < ntype;++it)
2267+
{
2268+
for (int ia = 0; ia < atoms[it].na; ++ia)
2269+
{
2270+
bool find = false;
2271+
for (auto& mt : mag_type_atoms)
2272+
{
2273+
const int mag_iat = *mt.begin();
2274+
const int mag_it = st.iat2it[mag_iat];
2275+
const int mag_ia = st.iat2ia[mag_iat];
2276+
if (it == mag_it && this->equal(atoms[it].mag[ia], atoms[mag_it].mag[mag_ia]))
2277+
{
2278+
mt.insert(st.itia2iat(it, ia));
2279+
find = true;
2280+
break;
2281+
}
2282+
}
2283+
if (!find)
2284+
{
2285+
mag_type_atoms.push_back(std::set<int>({ st.itia2iat(it,ia) }));
2286+
}
2287+
}
2288+
}
2289+
2290+
// 2. get the start index, number of atoms and positions for each mag_type
2291+
std::vector<int> mag_istart(mag_type_atoms.size());
2292+
std::vector<int> mag_na(mag_type_atoms.size());
2293+
std::vector<double> mag_pos;
2294+
int mag_itmin_type = 0;
2295+
int mag_itmin_start = 0;
2296+
for (int mag_it = 0;mag_it < mag_type_atoms.size(); ++mag_it)
2297+
{
2298+
mag_na[mag_it] = mag_type_atoms.at(mag_it).size();
2299+
if (mag_it > 0)
2300+
{
2301+
mag_istart[mag_it] = mag_istart[mag_it - 1] + mag_na[mag_it - 1];
2302+
}
2303+
if (mag_na[mag_it] < mag_na[itmin_type])
2304+
{
2305+
mag_itmin_type = mag_it;
2306+
mag_itmin_start = mag_istart[mag_it];
2307+
}
2308+
for (auto& mag_iat : mag_type_atoms.at(mag_it))
2309+
{
2310+
// this->newpos have been ordered by original structure(ntype, na), it cannot be directly used here.
2311+
// we need to reset the calculate again the coordinate of the new structure.
2312+
const ModuleBase::Vector3<double> direct_tmp = atoms[st.iat2it[mag_iat]].tau[st.iat2ia[mag_iat]] * this->optlat.Inverse();
2313+
std::array<double, 3> direct = { direct_tmp.x, direct_tmp.y, direct_tmp.z };
2314+
for (int i = 0; i < 3; ++i)
2315+
{
2316+
this->check_translation(direct[i], -floor(direct[i]));
2317+
this->check_boundary(direct[i]);
2318+
mag_pos.push_back(direct[i]);
2319+
}
2320+
}
2321+
}
2322+
// 3. analyze the effective structure
2323+
this->getgroup(nrot_out, nrotk_out, GlobalV::ofs_running, this->nop, this->symop, this->gmatrix, this->gtrans,
2324+
mag_pos.data(), this->rotpos, this->index, mag_type_atoms.size(), mag_itmin_type, mag_itmin_start, mag_istart.data(), mag_na.data());
2325+
}
23002326
}

source/module_cell/module_symmetry/symmetry.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,10 @@ class Symmetry : public Symmetry_Basic
9191

9292
void getgroup(int& nrot, int& nrotk, std::ofstream& ofs_running, const int& nop,
9393
const ModuleBase::Matrix3* symop, ModuleBase::Matrix3* gmatrix, ModuleBase::Vector3<double>* gtrans,
94-
double* pos, double* rotpos, int* index, const int itmin_type, const int itmin_start, int* istart, int* na)const;
94+
double* pos, double* rotpos, int* index, const int ntype, const int itmin_type, const int itmin_start, int* istart, int* na)const;
9595
bool checksym(const ModuleBase::Matrix3& s, ModuleBase::Vector3<double>& gtrans,
96-
double* pos, double* rotpos, int* index, const int itmin_type, const int itmin_start, int* istart, int* na)const;
96+
double* pos, double* rotpos, int* index, const int itmin_type,
97+
const int ntype, const int itmin_start, int* istart, int* na)const;
9798
/// @brief primitive cell analysis
9899
void pricell(double* pos, const Atom* atoms);
99100

@@ -145,6 +146,10 @@ class Symmetry : public Symmetry_Basic
145146
/// Loop the magmom of each atoms in its type when NSPIN>1. If not all the same, primitive cells should not be looped in rhog_symmetry.
146147
bool magmom_same_check(const Atom* atoms)const;
147148

149+
/// Analyze magnetic group without time-reversal symmetry
150+
/// (because currently the charge density symmetrization does not support it)
151+
/// Method: treat atoms with different magmom as atoms of different type
152+
void analyze_magnetic_group(const Atom* atoms, const Statistics& st, int& nrot_out, int& nrotk_out);
148153
};
149154
}
150155

source/module_ri/module_exx_symmetry/irreducible_sector_bvk.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ namespace ModuleSymmetry
136136
symm.getgroup(bvk_npg, bvk_nsg, GlobalV::ofs_running, bvk_nop,
137137
bvk_op.data(), bvk_gmatrix.data(), bvk_gtrans.data(),
138138
bvk_dpos.data(), bvk_rot_dpos.data(), order_index.data(),
139-
bvk_itmin_type, bvk_itmin_start, bvk_istart.data(), bvk_na.data());
139+
symm.ntype, bvk_itmin_type, bvk_itmin_start, bvk_istart.data(), bvk_na.data());
140140
bvk_gmatrix.resize(bvk_nsg);
141141
bvk_gtrans.resize(bvk_nsg);
142142
this->bvk_nsym_ = bvk_nsg;

0 commit comments

Comments
 (0)