1+ #include " dipole.h"
2+ #include " ../module_base/constants.h"
3+ #include " ../module_base/timer.h"
4+ #include " ../module_base/global_variable.h"
5+ #include " ../src_parallel/parallel_reduce.h"
6+
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 ;
11+
12+ Dipole::Dipole (){}
13+
14+ Dipole::~Dipole (){}
15+
16+ // =======================================================
17+ // calculate dipole potential in surface calculations
18+ // =======================================================
19+ ModuleBase::matrix Dipole::v_dipole (const UnitCell &cell,
20+ PW_Basis &pwb,
21+ const int &nspin,
22+ const double *const *const rho)
23+ {
24+ ModuleBase::TITLE (" Dipole" , " v_dipole" );
25+ ModuleBase::timer::tick (" Dipole" , " v_dipole" );
26+
27+ double h_inv; // inverse of height
28+ if (dir == 0 )
29+ {
30+ h_inv = sqrt (cell.G .e11 * cell.G .e11 + cell.G .e12 * cell.G .e12 + cell.G .e13 * cell.G .e13 );
31+ }
32+ else if (dir == 1 )
33+ {
34+ h_inv = sqrt (cell.G .e21 * cell.G .e21 + cell.G .e22 * cell.G .e22 + cell.G .e23 * cell.G .e23 );
35+ }
36+ else if (dir = 2 )
37+ {
38+ h_inv = sqrt (cell.G .e31 * cell.G .e31 + cell.G .e32 * cell.G .e32 + cell.G .e33 * cell.G .e33 );
39+ }
40+ else
41+ {
42+ ModuleBase::WARNING_QUIT (" Dipole::ion_dipole" , " dipole direction is wrong!" );
43+ }
44+
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;
48+
49+ // dipole energy correction
50+ dipole_energy = 0.5 * ModuleBase::e2 * tot_dipole * tot_dipole * cell.omega / ModuleBase::FOUR_PI;
51+
52+ // dipole potential
53+ ModuleBase::matrix v (nspin, pwb.nrxx );
54+ const int nspin0 = (nspin == 2 ) ? 2 : 1 ;
55+
56+ for (int ir = 0 ; ir < pwb.nrxx ; ++ir)
57+ {
58+ int i = ir / (pwb.ncy * pwb.nczp );
59+ int j = ir / pwb.nczp - i * pwb.ncy ;
60+ int k = ir % pwb.nczp + pwb.nczp_start ;
61+ double x = (double )i / pwb.ncx ;
62+ double y = (double )j / pwb.ncy ;
63+ double z = (double )k / pwb.ncz ;
64+ ModuleBase::Vector3<double > pos (x, y, z);
65+
66+ double saw = saw_function (max_pos, de_reg, pos[dir]);
67+
68+ for (int is = 0 ; is < nspin0; is++)
69+ {
70+ v (is, ir) = saw;
71+ }
72+ }
73+
74+ double fac = - ModuleBase::e2 * tot_dipole * cell.lat0 / h_inv;
75+
76+ ModuleBase::timer::tick (" Dipole" , " v_dipole" );
77+ return v * fac;
78+ }
79+
80+
81+ // =======================================================
82+ // calculate dipole density in surface calculations
83+ // =======================================================
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)
126+ {
127+ double ion_dipole = 0 ;
128+ for (int it=0 ; it<cell.ntype ; ++it)
129+ {
130+ double sum = 0 ;
131+ for (int ia=0 ; ia<cell.atoms [it].na ; ++ia)
132+ {
133+ sum += saw_function (max_pos, de_reg, cell.atoms [it].taud [ia][dir]);
134+ }
135+ ion_dipole += sum * cell.atoms [it].zv ;
136+ }
137+ ion_dipole *= cell.lat0 / h_inv * ModuleBase::FOUR_PI / cell.omega ;
138+
139+ // std::cout << "ion_dipole = " << ion_dipole << std::endl;
140+
141+ return ion_dipole;
142+ }
143+
144+ double Dipole::cal_elec_dipole (const UnitCell &cell,
145+ PW_Basis &pwb,
146+ const int &nspin,
147+ const double *const *const rho,
148+ const double &h_inv)
149+ {
150+ double elec_dipole = 0 ;
151+ const int nspin0 = (nspin == 2 ) ? 2 : 1 ;
152+
153+ for (int ir = 0 ; ir < pwb.nrxx ; ++ir)
154+ {
155+ int i = ir / (pwb.ncy * pwb.nczp );
156+ int j = ir / pwb.nczp - i * pwb.ncy ;
157+ int k = ir % pwb.nczp + pwb.nczp_start ;
158+ double x = (double )i / pwb.ncx ;
159+ double y = (double )j / pwb.ncy ;
160+ double z = (double )k / pwb.ncz ;
161+ ModuleBase::Vector3<double > pos (x, y, z);
162+
163+ double saw = saw_function (max_pos, de_reg, pos[dir]);
164+
165+ for (int is = 0 ; is < nspin0; is++)
166+ {
167+ elec_dipole += rho[is][ir] * saw;
168+ }
169+ }
170+
171+ 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;
175+
176+ return elec_dipole;
177+ }
178+
179+ double Dipole::saw_function (const double &a, const double &b, const double &x)
180+ {
181+ assert (x>=0 );
182+ assert (x<=1 );
183+
184+ const double fac = 1 - b;
185+
186+ if ( x < a )
187+ {
188+ return x - a + 0.5 * fac;
189+ }
190+ else if ( x > (a+b))
191+ {
192+ return x - a - 1 + 0.5 * fac;
193+ }
194+ else
195+ {
196+ return 0.5 * fac - fac * (x - a) / b;
197+ }
198+ }
0 commit comments