25#ifndef __LATTICE_RELAXATION_HPP__
26#define __LATTICE_RELAXATION_HPP__
29#if defined(SIRIUS_VCSQNM)
45 nlohmann::json find(
int max_num_steps__,
double forces_thr__ = 1e-4,
double stress_thr__ = -1e-4)
47 nlohmann::json result;
48#if defined(SIRIUS_VCSQNM)
49 bool compute_stress = stress_thr__ > 0;
50 bool compute_forces = forces_thr__ > 0;
52 int na = dft_.
ctx().unit_cell().num_atoms();
54 std::unique_ptr<vcsqnm::PES_optimizer::periodic_optimizer> geom_opt;
55 Eigen::MatrixXd r(3, na);
56 Eigen::MatrixXd f(3, na);
57 Eigen::Vector3d lat_a, lat_b, lat_c;
58 for (
int x = 0; x < 3; x++) {
59 lat_a[x] = dft_.
ctx().unit_cell().lattice_vector(0)[x];
60 lat_b[x] = dft_.
ctx().unit_cell().lattice_vector(1)[x];
61 lat_c[x] = dft_.
ctx().unit_cell().lattice_vector(2)[x];
64 Eigen::Matrix3d stress;
66 for (
int ia = 0; ia < na; ia++) {
67 for (
auto x: {0, 1, 2}) {
68 r(x, ia) = dft_.
ctx().unit_cell().atom(ia).position()[x];
79 auto& inp = dft_.
ctx().cfg().vcsqnm();
80 double initial_step_size = inp.initial_step_size();
81 int nhist_max = inp.nhist_max();
82 double lattice_weight = inp.lattice_weight();
83 double alpha0 = inp.alpha0();
84 double eps_subsp = inp.eps_subsp();
85 if (compute_forces && compute_stress) {
86 geom_opt = std::make_unique<vcsqnm::PES_optimizer::periodic_optimizer>(na, lat_a, lat_b, lat_c,
87 initial_step_size, nhist_max, lattice_weight, alpha0, eps_subsp);
88 }
else if (compute_forces) {
89 geom_opt = std::make_unique<vcsqnm::PES_optimizer::periodic_optimizer>(na, initial_step_size,
90 nhist_max, alpha0, eps_subsp);
93 bool stress_converged{
true};
94 bool forces_converged{
true};
96 for (
int istep = 0; istep < max_num_steps__; istep++) {
97 RTE_OUT(dft_.
ctx().
out()) <<
"optimisation step " << istep + 1 <<
" out of " << max_num_steps__ << std::endl;
99 auto& inp = dft_.
ctx().cfg().parameters();
100 bool write_state{
false};
103 result = dft_.
find(inp.density_tol(), inp.energy_tol(), dft_.
ctx().cfg().iterative_solver().energy_tolerance(),
104 inp.num_dft_iter(), write_state);
108 if (compute_stress) {
109 dft_.stress().calc_stress_total();
110 dft_.stress().print_info(out, dft_.
ctx().verbosity());
112 auto st = dft_.stress().stress_total();
114 for (
int i = 0; i < 3; i++) {
115 for (
int j = 0; j < 3; j++) {
116 stress(i, j) = -st(i, j);
117 d += std::abs(st(i, j));
120 if (d < stress_thr__) {
121 stress_converged =
true;
123 stress_converged =
false;
126 out <<
"total stress value: " << d <<
", stress threshold: " << stress_thr__
127 <<
", converged: " << stress_converged << std::endl;
130 if (compute_forces) {
131 dft_.forces().calc_forces_total();
132 dft_.forces().print_info(out, dft_.
ctx().verbosity());
134 auto& ft = dft_.forces().forces_total();
136 for (
int i = 0; i < dft_.
ctx().unit_cell().num_atoms(); i++) {
137 for (
int x: {0, 1, 2}) {
139 d += std::abs(ft(x, i));
142 if (d < forces_thr__) {
143 forces_converged =
true;
145 forces_converged =
false;
147 out <<
"total forces value: " << d <<
", forces threshold: " << forces_thr__
148 <<
", converged: " << forces_converged << std::endl;
150 auto etot = result[
"energy"][
"total"].get<
double>();
152 if (forces_converged && stress_converged) {
153 out <<
"lattice relaxation is converged in " << istep <<
" steps" << std::endl;
160 if (compute_forces && compute_stress) {
161 geom_opt->step(r, etot, f, lat_a, lat_b, lat_c, stress);
162 }
else if (compute_forces) {
163 geom_opt->step(r, etot, f);
169 ctx.unit_cell().set_lattice_vectors({lat_a[0], lat_a[1], lat_a[2]},
170 {lat_b[0], lat_b[1], lat_b[2]},
171 {lat_c[0], lat_c[1], lat_c[2]});
172 for (
int ia = 0; ia < na; ia++) {
173 ctx.unit_cell().atom(ia).set_position({r(0, ia), r(1, ia), r(2, ia)});
176 ctx.unit_cell().print_geometry_info(out, ctx.verbosity());
178 if (!(forces_converged && stress_converged)) {
179 RTE_OUT(dft_.
ctx().
out()) <<
"lattice relaxation not converged" << std::endl;
182 RTE_THROW(
"not compiled with vcsqnm support");
The whole DFT ground state implementation.
json find(double density_tol, double energy_tol, double initial_tolerance, int num_dft_iter, bool write_state)
Run the SCF ground state calculation and find a total energy minimum.
Simulation_context const & ctx() const
Return reference to a simulation context.
void update()
Update the parameters after the change of lattice vectors or atomic positions.
Simulation context is a set of parameters and objects describing a single simulation.
std::ostream & out() const
Return output stream.
Contains definition and partial implementation of sirius::DFT_ground_state class.
Namespace of the SIRIUS library.
Implementation of the vc-sqnm method. More informations about the algorithm can be found here: https:...