|
1 | 1 | #include "ifc_derivative.h" |
| 2 | +#include <boost/sort/block_indirect_sort/block_indirect_sort.hpp> |
2 | 3 | #include <cstdlib> |
3 | 4 | #include <iomanip> |
4 | 5 | #include <iostream> |
5 | 6 | #include <sstream> |
| 7 | +#include "anharmonic_core.h" |
6 | 8 | #include "constants.h" |
| 9 | +#include "dynamical.h" |
7 | 10 | #include "error.h" |
8 | 11 | #include "mpi_common.h" |
| 12 | +#include "scph.h" |
9 | 13 | #include "system.h" |
10 | 14 |
|
11 | 15 | using namespace PHON_NS; |
@@ -141,6 +145,320 @@ bool are_same_fcs_array_with_cell_verbose(const std::vector<FcsArrayWithCell> &l |
141 | 145 | DerivativeIFC::DerivativeIFC(PHON *phon): Pointers(phon) |
142 | 146 | {} |
143 | 147 |
|
| 148 | +void DerivativeIFC::compute_del_v1_del_umn(std::complex<double> **del_v1_del_umn, |
| 149 | + const std::complex<double> *const *const *const evec_harmonic) const |
| 150 | +{ |
| 151 | + const auto natmin = system->get_primcell().number_of_atoms; |
| 152 | + const auto ns = dynamical->neval; |
| 153 | + const auto invsqrt_mass = system->get_invsqrt_mass(); |
| 154 | + Eigen::MatrixXd del_v1_del_umn_in_real_space(9, ns); |
| 155 | + |
| 156 | + int ixyz1; |
| 157 | + |
| 158 | + del_v1_del_umn_in_real_space.setZero(); |
| 159 | + |
| 160 | + for (const auto &it: fcs_phonon->force_constant_with_cell[0]) { |
| 161 | + const int ind1 = it.pairs[0].index; |
| 162 | + for (ixyz1 = 0; ixyz1 < 3; ixyz1++) { |
| 163 | + del_v1_del_umn_in_real_space(it.coords[1] * 3 + ixyz1, ind1) += it.fcs_val * it.relvecs_velocity[0][ixyz1]; |
| 164 | + } |
| 165 | + } |
| 166 | + |
| 167 | + for (int ixyz = 0; ixyz < 9; ixyz++) { |
| 168 | + for (int is1 = 0; is1 < ns; is1++) { |
| 169 | + del_v1_del_umn[ixyz][is1] = 0.0; |
| 170 | + for (int i = 0; i < natmin; i++) { |
| 171 | + for (ixyz1 = 0; ixyz1 < 3; ixyz1++) { |
| 172 | + del_v1_del_umn[ixyz][is1] += evec_harmonic[0][is1][i * 3 + ixyz1] * invsqrt_mass[i] * |
| 173 | + del_v1_del_umn_in_real_space(ixyz, i * 3 + ixyz1); |
| 174 | + } |
| 175 | + } |
| 176 | + } |
| 177 | + } |
| 178 | +} |
| 179 | + |
| 180 | +void DerivativeIFC::compute_del2_v1_del_umn2(std::complex<double> **del2_v1_del_umn2, |
| 181 | + const std::complex<double> *const *const *const evec_harmonic) const |
| 182 | +{ |
| 183 | + const auto natmin = system->get_primcell().number_of_atoms; |
| 184 | + const auto ns = dynamical->neval; |
| 185 | + const auto invsqrt_mass = system->get_invsqrt_mass(); |
| 186 | + Eigen::MatrixXd del2_v1_del_umn2_in_real_space(81, ns); |
| 187 | + |
| 188 | + int ixyz1; |
| 189 | + |
| 190 | + del2_v1_del_umn2_in_real_space.setZero(); |
| 191 | + |
| 192 | + for (auto &it: fcs_phonon->force_constant_with_cell[1]) { |
| 193 | + |
| 194 | + const int ind1 = it.pairs[0].index; |
| 195 | + |
| 196 | + for (ixyz1 = 0; ixyz1 < 3; ixyz1++) { |
| 197 | + for (int ixyz2 = 0; ixyz2 < 3; ixyz2++) { |
| 198 | + int const ixyz_comb = it.coords[1] * 27 + ixyz1 * 9 + it.coords[2] * 3 + ixyz2; |
| 199 | + del2_v1_del_umn2_in_real_space(ixyz_comb, ind1) += |
| 200 | + it.fcs_val * it.relvecs_velocity[0][ixyz1] * it.relvecs_velocity[1][ixyz2]; |
| 201 | + } |
| 202 | + } |
| 203 | + } |
| 204 | + |
| 205 | + for (int ixyz = 0; ixyz < 81; ixyz++) { |
| 206 | + for (int is1 = 0; is1 < ns; is1++) { |
| 207 | + del2_v1_del_umn2[ixyz][is1] = 0.0; |
| 208 | + for (int i = 0; i < natmin; i++) { |
| 209 | + for (ixyz1 = 0; ixyz1 < 3; ixyz1++) { |
| 210 | + del2_v1_del_umn2[ixyz][is1] += evec_harmonic[0][is1][i * 3 + ixyz1] * invsqrt_mass[i] * |
| 211 | + del2_v1_del_umn2_in_real_space(ixyz, i * 3 + ixyz1); |
| 212 | + } |
| 213 | + } |
| 214 | + } |
| 215 | + } |
| 216 | +} |
| 217 | + |
| 218 | +void DerivativeIFC::compute_del3_v1_del_umn3(std::complex<double> **del3_v1_del_umn3, |
| 219 | + const std::complex<double> *const *const *const evec_harmonic) const |
| 220 | +{ |
| 221 | + const auto natmin = system->get_primcell().number_of_atoms; |
| 222 | + const auto ns = dynamical->neval; |
| 223 | + const auto invsqrt_mass = system->get_invsqrt_mass(); |
| 224 | + Eigen::MatrixXd del3_v1_del_umn3_in_real_space(729, ns); |
| 225 | + |
| 226 | + int ixyz1; |
| 227 | + |
| 228 | + del3_v1_del_umn3_in_real_space.setZero(); |
| 229 | + |
| 230 | + for (auto &it: fcs_phonon->force_constant_with_cell[2]) { |
| 231 | + |
| 232 | + int ind1 = it.pairs[0].index; |
| 233 | + |
| 234 | + for (ixyz1 = 0; ixyz1 < 3; ixyz1++) { |
| 235 | + for (int ixyz2 = 0; ixyz2 < 3; ixyz2++) { |
| 236 | + for (int ixyz3 = 0; ixyz3 < 3; ixyz3++) { |
| 237 | + const int ixyz_comb = |
| 238 | + it.coords[1] * 243 + ixyz1 * 81 + it.coords[2] * 27 + ixyz2 * 9 + it.coords[3] * 3 + ixyz3; |
| 239 | + del3_v1_del_umn3_in_real_space(ixyz_comb, ind1) += it.fcs_val * it.relvecs_velocity[0][ixyz1] * |
| 240 | + it.relvecs_velocity[1][ixyz2] * |
| 241 | + it.relvecs_velocity[2][ixyz3]; |
| 242 | + } |
| 243 | + } |
| 244 | + } |
| 245 | + } |
| 246 | + |
| 247 | + for (int ixyz = 0; ixyz < 729; ixyz++) { |
| 248 | + for (int is1 = 0; is1 < ns; is1++) { |
| 249 | + del3_v1_del_umn3[ixyz][is1] = 0.0; |
| 250 | + for (int i = 0; i < natmin; i++) { |
| 251 | + for (ixyz1 = 0; ixyz1 < 3; ixyz1++) { |
| 252 | + del3_v1_del_umn3[ixyz][is1] += evec_harmonic[0][is1][i * 3 + ixyz1] * invsqrt_mass[i] * |
| 253 | + del3_v1_del_umn3_in_real_space(ixyz, i * 3 + ixyz1); |
| 254 | + } |
| 255 | + } |
| 256 | + } |
| 257 | + } |
| 258 | +} |
| 259 | + |
| 260 | +void DerivativeIFC::compute_del_v2_del_umn(std::complex<double> ***del_v2_del_umn, |
| 261 | + const std::complex<double> *const *const *const evec_harmonic, |
| 262 | + const unsigned int nk, |
| 263 | + double **xk_in) const |
| 264 | +{ |
| 265 | + using namespace Eigen; |
| 266 | + |
| 267 | + const auto ns = dynamical->neval; |
| 268 | + int is1, is2; |
| 269 | + |
| 270 | + std::vector<FcsArrayWithCell> delta_fcs; |
| 271 | + |
| 272 | + std::complex<double> **mat_tmp; |
| 273 | + allocate(mat_tmp, ns, ns); |
| 274 | + |
| 275 | + MatrixXcd Dymat(ns, ns); |
| 276 | + MatrixXcd evec_tmp(ns, ns); |
| 277 | + |
| 278 | + std::vector<FcsArrayWithCell> fcs_aligned; |
| 279 | + |
| 280 | + fcs_aligned.clear(); |
| 281 | + |
| 282 | + for (const auto &it: fcs_phonon->force_constant_with_cell[1]) { |
| 283 | + fcs_aligned.emplace_back(it); |
| 284 | + } |
| 285 | + sort_by_heading_indices const operator_fcs(1); |
| 286 | + boost::sort::block_indirect_sort(fcs_aligned.begin(), fcs_aligned.end(), operator_fcs); |
| 287 | + |
| 288 | + for (int ixyz1 = 0; ixyz1 < 3; ixyz1++) { |
| 289 | + for (int ixyz2 = 0; ixyz2 < 3; ixyz2++) { |
| 290 | + compute_del_v_strain_in_real_space1(fcs_aligned, delta_fcs, ixyz1, ixyz2); |
| 291 | + |
| 292 | + for (int ik = 0; ik < nk; ik++) { |
| 293 | + |
| 294 | + dynamical->calc_analytic_k(xk_in[ik], delta_fcs, mat_tmp); |
| 295 | + |
| 296 | + for (is1 = 0; is1 < ns; is1++) { |
| 297 | + for (is2 = 0; is2 < ns; is2++) { |
| 298 | + Dymat(is1, is2) = mat_tmp[is1][is2]; |
| 299 | + evec_tmp(is1, is2) = evec_harmonic[ik][is2][is1]; |
| 300 | + } |
| 301 | + } |
| 302 | + Dymat = evec_tmp.adjoint() * Dymat * evec_tmp; |
| 303 | + |
| 304 | + for (is1 = 0; is1 < ns; is1++) { |
| 305 | + for (is2 = 0; is2 < ns; is2++) { |
| 306 | + del_v2_del_umn[ixyz1 * 3 + ixyz2][ik][is1 * ns + is2] = Dymat(is1, is2); |
| 307 | + } |
| 308 | + } |
| 309 | + } |
| 310 | + } |
| 311 | + } |
| 312 | + |
| 313 | + deallocate(mat_tmp); |
| 314 | +} |
| 315 | + |
| 316 | +void DerivativeIFC::compute_del2_v2_del_umn2(std::complex<double> ***del2_v2_del_umn2, |
| 317 | + const std::complex<double> *const *const *const evec_harmonic, |
| 318 | + const unsigned int nk, |
| 319 | + double **xk_in) const |
| 320 | +{ |
| 321 | + using namespace Eigen; |
| 322 | + |
| 323 | + const auto ns = dynamical->neval; |
| 324 | + |
| 325 | + std::vector<FcsArrayWithCell> fcs_aligned; |
| 326 | + fcs_aligned.clear(); |
| 327 | + for (const auto &it: fcs_phonon->force_constant_with_cell[2]) { |
| 328 | + fcs_aligned.emplace_back(it); |
| 329 | + } |
| 330 | + sort_by_heading_indices const operator_fcs(2); |
| 331 | + boost::sort::block_indirect_sort(fcs_aligned.begin(), fcs_aligned.end(), operator_fcs); |
| 332 | + |
| 333 | +#pragma omp parallel |
| 334 | + { |
| 335 | + int ixyz; |
| 336 | + int is1, is2; |
| 337 | + std::vector<FcsArrayWithCell> delta_fcs; |
| 338 | + |
| 339 | + std::complex<double> **mat_tmp; |
| 340 | + allocate(mat_tmp, ns, ns); |
| 341 | + |
| 342 | + MatrixXcd Dymat(ns, ns); |
| 343 | + MatrixXcd evec_tmp(ns, ns); |
| 344 | + |
| 345 | +#pragma omp for |
| 346 | + for (ixyz = 0; ixyz < 81; ixyz++) { |
| 347 | + int itmp = ixyz; |
| 348 | + const int ixyz22 = itmp % 3; |
| 349 | + itmp /= 3; |
| 350 | + const int ixyz21 = itmp % 3; |
| 351 | + itmp /= 3; |
| 352 | + const int ixyz12 = itmp % 3; |
| 353 | + const int ixyz11 = itmp / 3; |
| 354 | + |
| 355 | + compute_del_v_strain_in_real_space2(fcs_aligned, delta_fcs, ixyz11, ixyz12, ixyz21, ixyz22); |
| 356 | + |
| 357 | + for (int ik = 0; ik < nk; ik++) { |
| 358 | + dynamical->calc_analytic_k(xk_in[ik], delta_fcs, mat_tmp); |
| 359 | + |
| 360 | + for (is1 = 0; is1 < ns; is1++) { |
| 361 | + for (is2 = 0; is2 < ns; is2++) { |
| 362 | + Dymat(is1, is2) = mat_tmp[is1][is2]; |
| 363 | + evec_tmp(is1, is2) = evec_harmonic[ik][is2][is1]; |
| 364 | + } |
| 365 | + } |
| 366 | + Dymat = evec_tmp.adjoint() * Dymat * evec_tmp; |
| 367 | + |
| 368 | + for (is1 = 0; is1 < ns; is1++) { |
| 369 | + for (is2 = 0; is2 < ns; is2++) { |
| 370 | + del2_v2_del_umn2[ixyz][ik][is1 * ns + is2] = Dymat(is1, is2); |
| 371 | + } |
| 372 | + } |
| 373 | + } |
| 374 | + } |
| 375 | + |
| 376 | + deallocate(mat_tmp); |
| 377 | + } |
| 378 | +} |
| 379 | + |
| 380 | +void DerivativeIFC::compute_del_v3_del_umn(std::complex<double> ****del_v3_del_umn, |
| 381 | + double **omega2_harmonic, |
| 382 | + const std::complex<double> *const *const *const evec_harmonic, |
| 383 | + const KpointMeshUniform *kmesh_coarse_in, |
| 384 | + const KpointMeshUniform *kmesh_dense_in, |
| 385 | + const PhaseFactorStorage *phase_storage_in) const |
| 386 | +{ |
| 387 | + int ngroup_tmp; |
| 388 | + double *invmass_v3_tmp; |
| 389 | + int **evec_index_v3_tmp; |
| 390 | + std::vector<double> *fcs_group_tmp; |
| 391 | + std::vector<RelativeVector> *relvec_tmp; |
| 392 | + std::complex<double> *phi3_reciprocal_tmp; |
| 393 | + |
| 394 | + int i; |
| 395 | + int ixyz1, ixyz2; |
| 396 | + |
| 397 | + double *invsqrt_mass_p; |
| 398 | + allocate(invsqrt_mass_p, system->get_primcell().number_of_atoms); |
| 399 | + for (i = 0; i < system->get_primcell().number_of_atoms; ++i) { |
| 400 | + invsqrt_mass_p[i] = std::sqrt(1.0 / system->get_mass_prim()[i]); |
| 401 | + } |
| 402 | + |
| 403 | + std::vector<FcsArrayWithCell> delta_fcs; |
| 404 | + std::vector<FcsArrayWithCell> fcs_aligned; |
| 405 | + fcs_aligned.clear(); |
| 406 | + for (const auto &it: fcs_phonon->force_constant_with_cell[2]) { |
| 407 | + fcs_aligned.emplace_back(it); |
| 408 | + } |
| 409 | + const sort_by_heading_indices operator_fcs(1); |
| 410 | + boost::sort::block_indirect_sort(fcs_aligned.begin(), fcs_aligned.end(), operator_fcs); |
| 411 | + |
| 412 | + for (ixyz1 = 0; ixyz1 < 3; ixyz1++) { |
| 413 | + for (ixyz2 = 0; ixyz2 < 3; ixyz2++) { |
| 414 | + |
| 415 | + compute_del_v_strain_in_real_space1(fcs_aligned, delta_fcs, ixyz1, ixyz2); |
| 416 | + |
| 417 | + boost::sort::block_indirect_sort(delta_fcs.begin(), delta_fcs.end()); |
| 418 | + |
| 419 | + anharmonic_core->prepare_group_of_force_constants(delta_fcs, ngroup_tmp, fcs_group_tmp); |
| 420 | + |
| 421 | + allocate(invmass_v3_tmp, ngroup_tmp); |
| 422 | + allocate(evec_index_v3_tmp, ngroup_tmp, 3); |
| 423 | + allocate(relvec_tmp, ngroup_tmp); |
| 424 | + allocate(phi3_reciprocal_tmp, ngroup_tmp); |
| 425 | + |
| 426 | + anharmonic_core->prepare_relative_vector(delta_fcs, ngroup_tmp, fcs_group_tmp, relvec_tmp); |
| 427 | + |
| 428 | + int k = 0; |
| 429 | + for (i = 0; i < ngroup_tmp; ++i) { |
| 430 | + for (int j = 0; j < 3; ++j) { |
| 431 | + evec_index_v3_tmp[i][j] = delta_fcs[k].pairs[j].index; |
| 432 | + } |
| 433 | + invmass_v3_tmp[i] = invsqrt_mass_p[evec_index_v3_tmp[i][0] / 3] * |
| 434 | + invsqrt_mass_p[evec_index_v3_tmp[i][1] / 3] * |
| 435 | + invsqrt_mass_p[evec_index_v3_tmp[i][2] / 3]; |
| 436 | + k += fcs_group_tmp[i].size(); |
| 437 | + } |
| 438 | + |
| 439 | + scph->compute_V3_elements_for_given_IFCs(del_v3_del_umn[ixyz1 * 3 + ixyz2], |
| 440 | + omega2_harmonic, |
| 441 | + ngroup_tmp, |
| 442 | + fcs_group_tmp, |
| 443 | + relvec_tmp, |
| 444 | + invmass_v3_tmp, |
| 445 | + evec_index_v3_tmp, |
| 446 | + evec_harmonic, |
| 447 | + true, |
| 448 | + kmesh_coarse_in, |
| 449 | + kmesh_dense_in, |
| 450 | + phase_storage_in); |
| 451 | + |
| 452 | + deallocate(fcs_group_tmp); |
| 453 | + deallocate(invmass_v3_tmp); |
| 454 | + deallocate(evec_index_v3_tmp); |
| 455 | + deallocate(relvec_tmp); |
| 456 | + deallocate(phi3_reciprocal_tmp); |
| 457 | + } |
| 458 | + } |
| 459 | + deallocate(invsqrt_mass_p); |
| 460 | +} |
| 461 | + |
144 | 462 | bool DerivativeIFC::check_del_v_strain_in_real_space_equivalence( |
145 | 463 | const std::vector<FcsArrayWithCell> &fcs_aligned, |
146 | 464 | const std::vector<std::pair<int, int>> &strain_components) const |
|
0 commit comments