58 const std::string& dispersion_correction =
"none",
59 bool disable_symmetry =
false) {
64 int number_of_atoms = crystal_structure.number_of_atoms();
68 auto ewald_forces = ewald_calculator.
compute();
76 auto dispersion_calculator =
78 std::vector<Vector3D> dispersion_forces = dispersion_calculator->compute_gradients().forces;
79 bool has_dispersion = dispersion_calculator->name() !=
"none";
87 projector_overlap_coefficients);
88 auto pseudopotential_contributions = pseudopotential_calculator.
compute();
104 auto reduce_kpoint_dependent_force = [&](std::vector<Vector3D>& force) {
105 std::vector<Real> flat;
106 flat.reserve(
static_cast<std::size_t
>(number_of_atoms * 3));
107 for (
const auto& value : force) {
108 flat.push_back(value.x);
109 flat.push_back(value.y);
110 flat.push_back(value.z);
113 for (
int atom_index = 0; atom_index < number_of_atoms; ++atom_index) {
114 force[atom_index].x = flat[
static_cast<std::size_t
>(atom_index * 3)];
115 force[atom_index].y = flat[
static_cast<std::size_t
>(atom_index * 3 + 1)];
116 force[atom_index].z = flat[
static_cast<std::size_t
>(atom_index * 3 + 2)];
119 reduce_kpoint_dependent_force(pseudopotential_contributions.nonlocal);
121 reduce_kpoint_dependent_force(pseudopotential_contributions.hubbard);
125 return assemble_total(
128 pseudopotential_contributions.local,
130 pseudopotential_contributions.nonlocal,
131 pseudopotential_contributions.core_correction,
132 pseudopotential_contributions.augmentation,
134 pseudopotential_contributions.hubbard,
144 assemble_total(
const Crystal& crystal_structure,
146 const std::vector<Vector3D>& local_forces,
147 const std::vector<Vector3D>& ewald_forces,
148 const std::vector<Vector3D>& nonlocal_forces,
149 const std::vector<Vector3D>& core_correction_forces,
150 const std::vector<Vector3D>& augmentation_forces,
151 const std::vector<Vector3D>& dispersion_forces,
152 const std::vector<Vector3D>& hubbard_forces,
153 bool has_nonlinear_core_correction,
154 bool has_augmentation,
157 bool disable_symmetry) {
158 std::vector<Vector3D> total_forces(number_of_atoms, {0.0, 0.0, 0.0});
159 for (
int atom_index = 0; atom_index < number_of_atoms; atom_index++) {
160 for (
int direction = 0; direction < 3; direction++) {
161 total_forces[atom_index][direction] =
162 local_forces[atom_index][direction] + ewald_forces[atom_index][direction] +
163 nonlocal_forces[atom_index][direction] +
164 core_correction_forces[atom_index][direction] +
165 augmentation_forces[atom_index][direction] +
166 dispersion_forces[atom_index][direction] +
167 hubbard_forces[atom_index][direction];
171 if (!disable_symmetry) {
173 if (symmetry_operations.size() > 1) {
175 crystal_structure, symmetry_operations, total_forces);
180 for (
int atom_index = 0; atom_index < number_of_atoms; atom_index++) {
181 log::info(
" atom {:3d} ({:2s}): {:12.8f} {:12.8f} {:12.8f}",
185 total_forces[atom_index].x,
186 total_forces[atom_index].y,
187 total_forces[atom_index].z);
191 log::info(
" Force contributions per atom (Ry/bohr):");
192 for (
int atom_index = 0; atom_index < number_of_atoms; atom_index++) {
193 log::info(
" atom {:2d} local: {:12.8f} {:12.8f} {:12.8f}",
195 local_forces[atom_index].x,
196 local_forces[atom_index].y,
197 local_forces[atom_index].z);
198 log::info(
" atom {:2d} Ewald: {:12.8f} {:12.8f} {:12.8f}",
200 ewald_forces[atom_index].x,
201 ewald_forces[atom_index].y,
202 ewald_forces[atom_index].z);
203 log::info(
" atom {:2d} nonlocal: {:12.8f} {:12.8f} {:12.8f}",
205 nonlocal_forces[atom_index].x,
206 nonlocal_forces[atom_index].y,
207 nonlocal_forces[atom_index].z);
208 log::info(
" atom {:2d} NLCC: {:12.8f} {:12.8f} {:12.8f}",
210 core_correction_forces[atom_index].x,
211 core_correction_forces[atom_index].y,
212 core_correction_forces[atom_index].z);
213 if (has_dispersion) {
214 log::info(
" atom {:2d} disp: {:12.8f} {:12.8f} {:12.8f}",
216 dispersion_forces[atom_index].x,
217 dispersion_forces[atom_index].y,
218 dispersion_forces[atom_index].z);
221 log::info(
" atom {:2d} hubbard: {:12.8f} {:12.8f} {:12.8f}",
223 hubbard_forces[atom_index].x,
224 hubbard_forces[atom_index].y,
225 hubbard_forces[atom_index].z);
229 log::info(
" Force contributions (diagonal RMS, Ry/bohr):");
230 auto compute_root_mean_square = [&](
const std::vector<Vector3D>& forces_vector) ->
Real {
231 Real sum_squared = 0.0;
232 for (
int atom_index = 0; atom_index < number_of_atoms; atom_index++) {
233 sum_squared += forces_vector[atom_index].x * forces_vector[atom_index].x +
234 forces_vector[atom_index].y * forces_vector[atom_index].y +
235 forces_vector[atom_index].z * forces_vector[atom_index].z;
237 return std::sqrt(sum_squared / (3.0 * number_of_atoms +
240 log::info(
" local: {:.8f}", compute_root_mean_square(local_forces));
241 log::info(
" Ewald: {:.8f}", compute_root_mean_square(ewald_forces));
242 log::info(
" nonlocal: {:.8f}", compute_root_mean_square(nonlocal_forces));
243 if (has_nonlinear_core_correction) {
244 log::info(
" NLCC: {:.8f}", compute_root_mean_square(core_correction_forces));
246 if (has_augmentation) {
247 log::info(
" augment: {:.8f}", compute_root_mean_square(augmentation_forces));
249 if (has_dispersion) {
250 log::info(
" disp: {:.8f}", compute_root_mean_square(dispersion_forces));
253 log::info(
" hubbard: {:.8f}", compute_root_mean_square(hubbard_forces));
255 log::info(
" TOTAL: {:.8f}", compute_root_mean_square(total_forces));
257 AtomicForcesContributions contributions;
258 contributions.local = local_forces;
259 contributions.ewald = ewald_forces;
260 contributions.nonlocal = nonlocal_forces;
261 contributions.core_correction = core_correction_forces;
262 contributions.augmentation = augmentation_forces;
263 contributions.dispersion = dispersion_forces;
264 contributions.hubbard = hubbard_forces;
266 return {total_forces, contributions};