mirror of https://github.com/phonopy/phono3py.git
469 lines
16 KiB
C
469 lines
16 KiB
C
/* Copyright (C) 2015 Atsushi Togo */
|
|
/* All rights reserved. */
|
|
|
|
/* This file is part of phonopy. */
|
|
|
|
/* Redistribution and use in source and binary forms, with or without */
|
|
/* modification, are permitted provided that the following conditions */
|
|
/* are met: */
|
|
|
|
/* * Redistributions of source code must retain the above copyright */
|
|
/* notice, this list of conditions and the following disclaimer. */
|
|
|
|
/* * Redistributions in binary form must reproduce the above copyright */
|
|
/* notice, this list of conditions and the following disclaimer in */
|
|
/* the documentation and/or other materials provided with the */
|
|
/* distribution. */
|
|
|
|
/* * Neither the name of the phonopy project nor the names of its */
|
|
/* contributors may be used to endorse or promote products derived */
|
|
/* from this software without specific prior written permission. */
|
|
|
|
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
|
|
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
|
|
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
|
|
/* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE */
|
|
/* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, */
|
|
/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, */
|
|
/* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
|
|
/* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER */
|
|
/* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT */
|
|
/* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN */
|
|
/* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */
|
|
/* POSSIBILITY OF SUCH DAMAGE. */
|
|
|
|
#include "imag_self_energy_with_g.h"
|
|
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "funcs.h"
|
|
#include "lagrid.h"
|
|
#include "phonoc_array.h"
|
|
#include "triplet.h"
|
|
|
|
static long set_g_pos_frequency_point(long (*g_pos)[4], const long num_band0,
|
|
const long num_band, const char *g_zero);
|
|
static void detailed_imag_self_energy_at_triplet(
|
|
double *detailed_imag_self_energy, double *imag_self_energy,
|
|
const long num_band0, const long num_band, const double *fc3_normal_squared,
|
|
const double *frequencies, const long triplet[3], const double *g1,
|
|
const double *g2_3, const char *g_zero, const double *temperatures,
|
|
const long num_temps, const double cutoff_frequency);
|
|
static double collect_detailed_imag_self_energy(
|
|
double *imag_self_energy, const long num_band,
|
|
const double *fc3_normal_squared, const double *n1, const double *n2,
|
|
const double *g1, const double *g2_3, const char *g_zero);
|
|
static double collect_detailed_imag_self_energy_0K(
|
|
double *imag_self_energy, const long num_band,
|
|
const double *fc3_normal_squared, const double *n1, const double *n2,
|
|
const double *g, const char *g_zero);
|
|
static void set_occupations(double *n1, double *n2, const long num_band,
|
|
const double temperature, const long triplet[3],
|
|
const double *frequencies,
|
|
const double cutoff_frequency);
|
|
|
|
void ise_get_imag_self_energy_with_g(
|
|
double *imag_self_energy, const Darray *fc3_normal_squared,
|
|
const double *frequencies, const long (*triplets)[3],
|
|
const long *triplet_weights, const double *g, const char *g_zero,
|
|
const double temperature, const double cutoff_frequency,
|
|
const long num_frequency_points, const long frequency_point_index) {
|
|
long i, j, num_triplets, num_band0, num_band, num_band_prod;
|
|
long num_g_pos, g_index_dims, g_index_shift;
|
|
long(*g_pos)[4];
|
|
double *ise;
|
|
long at_a_frequency_point;
|
|
|
|
g_pos = NULL;
|
|
ise = NULL;
|
|
|
|
num_triplets = fc3_normal_squared->dims[0];
|
|
num_band0 = fc3_normal_squared->dims[1];
|
|
num_band = fc3_normal_squared->dims[2];
|
|
num_band_prod = num_band0 * num_band * num_band;
|
|
ise = (double *)malloc(sizeof(double) * num_triplets * num_band0);
|
|
|
|
/**
|
|
* g has the shape of
|
|
* (num_triplets, num_band0 or num_frequency_points, num_band, num_band)
|
|
*
|
|
* g_index_dims: Stride for 1st dim
|
|
* g_index_shift: Fixed index shift for 2nd dim
|
|
*/
|
|
if (frequency_point_index < 0) {
|
|
/* frequency_points == frequencies at bands */
|
|
at_a_frequency_point = 0;
|
|
g_index_dims = num_band_prod;
|
|
g_index_shift = 0;
|
|
} else {
|
|
/* At an arbitrary frequency point. */
|
|
at_a_frequency_point = 1;
|
|
g_index_dims = num_frequency_points * num_band * num_band;
|
|
g_index_shift = frequency_point_index * num_band * num_band;
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for schedule(guided) private(num_g_pos, g_pos)
|
|
#endif
|
|
for (i = 0; i < num_triplets; i++) {
|
|
/**
|
|
* g_pos contains the indices of g that are known non-zeros in series.
|
|
*
|
|
* ise_set_g_pos works for frquency points as bands.
|
|
* set_g_pos_frequency_point works for frequency sampling mode.
|
|
*/
|
|
g_pos = (long(*)[4])malloc(sizeof(long[4]) * num_band_prod);
|
|
if (at_a_frequency_point) {
|
|
num_g_pos = set_g_pos_frequency_point(
|
|
g_pos, num_band0, num_band,
|
|
g_zero + i * g_index_dims + g_index_shift);
|
|
} else {
|
|
num_g_pos = ise_set_g_pos(g_pos, num_band0, num_band,
|
|
g_zero + i * g_index_dims);
|
|
}
|
|
|
|
ise_imag_self_energy_at_triplet(
|
|
ise + i * num_band0, num_band0, num_band,
|
|
fc3_normal_squared->data + i * num_band_prod, frequencies,
|
|
triplets[i], triplet_weights[i],
|
|
g + i * g_index_dims + g_index_shift,
|
|
g + (i + num_triplets) * g_index_dims + g_index_shift, g_pos,
|
|
num_g_pos, &temperature, 1, cutoff_frequency, 0,
|
|
at_a_frequency_point);
|
|
|
|
free(g_pos);
|
|
g_pos = NULL;
|
|
}
|
|
|
|
for (i = 0; i < num_band0; i++) {
|
|
imag_self_energy[i] = 0;
|
|
}
|
|
|
|
for (i = 0; i < num_triplets; i++) {
|
|
for (j = 0; j < num_band0; j++) {
|
|
imag_self_energy[j] += ise[i * num_band0 + j];
|
|
}
|
|
}
|
|
|
|
free(ise);
|
|
ise = NULL;
|
|
}
|
|
|
|
void ise_get_detailed_imag_self_energy_with_g(
|
|
double *detailed_imag_self_energy, double *imag_self_energy_N,
|
|
double *imag_self_energy_U, const Darray *fc3_normal_squared,
|
|
const double *frequencies, const long (*triplets)[3],
|
|
const long *triplet_weights, const long (*bz_grid_addresses)[3],
|
|
const double *g, const char *g_zero, const double temperature,
|
|
const double cutoff_frequency) {
|
|
double *ise;
|
|
long i, j, num_triplets, num_band0, num_band, num_band_prod;
|
|
long *is_N;
|
|
double ise_tmp, N, U;
|
|
|
|
ise = NULL;
|
|
is_N = NULL;
|
|
|
|
num_triplets = fc3_normal_squared->dims[0];
|
|
num_band0 = fc3_normal_squared->dims[1];
|
|
num_band = fc3_normal_squared->dims[2];
|
|
num_band_prod = num_band0 * num_band * num_band;
|
|
ise = (double *)malloc(sizeof(double) * num_triplets * num_band0);
|
|
|
|
/* detailed_imag_self_energy has the same shape as fc3_normal_squared. */
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for
|
|
#endif
|
|
for (i = 0; i < num_triplets; i++) {
|
|
detailed_imag_self_energy_at_triplet(
|
|
detailed_imag_self_energy + i * num_band_prod, ise + i * num_band0,
|
|
num_band0, num_band, fc3_normal_squared->data + i * num_band_prod,
|
|
frequencies, triplets[i], g + i * num_band_prod,
|
|
g + (i + num_triplets) * num_band_prod, g_zero + i * num_band_prod,
|
|
&temperature, 1, cutoff_frequency);
|
|
}
|
|
|
|
is_N = (long *)malloc(sizeof(long) * num_triplets);
|
|
for (i = 0; i < num_triplets; i++) {
|
|
is_N[i] = tpl_is_N(triplets[i], bz_grid_addresses);
|
|
}
|
|
|
|
for (i = 0; i < num_band0; i++) {
|
|
N = 0;
|
|
U = 0;
|
|
/* #ifdef _OPENMP */
|
|
/* #pragma omp parallel for private(ise_tmp) reduction(+:N,U) */
|
|
/* #endif */
|
|
for (j = 0; j < num_triplets; j++) {
|
|
ise_tmp = ise[j * num_band0 + i] * triplet_weights[j];
|
|
if (is_N[j]) {
|
|
N += ise_tmp;
|
|
} else {
|
|
U += ise_tmp;
|
|
}
|
|
}
|
|
imag_self_energy_N[i] = N;
|
|
imag_self_energy_U[i] = U;
|
|
}
|
|
|
|
free(is_N);
|
|
is_N = NULL;
|
|
free(ise);
|
|
ise = NULL;
|
|
}
|
|
|
|
void ise_imag_self_energy_at_triplet(
|
|
double *imag_self_energy, const long num_band0, const long num_band,
|
|
const double *fc3_normal_squared, const double *frequencies,
|
|
const long triplet[3], const long triplet_weight, const double *g1,
|
|
const double *g2_3, const long (*g_pos)[4], const long num_g_pos,
|
|
const double *temperatures, const long num_temps,
|
|
const double cutoff_frequency, const long openmp_per_triplets,
|
|
const long at_a_frequency_point) {
|
|
long i, j;
|
|
double *n1, *n2, *ise_at_g_pos;
|
|
long g_pos_3;
|
|
|
|
n1 = (double *)malloc(sizeof(double) * num_temps * num_band);
|
|
n2 = (double *)malloc(sizeof(double) * num_temps * num_band);
|
|
ise_at_g_pos = (double *)malloc(sizeof(double) * num_g_pos * num_temps);
|
|
|
|
for (i = 0; i < num_temps; i++) {
|
|
set_occupations(n1 + i * num_band, n2 + i * num_band, num_band,
|
|
temperatures[i], triplet, frequencies,
|
|
cutoff_frequency);
|
|
}
|
|
|
|
#ifdef _OPENMP
|
|
#pragma omp parallel for private(j, g_pos_3) if (!openmp_per_triplets)
|
|
#endif
|
|
for (i = 0; i < num_g_pos; i++) {
|
|
if (at_a_frequency_point) {
|
|
/** At a frequency point:
|
|
* g_pos[i][3] is for Phi with the shape of (band0, band, band).
|
|
* g_pos_3 is for g at-freq-point with the shape of (bands, bands).
|
|
*/
|
|
g_pos_3 = g_pos[i][3] % (num_band * num_band);
|
|
} else {
|
|
g_pos_3 = g_pos[i][3];
|
|
}
|
|
for (j = 0; j < num_temps; j++) {
|
|
if (n1[j * num_band + g_pos[i][1]] < 0 ||
|
|
n2[j * num_band + g_pos[i][2]] < 0) {
|
|
ise_at_g_pos[i * num_temps + j] = 0;
|
|
} else {
|
|
if (temperatures[j] > 0) {
|
|
ise_at_g_pos[i * num_temps + j] =
|
|
((n1[j * num_band + g_pos[i][1]] +
|
|
n2[j * num_band + g_pos[i][2]] + 1) *
|
|
g1[g_pos_3] +
|
|
(n1[j * num_band + g_pos[i][1]] -
|
|
n2[j * num_band + g_pos[i][2]]) *
|
|
g2_3[g_pos_3]) *
|
|
fc3_normal_squared[g_pos[i][3]] * triplet_weight;
|
|
} else {
|
|
ise_at_g_pos[i * num_temps + j] =
|
|
g1[g_pos_3] * fc3_normal_squared[g_pos[i][3]] *
|
|
triplet_weight;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < num_temps * num_band0; i++) {
|
|
imag_self_energy[i] = 0;
|
|
}
|
|
for (i = 0; i < num_g_pos; i++) {
|
|
for (j = 0; j < num_temps; j++) {
|
|
imag_self_energy[j * num_band0 + g_pos[i][0]] +=
|
|
ise_at_g_pos[i * num_temps + j];
|
|
}
|
|
}
|
|
|
|
free(ise_at_g_pos);
|
|
ise_at_g_pos = NULL;
|
|
free(n1);
|
|
n1 = NULL;
|
|
free(n2);
|
|
n2 = NULL;
|
|
}
|
|
|
|
long ise_set_g_pos(long (*g_pos)[4], const long num_band0, const long num_band,
|
|
const char *g_zero) {
|
|
long num_g_pos, j, k, l, jkl;
|
|
|
|
num_g_pos = 0;
|
|
jkl = 0;
|
|
for (j = 0; j < num_band0; j++) {
|
|
for (k = 0; k < num_band; k++) {
|
|
for (l = 0; l < num_band; l++) {
|
|
if (!g_zero[jkl]) {
|
|
g_pos[num_g_pos][0] = j;
|
|
g_pos[num_g_pos][1] = k;
|
|
g_pos[num_g_pos][2] = l;
|
|
g_pos[num_g_pos][3] = jkl;
|
|
num_g_pos++;
|
|
}
|
|
jkl++;
|
|
}
|
|
}
|
|
}
|
|
return num_g_pos;
|
|
}
|
|
|
|
/**
|
|
* @brief
|
|
*
|
|
* @param g_pos
|
|
* @param num_band0
|
|
* @param num_band
|
|
* @param g_zero
|
|
* @return long
|
|
*/
|
|
static long set_g_pos_frequency_point(long (*g_pos)[4], const long num_band0,
|
|
const long num_band, const char *g_zero) {
|
|
long num_g_pos, j, k, l, kl, jkl;
|
|
|
|
num_g_pos = 0;
|
|
jkl = 0;
|
|
for (j = 0; j < num_band0; j++) {
|
|
kl = 0;
|
|
for (k = 0; k < num_band; k++) {
|
|
for (l = 0; l < num_band; l++) {
|
|
if (!g_zero[kl]) {
|
|
g_pos[num_g_pos][0] = j;
|
|
g_pos[num_g_pos][1] = k;
|
|
g_pos[num_g_pos][2] = l;
|
|
g_pos[num_g_pos][3] = jkl;
|
|
num_g_pos++;
|
|
}
|
|
jkl++;
|
|
kl++;
|
|
}
|
|
}
|
|
}
|
|
return num_g_pos;
|
|
}
|
|
|
|
static void detailed_imag_self_energy_at_triplet(
|
|
double *detailed_imag_self_energy, double *imag_self_energy,
|
|
const long num_band0, const long num_band, const double *fc3_normal_squared,
|
|
const double *frequencies, const long triplet[3], const double *g1,
|
|
const double *g2_3, const char *g_zero, const double *temperatures,
|
|
const long num_temps, const double cutoff_frequency) {
|
|
long i, j, adrs_shift;
|
|
double *n1, *n2;
|
|
|
|
n1 = NULL;
|
|
n2 = NULL;
|
|
|
|
n1 = (double *)malloc(sizeof(double) * num_band);
|
|
n2 = (double *)malloc(sizeof(double) * num_band);
|
|
|
|
for (i = 0; i < num_temps; i++) {
|
|
set_occupations(n1, n2, num_band, temperatures[i], triplet, frequencies,
|
|
cutoff_frequency);
|
|
|
|
for (j = 0; j < num_band0; j++) {
|
|
adrs_shift = j * num_band * num_band;
|
|
if (temperatures[i] > 0) {
|
|
imag_self_energy[i * num_band0 + j] =
|
|
collect_detailed_imag_self_energy(
|
|
detailed_imag_self_energy + adrs_shift, num_band,
|
|
fc3_normal_squared + adrs_shift, n1, n2,
|
|
g1 + adrs_shift, g2_3 + adrs_shift,
|
|
g_zero + adrs_shift);
|
|
} else {
|
|
imag_self_energy[i * num_band0 + j] =
|
|
collect_detailed_imag_self_energy_0K(
|
|
detailed_imag_self_energy + adrs_shift, num_band,
|
|
fc3_normal_squared + adrs_shift, n1, n2,
|
|
g1 + adrs_shift, g_zero + adrs_shift);
|
|
}
|
|
}
|
|
}
|
|
|
|
free(n1);
|
|
n1 = NULL;
|
|
free(n2);
|
|
n2 = NULL;
|
|
}
|
|
|
|
static double collect_detailed_imag_self_energy(
|
|
double *imag_self_energy, const long num_band,
|
|
const double *fc3_normal_squared, const double *n1, const double *n2,
|
|
const double *g1, const double *g2_3, const char *g_zero) {
|
|
long ij, i, j;
|
|
double sum_g;
|
|
|
|
sum_g = 0;
|
|
for (ij = 0; ij < num_band * num_band; ij++) {
|
|
imag_self_energy[ij] = 0;
|
|
if (g_zero[ij]) {
|
|
continue;
|
|
}
|
|
i = ij / num_band;
|
|
j = ij % num_band;
|
|
if (n1[i] < 0 || n2[j] < 0) {
|
|
continue;
|
|
}
|
|
imag_self_energy[ij] =
|
|
(((n1[i] + n2[j] + 1) * g1[ij] + (n1[i] - n2[j]) * g2_3[ij]) *
|
|
fc3_normal_squared[ij]);
|
|
sum_g += imag_self_energy[ij];
|
|
}
|
|
|
|
return sum_g;
|
|
}
|
|
|
|
static double collect_detailed_imag_self_energy_0K(
|
|
double *imag_self_energy, const long num_band,
|
|
const double *fc3_normal_squared, const double *n1, const double *n2,
|
|
const double *g1, const char *g_zero) {
|
|
long ij, i, j;
|
|
double sum_g;
|
|
|
|
sum_g = 0;
|
|
for (ij = 0; ij < num_band * num_band; ij++) {
|
|
imag_self_energy[ij] = 0;
|
|
if (g_zero[ij]) {
|
|
continue;
|
|
}
|
|
i = ij / num_band;
|
|
j = ij % num_band;
|
|
if (n1[i] < 0 || n2[j] < 0) {
|
|
continue;
|
|
}
|
|
imag_self_energy[ij] = g1[ij] * fc3_normal_squared[ij];
|
|
sum_g += imag_self_energy[ij];
|
|
}
|
|
|
|
return sum_g;
|
|
}
|
|
|
|
static void set_occupations(double *n1, double *n2, const long num_band,
|
|
const double temperature, const long triplet[3],
|
|
const double *frequencies,
|
|
const double cutoff_frequency) {
|
|
long j;
|
|
double f1, f2;
|
|
|
|
for (j = 0; j < num_band; j++) {
|
|
f1 = frequencies[triplet[1] * num_band + j];
|
|
f2 = frequencies[triplet[2] * num_band + j];
|
|
if (f1 > cutoff_frequency) {
|
|
n1[j] = funcs_bose_einstein(f1, temperature);
|
|
} else {
|
|
n1[j] = -1;
|
|
}
|
|
if (f2 > cutoff_frequency) {
|
|
n2[j] = funcs_bose_einstein(f2, temperature);
|
|
} else {
|
|
n2[j] = -1;
|
|
}
|
|
}
|
|
}
|