108 const int N_cartesian = 3;
109 const int N_components = 3;
110 const int values_per_atom = N_cartesian * N_components;
112 std::vector<RealType> dipole_gradient(atoms.N * 3 * 3);
116 for (
int i = 0; i < atoms.N; i++) {
122 std::vector<RealType> dipole(3);
123 nep.find_dipole(atoms.type, atoms.cell, atoms.position, dipole);
126 std::vector<RealType> center_of_mass(3);
128 for (
int i = 0; i < 3; i++) {
129 dipole[i] += charge * center_of_mass[i];
133 std::vector<RealType> dipole_forward(3);
137 RealType old_position = 0.0;
138 RealType old_center_of_mass = 0.0;
139 const RealType displacement_over_M = displacement / M;
140 const RealType one_over_displacement = 1.0 / displacement;
142 for (
int i = 0; i < N_cartesian; i++) {
143 for (
int j = 0; j < atoms.N; j++) {
144 index = atoms.N * i + j;
145 old_position = atoms.position[index];
146 atoms.position[index] += displacement;
148 old_center_of_mass = center_of_mass[i];
149 center_of_mass[i] += displacement_over_M * atoms.mass[j];
151 nep.find_dipole(atoms.type, atoms.cell, atoms.position, dipole_forward);
153 for (
int k = 0; k < N_components; k++) {
154 dipole_gradient[i * N_components + j * values_per_atom + k] =
155 ((dipole_forward[k] + charge * center_of_mass[k]) - dipole[k]) *
156 one_over_displacement;
159 atoms.position[index] = old_position;
160 center_of_mass[i] = old_center_of_mass;
163 }
else if (method == 1) {
169 std::vector<RealType> dipole_forward(3);
170 std::vector<RealType> dipole_backward(3);
173 std::vector<RealType> center_of_mass_forward(3);
175 std::vector<RealType> center_of_mass_backward(center_of_mass_forward);
179 RealType old_position = 0.0;
180 RealType old_center_of_mass = 0.0;
181 const RealType displacement_over_M = displacement / M;
182 const RealType one_over_two_displacements = 0.5 / displacement;
184 for (
int i = 0; i < N_cartesian; i++) {
185 for (
int j = 0; j < atoms.N; j++) {
186 index = atoms.N * i + j;
187 old_position = atoms.position[index];
188 old_center_of_mass = center_of_mass_forward[i];
191 atoms.position[index] += displacement;
193 center_of_mass_forward[i] += displacement_over_M * atoms.mass[j];
194 nep.find_dipole(atoms.type, atoms.cell, atoms.position, dipole_forward);
197 atoms.position[index] -= 2 * displacement;
198 center_of_mass_backward[i] -= displacement_over_M * atoms.mass[j];
199 nep.find_dipole(atoms.type, atoms.cell, atoms.position, dipole_backward);
201 for (
int k = 0; k < N_components; k++) {
202 dipole_gradient[i * N_components + j * values_per_atom + k] =
203 ((dipole_forward[k] + charge * center_of_mass_forward[k]) -
204 (dipole_backward[k] + charge * center_of_mass_backward[k])) *
205 one_over_two_displacements;
208 atoms.position[index] = old_position;
209 center_of_mass_forward[i] = old_center_of_mass;
210 center_of_mass_backward[i] = old_center_of_mass;
213 }
else if (method == 2) {
220 std::vector<RealType> dipole_forward_one_h(3);
221 std::vector<RealType> dipole_forward_two_h(3);
222 std::vector<RealType> dipole_backward_one_h(3);
223 std::vector<RealType> dipole_backward_two_h(3);
226 std::vector<RealType> center_of_mass_forward_one_h(3);
228 std::vector<RealType> center_of_mass_forward_two_h(center_of_mass_forward_one_h);
229 std::vector<RealType> center_of_mass_backward_one_h(center_of_mass_forward_one_h);
230 std::vector<RealType> center_of_mass_backward_two_h(center_of_mass_forward_one_h);
234 RealType old_position = 0.0;
235 RealType old_center_of_mass = 0.0;
236 const RealType displacement_over_M = displacement / M;
237 const RealType one_over_displacement =
240 const RealType c0 = -1.0 / 12.0;
241 const RealType c1 = 2.0 / 3.0;
242 for (
int i = 0; i < N_cartesian; i++) {
243 for (
int j = 0; j < atoms.N; j++) {
244 index = atoms.N * i + j;
245 old_position = atoms.position[index];
246 old_center_of_mass = center_of_mass_forward_one_h[i];
250 atoms.position[index] += displacement;
251 center_of_mass_forward_one_h[i] +=
252 displacement_over_M * atoms.mass[j];
254 nep.find_dipole(atoms.type, atoms.cell, atoms.position,
255 dipole_forward_one_h);
257 atoms.position[index] += displacement;
258 center_of_mass_forward_two_h[i] +=
259 2 * displacement_over_M *
262 nep.find_dipole(atoms.type, atoms.cell, atoms.position,
263 dipole_forward_two_h);
266 atoms.position[index] -= 3 * displacement;
267 center_of_mass_backward_one_h[i] -= displacement_over_M * atoms.mass[j];
268 nep.find_dipole(atoms.type, atoms.cell, atoms.position,
269 dipole_backward_one_h);
271 atoms.position[index] -= displacement;
272 center_of_mass_backward_two_h[i] -=
273 2 * displacement_over_M * atoms.mass[j];
274 nep.find_dipole(atoms.type, atoms.cell, atoms.position,
275 dipole_backward_two_h);
277 for (
int k = 0; k < N_components; k++) {
278 dipole_gradient[i * N_components + j * values_per_atom + k] =
279 (c0 * (dipole_forward_two_h[k] +
280 charge * center_of_mass_forward_two_h[k]) +
281 c1 * (dipole_forward_one_h[k] +
282 charge * center_of_mass_forward_one_h[k]) -
283 c1 * (dipole_backward_one_h[k] +
284 charge * center_of_mass_backward_one_h[k]) -
285 c0 * (dipole_backward_two_h[k] +
286 charge * center_of_mass_backward_two_h[k])) *
287 one_over_displacement;
290 atoms.position[index] = old_position;
291 center_of_mass_forward_one_h[i] = old_center_of_mass;
292 center_of_mass_forward_two_h[i] = old_center_of_mass;
293 center_of_mass_backward_one_h[i] = old_center_of_mass;
294 center_of_mass_backward_two_h[i] = old_center_of_mass;
305 return dipole_gradient;
329 const int N_cartesian = 3;
330 const int N_components = 6;
331 std::vector<RealType> polarizability_gradient(atoms.N * N_cartesian * N_components);
339 const int values_per_atom = N_cartesian * N_components;
342 std::vector<RealType> polarizability_forward_one_h(6);
343 std::vector<RealType> polarizability_forward_two_h(6);
344 std::vector<RealType> polarizability_backward_one_h(6);
345 std::vector<RealType> polarizability_backward_two_h(6);
349 RealType old_position = 0.0;
350 const RealType one_over_displacement =
353 const RealType c0 = -1.0 / 12.0;
354 const RealType c1 = 2.0 / 3.0;
355 for (
int i = 0; i < N_cartesian; i++) {
356 if (std::count(components.begin(), components.end(), i) == 0) {
360 for (
int j = 0; j < atoms.N; j++) {
362 index = atoms.N * i + j;
363 old_position = atoms.position[index];
367 atoms.position[index] += displacement;
368 nep.find_polarizability(atoms.type, atoms.cell, atoms.position,
369 polarizability_forward_one_h);
371 atoms.position[index] += displacement;
372 nep.find_polarizability(atoms.type, atoms.cell, atoms.position,
373 polarizability_forward_two_h);
376 atoms.position[index] -= 3 * displacement;
377 nep.find_polarizability(atoms.type, atoms.cell, atoms.position,
378 polarizability_backward_one_h);
380 atoms.position[index] -= displacement;
381 nep.find_polarizability(atoms.type, atoms.cell, atoms.position,
382 polarizability_backward_two_h);
385 for (
int k = 0; k < N_components; k++) {
386 polarizability_gradient[i * N_components + j * values_per_atom + k] =
387 (c0 * polarizability_forward_two_h[k] +
388 c1 * polarizability_forward_one_h[k] -
389 c1 * polarizability_backward_one_h[k] -
390 c0 * polarizability_backward_two_h[k]) *
391 one_over_displacement;
394 atoms.position[index] = old_position;
404 return polarizability_gradient;