152 {
153 const int nat = static_cast<int>(pos.size()) / 3;
154 const double alpha = A > 0.0 ? A : 1.0;
155 const double scale = mu > 0.0 ? mu : 1.0;
156 const double r_bond = std::min(rcut, 1.35 * r_nn);
157 const double r_cov = 0.5 * r_nn;
158 auto mic = [&](int i, int j) {
159 Eigen::Vector3d dr = pos.segment<3>(3 * i) - pos.segment<3>(3 * j);
161 return dr;
162 };
163 std::vector<std::vector<int>> nb(static_cast<size_t>(nat));
164 const double r_pair = (kind == "swart") ? rcut : r_bond;
165 for (int i = 0; i < nat; ++i) {
166 for (int j = i + 1; j < nat; ++j) {
167 const Eigen::Vector3d rij = mic(i, j);
168 const double r = rij.norm();
169 if (r >= r_pair || r < 1.0e-14) {
170 continue;
171 }
172 double k = 0.0;
173 if (kind == "schlegel") {
174 const double den = std::max(r - 0.45 * r_nn, 0.15);
175 k = scale * 1.734 / (den * den * den);
176 } else if (kind == "fischer") {
177 k = scale * 0.3601 * std::exp(-1.944 * (r - r_cov));
178 } else {
179 k = scale *
lindhRho(r, r_nn, alpha);
180 if (kind == "swart") {
182 }
183 }
185 if (r < r_bond) {
186 nb[static_cast<size_t>(i)].push_back(j);
187 nb[static_cast<size_t>(j)].push_back(i);
188 }
189 }
190 }
191 for (int j = 0; j < nat; ++j) {
192 const auto &nbr = nb[static_cast<size_t>(j)];
193 for (size_t a = 0; a < nbr.size(); ++a) {
194 for (size_t b = a + 1; b < nbr.size(); ++b) {
195 const int i = nbr[a];
196 const int k = nbr[b];
197 const Eigen::Vector3d ri = pos.segment<3>(3 * i);
198 const Eigen::Vector3d rj = pos.segment<3>(3 * j);
199 const Eigen::Vector3d rk = pos.segment<3>(3 * k);
200 Eigen::Vector3d g[3];
201 Eigen::Vector3d rji = ri - rj;
202 Eigen::Vector3d rjk = rk - rj;
206 continue;
207 }
208 const double rij = rji.norm();
209 const double rkj = rjk.norm();
210 double kang = 0.16 * scale;
211 if (kind == "fischer") {
212 kang = scale * (0.089 + 0.11 *
213 std::pow(r_cov * r_cov, -0.42) *
214 std::exp(-0.44 * ((rij - r_cov) +
215 (rkj - r_cov))));
216 } else if (kind == "lindh_full" || kind == "swart") {
217 kang = 0.15 * scale *
lindhRho(rij, r_nn, alpha) *
219 if (kind == "swart") {
221 }
222 }
223 const int atoms[3] = {i, j, k};
225 }
226 }
227 }
228 for (int j = 0; j < nat; ++j) {
229 const auto &nj = nb[static_cast<size_t>(j)];
230 for (int k : nj) {
231 if (k <= j) {
232 continue;
233 }
234 const auto &nk = nb[static_cast<size_t>(k)];
235 for (int i : nj) {
236 if (i == k) {
237 continue;
238 }
239 for (int l : nk) {
240 if (l == j || l == i) {
241 continue;
242 }
243 Eigen::Vector3d rijv = pos.segment<3>(3 * i) - pos.segment<3>(3 * j);
244 Eigen::Vector3d rkjv = pos.segment<3>(3 * k) - pos.segment<3>(3 * j);
245 Eigen::Vector3d rklv = pos.segment<3>(3 * k) - pos.segment<3>(3 * l);
249 const Eigen::Vector3d rj = pos.segment<3>(3 * j);
250 Eigen::Vector3d g[4];
251 if (!
torsionGrads(rj + rijv, rj, rj + rkjv, rj + rkjv - rklv, g)) {
252 continue;
253 }
254 const double rij = rijv.norm();
255 const double rjk = rkjv.norm();
256 const double rkl = rklv.norm();
257 double ktor = 0.01 * scale;
258 if (kind == "fischer") {
259 ktor = 0.0015 * scale;
260 } else if (kind == "lindh_full" || kind == "swart") {
261 ktor = 0.005 * scale *
lindhRho(rij, r_nn, alpha) *
263 if (kind == "swart") {
266 }
267 }
268 const int atoms[4] = {i, j, k, l};
270 }
271 }
272 }
273 }
274}
virtual void minimumImage(Eigen::Ref< Eigen::Vector3d >) const
bool angleGrads(const Eigen::Vector3d &ri, const Eigen::Vector3d &rj, const Eigen::Vector3d &rk, Eigen::Vector3d g[3])
Wilson (B) rows for the valence angle (i{-}j{-}k) ((j) central).
double lindhRho(double r, double r_nn, double alpha)
void addPairBlock(Eigen::MatrixXd &P, int i, int j, const Eigen::Vector3d &rij, double k_par, double k_perp)
bool torsionGrads(const Eigen::Vector3d &ri, const Eigen::Vector3d &rj, const Eigen::Vector3d &rk, const Eigen::Vector3d &rl, Eigen::Vector3d g[4])
Wilson (B) rows for the torsion (i{-}j{-}k{-}l).
void addScalarInternal(Eigen::MatrixXd &P, const int *atoms, const Eigen::Vector3d *g, int n_atoms, double k)
Rank-1 update (k\,(\nabla q)(\nabla q)^\top) for a scalar internal.
double swartScreen(double r, double r_nn)