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
1217Dipole::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}
0 commit comments