ABACUS develop
Atomic-orbital Based Ab-initio Computation at UStc
Loading...
Searching...
No Matches
operator_force_stress_utils.hpp
Go to the documentation of this file.
1#ifndef OPERATOR_FORCE_STRESS_UTILS_HPP
2#define OPERATOR_FORCE_STRESS_UTILS_HPP
3
6#include "source_base/timer.h"
10
11namespace OperatorForceStress {
12
37template <typename TK, typename TR, typename IntegralFunc, int ForceSign, int StressSign>
39 const bool cal_force,
40 const bool cal_stress,
42 const UnitCell* ucell,
43 const Grid_Driver* gridD,
44 const std::vector<double>& orb_cutoff,
45 const Parallel_Orbitals* paraV,
46 IntegralFunc& integral_calculator,
47 ModuleBase::matrix& force,
48 ModuleBase::matrix& stress)
49{
50 const int npol = ucell->get_npol();
51 std::vector<double> stress_tmp(6, 0);
52
53 if (cal_force)
54 {
55 force.zero_out();
56 }
57
58 // Loop over all atom pairs and calculate force/stress contributions
59 #pragma omp parallel
60 {
61 std::vector<double> stress_local(6, 0);
62 ModuleBase::matrix force_local(force.nr, force.nc);
63
64 #pragma omp for schedule(dynamic)
65 for (int iat1 = 0; iat1 < ucell->nat; iat1++)
66 {
67 auto tau1 = ucell->get_tau(iat1);
68 int T1 = 0, I1 = 0;
69 ucell->iat2iait(iat1, &I1, &T1);
70 Atom& atom1 = ucell->atoms[T1];
71
72 // Find adjacent atoms
74 gridD->Find_atom(*ucell, tau1, T1, I1, &adjs);
75
76 for (int ad = 0; ad < adjs.adj_num + 1; ++ad)
77 {
78 const int T2 = adjs.ntype[ad];
79 const int I2 = adjs.natom[ad];
80 const int iat2 = ucell->itia2iat(T2, I2);
81 const ModuleBase::Vector3<int>& R_index = adjs.box[ad];
82
83 // Check cutoff
84 ModuleBase::Vector3<double> dtau = ucell->cal_dtau(iat1, iat2, R_index);
85 if (dtau.norm() * ucell->lat0 >= orb_cutoff[T1] + orb_cutoff[T2])
86 {
87 continue;
88 }
89
90 // Find density matrix for this atom pair
91 const hamilt::BaseMatrix<double>* dm_matrix = dmR->find_matrix(iat1, iat2, R_index[0], R_index[1], R_index[2]);
92 if (dm_matrix == nullptr)
93 {
94 continue;
95 }
96
97 // Calculate force and stress for this atom pair
98 double* force_tmp1 = (cal_force) ? &force_local(iat1, 0) : nullptr;
99 double* force_tmp2 = (cal_force) ? &force_local(iat2, 0) : nullptr;
100
101 Atom& atom2 = ucell->atoms[T2];
102 auto row_indexes = paraV->get_indexes_row(iat1);
103 auto col_indexes = paraV->get_indexes_col(iat2);
104
105 if (row_indexes.size() == 0 || col_indexes.size() == 0)
106 {
107 continue;
108 }
109
110 const double* dm_pointer = dm_matrix->get_pointer();
111 double olm[4] = {0, 0, 0, 0}; // value, dx, dy, dz
112
113 // step_trace = 0 for npol=1; ={0, 1, col_size, col_size+1} for npol=2
114 std::vector<int> step_trace(npol * npol, 0);
115 if (npol == 2)
116 {
117 step_trace[1] = 1;
118 step_trace[2] = col_indexes.size();
119 step_trace[3] = col_indexes.size() + 1;
120 }
121
122 // Loop over orbital pairs
123 for (int iw1l = 0; iw1l < row_indexes.size(); iw1l += npol)
124 {
125 const int iw1 = row_indexes[iw1l] / npol;
126 const int L1 = atom1.iw2l[iw1];
127 const int N1 = atom1.iw2n[iw1];
128 const int m1 = atom1.iw2m[iw1];
129 const int M1 = (m1 % 2 == 0) ? -m1 / 2 : (m1 + 1) / 2;
130
131 for (int iw2l = 0; iw2l < col_indexes.size(); iw2l += npol)
132 {
133 const int iw2 = col_indexes[iw2l] / npol;
134 const int L2 = atom2.iw2l[iw2];
135 const int N2 = atom2.iw2n[iw2];
136 const int m2 = atom2.iw2m[iw2];
137 const int M2 = (m2 % 2 == 0) ? -m2 / 2 : (m2 + 1) / 2;
138
139 // Calculate integral and its gradient using provided functor
140 integral_calculator(T1, L1, N1, M1, T2, L2, N2, M2, dtau, olm);
141
142 // only charge should be considered
143 const double dm_current = dm_pointer[0];
144
145 // Calculate force contribution with compile-time sign
146 if (cal_force)
147 {
148 // Factor of 2 for Hermitian matrix will be applied later
149 for (int i = 0; i < 3; i++)
150 {
151 force_tmp1[i] += ForceSign * dm_current * olm[i + 1];
152 force_tmp2[i] -= ForceSign * dm_current * olm[i + 1];
153 }
154 }
155
156 // Calculate stress contribution with compile-time sign
157 if (cal_stress)
158 {
159 stress_local[0] += StressSign * dm_current * olm[1] * dtau.x; // xx
160 stress_local[1] += StressSign * dm_current * olm[1] * dtau.y; // xy
161 stress_local[2] += StressSign * dm_current * olm[1] * dtau.z; // xz
162 stress_local[3] += StressSign * dm_current * olm[2] * dtau.y; // yy
163 stress_local[4] += StressSign * dm_current * olm[2] * dtau.z; // yz
164 stress_local[5] += StressSign * dm_current * olm[3] * dtau.z; // zz
165 }
166
167 dm_pointer += npol;
168 }
169 dm_pointer += (npol - 1) * col_indexes.size();
170 }
171 }
172 }
173
174 #pragma omp critical
175 {
176 if (cal_force)
177 {
178 force += force_local;
179 }
180 if (cal_stress)
181 {
182 for (int i = 0; i < 6; i++)
183 {
184 stress_tmp[i] += stress_local[i];
185 }
186 }
187 }
188 }
189
190 // Finalize with MPI reduction and post-processing
191 finalize_force_stress(cal_force, cal_stress, ucell, stress_tmp, force, stress, 1.0, 1.0);
192}
193
194} // namespace OperatorForceStress
195
196#endif // OPERATOR_FORCE_STRESS_UTILS_HPP
const std::complex< double > i
Definition cal_pLpR.cpp:46
Definition sltk_grid_driver.h:17
int adj_num
Definition sltk_grid_driver.h:22
std::vector< ModuleBase::Vector3< int > > box
Definition sltk_grid_driver.h:26
std::vector< int > ntype
Definition sltk_grid_driver.h:23
std::vector< int > natom
Definition sltk_grid_driver.h:24
Definition atom_spec.h:6
std::vector< int > iw2m
Definition atom_spec.h:17
std::vector< int > iw2l
Definition atom_spec.h:19
std::vector< int > iw2n
Definition atom_spec.h:18
Definition sltk_grid_driver.h:40
void Find_atom(const UnitCell &ucell, const int ntype, const int nnumber, AdjacentAtomInfo *adjs=nullptr) const
Definition sltk_grid_driver.cpp:25
3 elements vector
Definition vector3.h:24
T x
Definition vector3.h:26
T norm(void) const
Get the norm of a Vector3.
Definition vector3.h:216
T y
Definition vector3.h:27
T z
Definition vector3.h:28
Definition matrix.h:18
void zero_out(void)
Definition matrix.cpp:296
int nr
Definition matrix.h:22
int nc
Definition matrix.h:23
Definition parallel_orbitals.h:9
std::vector< int > get_indexes_col() const
Definition parallel_orbitals.cpp:154
std::vector< int > get_indexes_row() const
gather global indexes of orbitals in this processor get_indexes_row() : global indexes (~NLOCAL) of r...
Definition parallel_orbitals.cpp:140
Definition unitcell.h:15
Atom * atoms
Definition unitcell.h:45
const int & get_npol() const
Definition unitcell.h:104
const ModuleBase::Vector3< double > & get_tau(const int &iat) const
Definition unitcell.h:177
double & lat0
Definition unitcell.h:56
ModuleBase::IntArray & itia2iat
Definition unitcell.h:79
int & nat
Definition unitcell.h:74
const ModuleBase::Vector3< double > cal_dtau(const int &iat1, const int &iat2, const ModuleBase::Vector3< int > &R) const
Definition unitcell.h:183
bool iat2iait(const Tiat iat, Tiait *ia, Tiait *it) const
Definition unitcell.h:117
Definition base_matrix.h:20
T * get_pointer() const
get pointer of value from a submatrix
Definition base_matrix.h:86
Definition hcontainer.h:144
BaseMatrix< T > * find_matrix(int i, int j, int rx, int ry, int rz)
find BaseMatrix with atom index atom_i and atom_j and R index (rx, ry, rz) This interface can be used...
Definition hcontainer.cpp:286
Definition operator_force_stress_utils.cpp:4
void cal_force_stress_2center(const bool cal_force, const bool cal_stress, const hamilt::HContainer< double > *dmR, const UnitCell *ucell, const Grid_Driver *gridD, const std::vector< double > &orb_cutoff, const Parallel_Orbitals *paraV, IntegralFunc &integral_calculator, ModuleBase::matrix &force, ModuleBase::matrix &stress)
Template function for calculating force and stress from 2-center integrals.
Definition operator_force_stress_utils.hpp:38
void finalize_force_stress(bool cal_force, bool cal_stress, const UnitCell *ucell, const std::vector< double > &stress_tmp, ModuleBase::matrix &force, ModuleBase::matrix &stress, double force_factor, double stress_factor)
Finalize force and stress calculations with MPI reduction and post-processing.
Definition operator_force_stress_utils.cpp:6