Skip to content

Commit f78b890

Browse files
committed
feature : incorporate efield into dipole.cpp
1 parent 22c0d77 commit f78b890

File tree

15 files changed

+177
-479
lines changed

15 files changed

+177
-479
lines changed

source/Makefile.Objects

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,6 @@ write_HS.o\
295295
write_HS_R.o\
296296
write_dm.o\
297297
write_wfc_realspace.o\
298-
efield.o \
299298
magnetism.o\
300299
optical.o\
301300
Cell_PW.o\

source/input_conv.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#include "src_io/epsilon0_vasp.h"
1313
#include "src_io/optical.h"
1414
#include "src_ions/ions_move_basic.h"
15-
#include "src_pw/efield.h"
1615
#include "src_pw/global.h"
1716
#include "src_pw/occupy.h"
1817
#ifdef __EXX

source/module_esolver/esolver_ks_lcao.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "src_pw/symmetry_rho.h"
1515
#include "src_io/chi0_hilbert.h"
1616
#include "src_pw/threshold_elec.h"
17+
#include "module_surchem/dipole.h"
1718

1819
#ifdef __DEEPKS
1920
#include "../module_deepks/LCAO_deepks.h"
@@ -315,6 +316,7 @@ namespace ModuleESolver
315316
if (iter == 1)
316317
{
317318
GlobalC::CHR.set_new_e_iteration(true);
319+
Dipole::first = true;
318320
}
319321
else
320322
{

source/module_esolver/esolver_ks_pw.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "../src_io/chi0_hilbert.h"
2222
#include "../src_io/epsilon0_pwscf.h"
2323
#include "../src_io/epsilon0_vasp.h"
24+
#include "../module_surchem/dipole.h"
2425
//-----force-------------------
2526
#include "../src_pw/forces.h"
2627
//-----stress------------------
@@ -195,8 +196,15 @@ namespace ModuleESolver
195196
void ESolver_KS_PW::eachiterinit(const int istep, const int iter)
196197
{
197198
// mohan add 2010-07-16
198-
if (iter == 1) GlobalC::CHR.set_new_e_iteration(true);
199-
else GlobalC::CHR.set_new_e_iteration(false);
199+
if (iter == 1)
200+
{
201+
GlobalC::CHR.set_new_e_iteration(true);
202+
Dipole::first = true;
203+
}
204+
else
205+
{
206+
GlobalC::CHR.set_new_e_iteration(false);
207+
}
200208

201209
if (GlobalV::FINAL_SCF && iter == 1)
202210
{

source/module_surchem/dipole.cpp

Lines changed: 121 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@
44
#include "../module_base/global_variable.h"
55
#include "../src_parallel/parallel_reduce.h"
66

7-
int Dipole::dir = 2;
8-
double Dipole::dipole_energy = 0.0;
9-
double Dipole::max_pos = 0.5;
10-
double Dipole::de_reg = 0.1;
7+
double Dipole::etotefield = 0.0;
8+
double Dipole::tot_dipole = 0.0;
9+
int Dipole::edir = 2;
10+
double Dipole::emaxpos = 0.5;
11+
double Dipole::eopreg = 0.1;
12+
double Dipole::eamp = 0.0;
13+
bool Dipole::first = true;
14+
double Dipole::bvec[3];
15+
double Dipole::bmod;
1116

1217
Dipole::Dipole(){}
1318

@@ -16,41 +21,90 @@ Dipole::~Dipole(){}
1621
//=======================================================
1722
// calculate dipole potential in surface calculations
1823
//=======================================================
19-
ModuleBase::matrix Dipole::v_dipole(const UnitCell &cell,
20-
PW_Basis &pwb,
21-
const int &nspin,
22-
const double *const *const rho)
24+
ModuleBase::matrix Dipole::add_efield(const UnitCell &cell,
25+
PW_Basis &pwb,
26+
const int &nspin,
27+
const double *const *const rho)
2328
{
24-
ModuleBase::TITLE("Dipole", "v_dipole");
25-
ModuleBase::timer::tick("Dipole", "v_dipole");
29+
ModuleBase::TITLE("Dipole", "add_efield");
30+
ModuleBase::timer::tick("Dipole", "add_efield");
2631

27-
double h_inv; // inverse of height
28-
if(dir == 0)
32+
ModuleBase::matrix v(nspin, pwb.nrxx);
33+
34+
// efield only needs to be added on the first iteration, if dipfield
35+
// is not used. note that for relax calculations it has to be added
36+
// again on subsequent relax steps.
37+
if(!GlobalV::DIPOLE && !first)
38+
{
39+
return v;
40+
}
41+
first = false;
42+
43+
double latvec; // latvec along the efield direction
44+
if(edir == 0)
2945
{
30-
h_inv = sqrt(cell.G.e11 * cell.G.e11 + cell.G.e12 * cell.G.e12 + cell.G.e13 * cell.G.e13);
46+
bvec[0] = cell.G.e11;
47+
bvec[1] = cell.G.e12;
48+
bvec[2] = cell.G.e13;
49+
latvec = cell.a1.norm();
3150
}
32-
else if(dir == 1)
51+
else if(edir == 1)
3352
{
34-
h_inv = sqrt(cell.G.e21 * cell.G.e21 + cell.G.e22 * cell.G.e22 + cell.G.e23 * cell.G.e23);
53+
bvec[0] = cell.G.e21;
54+
bvec[1] = cell.G.e22;
55+
bvec[2] = cell.G.e23;
56+
latvec = cell.a2.norm();
3557
}
36-
else if(dir = 2)
58+
else if(edir = 2)
59+
{
60+
bvec[0] = cell.G.e31;
61+
bvec[1] = cell.G.e32;
62+
bvec[2] = cell.G.e33;
63+
latvec = cell.a3.norm();
64+
}
65+
else
66+
{
67+
ModuleBase::WARNING_QUIT("Dipole::ion_dipole", "direction is wrong!");
68+
}
69+
bmod = sqrt(pow(bvec[0],2) + pow(bvec[1],2) + pow(bvec[2],2));
70+
71+
double ion_dipole = 0;
72+
double elec_dipole = 0;
73+
74+
if(GlobalV::DIPOLE)
3775
{
38-
h_inv = sqrt(cell.G.e31 * cell.G.e31 + cell.G.e32 * cell.G.e32 + cell.G.e33 * cell.G.e33);
76+
ion_dipole = cal_ion_dipole(cell, bmod);
77+
elec_dipole = cal_elec_dipole(cell, pwb, nspin, rho, bmod);
78+
tot_dipole = ion_dipole - elec_dipole;
79+
80+
// energy correction
81+
etotefield = - ModuleBase::e2 * (eamp - 0.5 * tot_dipole) * tot_dipole * cell.omega / ModuleBase::FOUR_PI;
3982
}
4083
else
4184
{
42-
ModuleBase::WARNING_QUIT("Dipole::ion_dipole", "dipole direction is wrong!");
85+
ion_dipole = cal_ion_dipole(cell, bmod);
86+
tot_dipole = ion_dipole - elec_dipole;
87+
88+
// energy correction
89+
etotefield = - ModuleBase::e2 * eamp * tot_dipole * cell.omega / ModuleBase::FOUR_PI;
4390
}
4491

45-
double ion_dipole = cal_ion_dipole(cell, h_inv);
46-
double elec_dipole = cal_elec_dipole(cell, pwb, nspin, rho, h_inv);
47-
double tot_dipole = ion_dipole - elec_dipole;
92+
const double length = (1.0 - eopreg) * latvec * cell.lat0;
93+
const double vamp = ModuleBase::e2 * (eamp - tot_dipole) * length;
4894

49-
// dipole energy correction
50-
dipole_energy = 0.5 * ModuleBase::e2 * tot_dipole * tot_dipole * cell.omega / ModuleBase::FOUR_PI;
95+
GlobalV::ofs_running << "\n\n Adding external electric field: " << std::endl;
96+
ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "Computed dipole along edir", edir);
97+
ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "Elec. dipole (Ry a.u.)", elec_dipole);
98+
ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "Ion dipole (Ry a.u.)", ion_dipole);
99+
ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "Total dipole (Ry a.u.)", tot_dipole);
100+
if( abs(eamp) > 0.0)
101+
{
102+
ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "Amplitute of Efield (Hartree)", eamp);
103+
}
104+
ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "Potential amplitute (Ry)", vamp);
105+
ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "Total length (Bohr)", length);
51106

52107
// dipole potential
53-
ModuleBase::matrix v(nspin, pwb.nrxx);
54108
const int nspin0 = (nspin == 2) ? 2 : 1;
55109

56110
for (int ir = 0; ir < pwb.nrxx; ++ir)
@@ -63,80 +117,37 @@ ModuleBase::matrix Dipole::v_dipole(const UnitCell &cell,
63117
double z = (double)k / pwb.ncz;
64118
ModuleBase::Vector3<double> pos(x, y, z);
65119

66-
double saw = saw_function(max_pos, de_reg, pos[dir]);
120+
double saw = saw_function(emaxpos, eopreg, pos[edir]);
67121

68122
for (int is = 0; is < nspin0; is++)
69123
{
70124
v(is, ir) = saw;
71125
}
72126
}
73127

74-
double fac = - ModuleBase::e2 * tot_dipole * cell.lat0 / h_inv;
128+
double fac = ModuleBase::e2 * (eamp - tot_dipole) * cell.lat0 / bmod;
75129

76-
ModuleBase::timer::tick("Dipole", "v_dipole");
130+
ModuleBase::timer::tick("Dipole", "add_efield");
77131
return v * fac;
78132
}
79133

80134

81135
//=======================================================
82136
// calculate dipole density in surface calculations
83137
//=======================================================
84-
// double Dipole::dipole(const UnitCell &cell,
85-
// PW_Basis &pwb,
86-
// const double *const *const rho,
87-
// complex<double> *TOTN)
88-
// {
89-
// double *Porter = new double[pwb.nrxx];
90-
91-
// for (int ir = 0; ir < pwb.nrxx; ++ir)
92-
// {
93-
// int i = ir / (pwb.ncy * pwb.nczp);
94-
// int j = ir / pwb.nczp - i * pwb.ncy;
95-
// int k = ir % pwb.nczp + pwb.nczp_start;
96-
// double x = (double)i / pwb.ncx;
97-
// double y = (double)j / pwb.ncy;
98-
// double z = (double)k / pwb.ncz;
99-
// ModuleBase::Vector3<double> pos(x, y, z);
100-
101-
// pos = cell.latvec * pos;
102-
103-
// Porter[ir] = cell.lat0 * pos[dir];
104-
// }
105-
106-
// complex<double> *Porter_g = new complex<double>[pwb.ngmc];
107-
// GlobalC::UFFT.ToReciSpace(Porter, Porter_g);
108-
109-
// double m = 0;
110-
// for (int ig = 0; ig < pwb.ngmc; ig++)
111-
// {
112-
// m += (conj(TOTN[ig]) * Porter_g[ig]).real();
113-
// }
114-
115-
// Parallel_Reduce::reduce_double_pool(m);
116-
117-
// // height
118-
// const double h = cell.latvec.to_matrix()(dir, dir) * cell.lat0;
119-
120-
// delete[] Porter, Porter_g;
121-
122-
// return -m * h * ModuleBase::e2;
123-
// }
124-
125-
double Dipole::cal_ion_dipole(const UnitCell &cell, const double &h_inv)
138+
double Dipole::cal_ion_dipole(const UnitCell &cell, const double &bmod)
126139
{
127140
double ion_dipole = 0;
128141
for(int it=0; it<cell.ntype; ++it)
129142
{
130143
double sum = 0;
131144
for(int ia=0; ia<cell.atoms[it].na; ++ia)
132145
{
133-
sum += saw_function(max_pos, de_reg, cell.atoms[it].taud[ia][dir]);
146+
sum += saw_function(emaxpos, eopreg, cell.atoms[it].taud[ia][edir]);
134147
}
135148
ion_dipole += sum * cell.atoms[it].zv;
136149
}
137-
ion_dipole *= cell.lat0 / h_inv * ModuleBase::FOUR_PI / cell.omega;
138-
139-
// std::cout << "ion_dipole = " << ion_dipole << std::endl;
150+
ion_dipole *= cell.lat0 / bmod * ModuleBase::FOUR_PI / cell.omega;
140151

141152
return ion_dipole;
142153
}
@@ -145,7 +156,7 @@ double Dipole::cal_elec_dipole(const UnitCell &cell,
145156
PW_Basis &pwb,
146157
const int &nspin,
147158
const double *const *const rho,
148-
const double &h_inv)
159+
const double &bmod)
149160
{
150161
double elec_dipole = 0;
151162
const int nspin0 = (nspin == 2) ? 2 : 1;
@@ -160,7 +171,7 @@ double Dipole::cal_elec_dipole(const UnitCell &cell,
160171
double z = (double)k / pwb.ncz;
161172
ModuleBase::Vector3<double> pos(x, y, z);
162173

163-
double saw = saw_function(max_pos, de_reg, pos[dir]);
174+
double saw = saw_function(emaxpos, eopreg, pos[edir]);
164175

165176
for (int is = 0; is < nspin0; is++)
166177
{
@@ -169,9 +180,7 @@ double Dipole::cal_elec_dipole(const UnitCell &cell,
169180
}
170181

171182
Parallel_Reduce::reduce_double_pool(elec_dipole);
172-
elec_dipole *= cell.lat0 / h_inv * ModuleBase::FOUR_PI / pwb.ncxyz;
173-
174-
// std::cout << "elec_dipole = " << elec_dipole << std::endl;
183+
elec_dipole *= cell.lat0 / bmod * ModuleBase::FOUR_PI / pwb.ncxyz;
175184

176185
return elec_dipole;
177186
}
@@ -195,4 +204,38 @@ double Dipole::saw_function(const double &a, const double &b, const double &x)
195204
{
196205
return 0.5 * fac - fac * (x - a) / b;
197206
}
207+
}
208+
209+
void Dipole::compute_force(const UnitCell &cell, ModuleBase::matrix &fdip)
210+
{
211+
if(GlobalV::DIPOLE)
212+
{
213+
int iat = 0;
214+
for(int it=0; it<cell.ntype; ++it)
215+
{
216+
for(int ia=0; ia<cell.atoms[it].na; ++ia)
217+
{
218+
for(int jj=0; jj<3; ++jj)
219+
{
220+
fdip(iat, jj) = ModuleBase::e2 * (eamp - tot_dipole) * cell.atoms[it].zv * bvec[jj] / bmod;
221+
}
222+
++iat;
223+
}
224+
}
225+
}
226+
else
227+
{
228+
int iat = 0;
229+
for(int it=0; it<cell.ntype; ++it)
230+
{
231+
for(int ia=0; ia<cell.atoms[it].na; ++ia)
232+
{
233+
for(int jj=0; jj<3; ++jj)
234+
{
235+
fdip(iat, jj) = ModuleBase::e2 * eamp * cell.atoms[it].zv * bvec[jj] / bmod;
236+
}
237+
++iat;
238+
}
239+
}
240+
}
198241
}

source/module_surchem/dipole.h

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,10 @@ class Dipole
1010
Dipole();
1111
~Dipole();
1212

13-
static double dipole(const UnitCell &cell,
14-
PW_Basis &pwb,
15-
const double *const *const rho,
16-
complex<double> *TOTN);
17-
18-
static ModuleBase::matrix v_dipole(const UnitCell &cell,
19-
PW_Basis &pwb,
20-
const int &nspin,
21-
const double *const *const rho);
13+
static ModuleBase::matrix add_efield(const UnitCell &cell,
14+
PW_Basis &pwb,
15+
const int &nspin,
16+
const double *const *const rho);
2217

2318
static double cal_elec_dipole(const UnitCell &cell,
2419
PW_Basis &pwb,
@@ -30,12 +25,19 @@ class Dipole
3025

3126
static double saw_function(const double &a, const double &b, const double &x);
3227

28+
static void compute_force(const UnitCell &cell, ModuleBase::matrix &fdip);
29+
3330

3431

35-
static double dipole_energy; // dipole energy
36-
static int dir; // 0, 1, 2 denotes x, y, z direction for dipole correction
37-
static double max_pos; // the maximum position of the saw function
38-
static double de_reg; // the decrease region length of the saw function
32+
static double etotefield; // dipole energy
33+
static double tot_dipole; // total dipole
34+
static int edir; // 0, 1, 2 denotes x, y, z direction for dipole correction
35+
static double emaxpos; // the maximum position of the saw function
36+
static double eopreg; // the decrease region length of the saw function
37+
static double eamp; // field amplitude (in a.u.) (1 a.u. = 51.44 10^10 V/m)
38+
static bool first; // efield only needs to be added on the first iteration, if dipfield is not used.
39+
static double bvec[3];
40+
static double bmod;
3941
};
4042

4143

0 commit comments

Comments
 (0)