mirror of https://github.com/phonopy/phonopy.git
500 lines
14 KiB
C
500 lines
14 KiB
C
#include <Python.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <numpy/arrayobject.h>
|
|
#include <lapacke.h>
|
|
#include "phonoc_array.h"
|
|
#include "phonon4_h/fc4.h"
|
|
#include "phonon4_h/real_to_reciprocal.h"
|
|
#include "phonon4_h/frequency_shift.h"
|
|
|
|
static PyObject * py_get_fc4_normal_for_frequency_shift(PyObject *self, PyObject *args);
|
|
static PyObject * py_get_fc4_frequency_shifts(PyObject *self, PyObject *args);
|
|
static PyObject * py_real_to_reciprocal4(PyObject *self, PyObject *args);
|
|
static PyObject * py_reciprocal_to_normal4(PyObject *self, PyObject *args);
|
|
static PyObject * py_set_phonons_grid_points(PyObject *self, PyObject *args);
|
|
static PyObject * py_distribute_fc4(PyObject *self, PyObject *args);
|
|
static PyObject * py_rotate_delta_fc3s_elem(PyObject *self, PyObject *args);
|
|
static PyObject * py_set_translational_invariance_fc4(PyObject *self,
|
|
PyObject *args);
|
|
static PyObject * py_set_permutation_symmetry_fc4(PyObject *self,
|
|
PyObject *args);
|
|
static PyObject * py_get_drift_fc4(PyObject *self, PyObject *args);
|
|
|
|
static PyMethodDef functions[] = {
|
|
{"fc4_normal_for_frequency_shift", py_get_fc4_normal_for_frequency_shift, METH_VARARGS, "Calculate fc4 normal for frequency shift"},
|
|
{"fc4_frequency_shifts", py_get_fc4_frequency_shifts, METH_VARARGS, "Calculate fc4 frequency shift"},
|
|
{"real_to_reciprocal4", py_real_to_reciprocal4, METH_VARARGS, "Transform fc4 of real space to reciprocal space"},
|
|
{"reciprocal_to_normal4", py_reciprocal_to_normal4, METH_VARARGS, "Transform fc4 of reciprocal space to normal coordinate in special case for frequency shift"},
|
|
{"phonons_grid_points", py_set_phonons_grid_points, METH_VARARGS, "Set phonons on grid points"},
|
|
{"distribute_fc4", py_distribute_fc4, METH_VARARGS, "Distribute least fc4 to full fc4"},
|
|
{"rotate_delta_fc3s_elem", py_rotate_delta_fc3s_elem, METH_VARARGS, "Rotate delta fc3s for a set of atomic indices"},
|
|
{"translational_invariance_fc4", py_set_translational_invariance_fc4, METH_VARARGS, "Set translational invariance for fc4"},
|
|
{"permutation_symmetry_fc4", py_set_permutation_symmetry_fc4, METH_VARARGS, "Set permutation symmetry for fc4"},
|
|
{"drift_fc4", py_get_drift_fc4, METH_VARARGS, "Get drifts of fc4"},
|
|
{NULL, NULL, 0, NULL}
|
|
};
|
|
|
|
PyMODINIT_FUNC init_phono4py(void)
|
|
{
|
|
Py_InitModule3("_phono4py", functions, "C-extension for phono4py\n\n...\n");
|
|
return;
|
|
}
|
|
|
|
static PyObject * py_get_fc4_normal_for_frequency_shift(PyObject *self,
|
|
PyObject *args)
|
|
{
|
|
PyArrayObject* fc4_normal_py;
|
|
PyArrayObject* frequencies_py;
|
|
PyArrayObject* eigenvectors_py;
|
|
PyArrayObject* grid_points1_py;
|
|
PyArrayObject* grid_address_py;
|
|
PyArrayObject* mesh_py;
|
|
PyArrayObject* fc4_py;
|
|
PyArrayObject* shortest_vectors_py;
|
|
PyArrayObject* multiplicity_py;
|
|
PyArrayObject* masses_py;
|
|
PyArrayObject* p2s_map_py;
|
|
PyArrayObject* s2p_map_py;
|
|
PyArrayObject* band_indicies_py;
|
|
double cutoff_frequency;
|
|
int grid_point0;
|
|
|
|
if (!PyArg_ParseTuple(args, "OOOiOOOOOOOOOOd",
|
|
&fc4_normal_py,
|
|
&frequencies_py,
|
|
&eigenvectors_py,
|
|
&grid_point0,
|
|
&grid_points1_py,
|
|
&grid_address_py,
|
|
&mesh_py,
|
|
&fc4_py,
|
|
&shortest_vectors_py,
|
|
&multiplicity_py,
|
|
&masses_py,
|
|
&p2s_map_py,
|
|
&s2p_map_py,
|
|
&band_indicies_py,
|
|
&cutoff_frequency)) {
|
|
return NULL;
|
|
}
|
|
|
|
double* fc4_normal = (double*)fc4_normal_py->data;
|
|
double* freqs = (double*)frequencies_py->data;
|
|
/* npy_cdouble and lapack_complex_double may not be compatible. */
|
|
/* So eigenvectors should not be used in Python side */
|
|
lapack_complex_double* eigvecs =
|
|
(lapack_complex_double*)eigenvectors_py->data;
|
|
Iarray* grid_points1 = convert_to_iarray(grid_points1_py);
|
|
const int* grid_address = (int*)grid_address_py->data;
|
|
const int* mesh = (int*)mesh_py->data;
|
|
double* fc4 = (double*)fc4_py->data;
|
|
Darray* svecs = convert_to_darray(shortest_vectors_py);
|
|
Iarray* multi = convert_to_iarray(multiplicity_py);
|
|
const double* masses = (double*)masses_py->data;
|
|
const int* p2s = (int*)p2s_map_py->data;
|
|
const int* s2p = (int*)s2p_map_py->data;
|
|
Iarray* band_indicies = convert_to_iarray(band_indicies_py);
|
|
|
|
get_fc4_normal_for_frequency_shift(fc4_normal,
|
|
freqs,
|
|
eigvecs,
|
|
grid_point0,
|
|
grid_points1,
|
|
grid_address,
|
|
mesh,
|
|
fc4,
|
|
svecs,
|
|
multi,
|
|
masses,
|
|
p2s,
|
|
s2p,
|
|
band_indicies,
|
|
cutoff_frequency);
|
|
|
|
free(grid_points1);
|
|
free(svecs);
|
|
free(multi);
|
|
free(band_indicies);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyObject * py_get_fc4_frequency_shifts(PyObject *self, PyObject *args)
|
|
{
|
|
PyArrayObject* frequency_shifts_py;
|
|
PyArrayObject* fc4_normal_py;
|
|
PyArrayObject* frequencies_py;
|
|
PyArrayObject* grid_points1_py;
|
|
PyArrayObject* temperatures_py;
|
|
PyArrayObject* band_indicies_py;
|
|
double unit_conversion_factor;
|
|
|
|
if (!PyArg_ParseTuple(args, "OOOOOOd",
|
|
&frequency_shifts_py,
|
|
&fc4_normal_py,
|
|
&frequencies_py,
|
|
&grid_points1_py,
|
|
&temperatures_py,
|
|
&band_indicies_py,
|
|
&unit_conversion_factor)) {
|
|
return NULL;
|
|
}
|
|
|
|
double* freq_shifts = (double*)frequency_shifts_py->data;
|
|
double* fc4_normal = (double*)fc4_normal_py->data;
|
|
double* freqs = (double*)frequencies_py->data;
|
|
Iarray* grid_points1 = convert_to_iarray(grid_points1_py);
|
|
Darray* temperatures = convert_to_darray(temperatures_py);
|
|
int* band_indicies = (int*)band_indicies_py->data;
|
|
const int num_band0 = (int)band_indicies_py->dimensions[0];
|
|
const int num_band = (int)frequencies_py->dimensions[1];
|
|
|
|
get_fc4_frequency_shifts(freq_shifts,
|
|
fc4_normal,
|
|
freqs,
|
|
grid_points1,
|
|
temperatures,
|
|
band_indicies,
|
|
num_band0,
|
|
num_band,
|
|
unit_conversion_factor);
|
|
|
|
free(grid_points1);
|
|
free(temperatures);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyObject * py_real_to_reciprocal4(PyObject *self, PyObject *args)
|
|
{
|
|
PyArrayObject* fc4_py;
|
|
PyArrayObject* fc4_reciprocal_py;
|
|
PyArrayObject* q_py;
|
|
PyArrayObject* shortest_vectors;
|
|
PyArrayObject* multiplicity;
|
|
PyArrayObject* p2s_map;
|
|
PyArrayObject* s2p_map;
|
|
|
|
if (!PyArg_ParseTuple(args, "OOOOOOO",
|
|
&fc4_reciprocal_py,
|
|
&fc4_py,
|
|
&q_py,
|
|
&shortest_vectors,
|
|
&multiplicity,
|
|
&p2s_map,
|
|
&s2p_map)) {
|
|
return NULL;
|
|
}
|
|
|
|
double* fc4 = (double*)fc4_py->data;
|
|
lapack_complex_double* fc4_reciprocal =
|
|
(lapack_complex_double*)fc4_reciprocal_py->data;
|
|
Darray* svecs = convert_to_darray(shortest_vectors);
|
|
Iarray* multi = convert_to_iarray(multiplicity);
|
|
const int* p2s = (int*)p2s_map->data;
|
|
const int* s2p = (int*)s2p_map->data;
|
|
const double* q = (double*)q_py->data;
|
|
|
|
real_to_reciprocal4(fc4_reciprocal,
|
|
q,
|
|
fc4,
|
|
svecs,
|
|
multi,
|
|
p2s,
|
|
s2p);
|
|
|
|
free(svecs);
|
|
free(multi);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyObject * py_reciprocal_to_normal4(PyObject *self, PyObject *args)
|
|
{
|
|
PyArrayObject* fc4_normal_py;
|
|
PyArrayObject* fc4_reciprocal_py;
|
|
PyArrayObject* frequencies_py;
|
|
PyArrayObject* eigenvectors_py;
|
|
PyArrayObject* grid_points_py;
|
|
PyArrayObject* masses_py;
|
|
PyArrayObject* band_indicies_py;
|
|
double cutoff_frequency;
|
|
|
|
if (!PyArg_ParseTuple(args, "OOOOOOOd",
|
|
&fc4_normal_py,
|
|
&fc4_reciprocal_py,
|
|
&frequencies_py,
|
|
&eigenvectors_py,
|
|
&grid_points_py,
|
|
&masses_py,
|
|
&band_indicies_py,
|
|
&cutoff_frequency)) {
|
|
return NULL;
|
|
}
|
|
|
|
lapack_complex_double* fc4_normal =
|
|
(lapack_complex_double*)fc4_normal_py->data;
|
|
const lapack_complex_double* fc4_reciprocal =
|
|
(lapack_complex_double*)fc4_reciprocal_py->data;
|
|
const lapack_complex_double* eigenvectors =
|
|
(lapack_complex_double*)eigenvectors_py->data;
|
|
const double* frequencies = (double*)frequencies_py->data;
|
|
const int* grid_points = (int*)grid_points_py->data;
|
|
const double* masses = (double*)masses_py->data;
|
|
const int* band_indices = (int*)band_indicies_py->data;
|
|
const int num_band0 = (int)band_indicies_py->dimensions[0];
|
|
const int num_band = (int)frequencies_py->dimensions[1];
|
|
|
|
reciprocal_to_normal4(fc4_normal,
|
|
fc4_reciprocal,
|
|
frequencies + grid_points[0] * num_band,
|
|
frequencies + grid_points[1] * num_band,
|
|
eigenvectors + grid_points[0] * num_band * num_band,
|
|
eigenvectors + grid_points[1] * num_band * num_band,
|
|
masses,
|
|
band_indices,
|
|
num_band0,
|
|
num_band,
|
|
cutoff_frequency);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyObject * py_set_phonons_grid_points(PyObject *self, PyObject *args)
|
|
{
|
|
PyArrayObject* frequencies;
|
|
PyArrayObject* eigenvectors;
|
|
PyArrayObject* phonon_done_py;
|
|
PyArrayObject* grid_points_py;
|
|
PyArrayObject* grid_address_py;
|
|
PyArrayObject* mesh_py;
|
|
PyArrayObject* shortest_vectors_fc2;
|
|
PyArrayObject* multiplicity_fc2;
|
|
PyArrayObject* fc2_py;
|
|
PyArrayObject* atomic_masses_fc2;
|
|
PyArrayObject* p2s_map_fc2;
|
|
PyArrayObject* s2p_map_fc2;
|
|
PyArrayObject* reciprocal_lattice;
|
|
PyArrayObject* born_effective_charge;
|
|
PyArrayObject* q_direction;
|
|
PyArrayObject* dielectric_constant;
|
|
double nac_factor, unit_conversion_factor;
|
|
char uplo;
|
|
|
|
if (!PyArg_ParseTuple(args, "OOOOOOOOOOOOdOOOOdc",
|
|
&frequencies,
|
|
&eigenvectors,
|
|
&phonon_done_py,
|
|
&grid_points_py,
|
|
&grid_address_py,
|
|
&mesh_py,
|
|
&fc2_py,
|
|
&shortest_vectors_fc2,
|
|
&multiplicity_fc2,
|
|
&atomic_masses_fc2,
|
|
&p2s_map_fc2,
|
|
&s2p_map_fc2,
|
|
&unit_conversion_factor,
|
|
&born_effective_charge,
|
|
&dielectric_constant,
|
|
&reciprocal_lattice,
|
|
&q_direction,
|
|
&nac_factor,
|
|
&uplo)) {
|
|
return NULL;
|
|
}
|
|
|
|
double* born;
|
|
double* dielectric;
|
|
double *q_dir;
|
|
Darray* freqs = convert_to_darray(frequencies);
|
|
/* npy_cdouble and lapack_complex_double may not be compatible. */
|
|
/* So eigenvectors should not be used in Python side */
|
|
Carray* eigvecs = convert_to_carray(eigenvectors);
|
|
char* phonon_done = (char*)phonon_done_py->data;
|
|
Iarray* grid_points = convert_to_iarray(grid_points_py);
|
|
const int* grid_address = (int*)grid_address_py->data;
|
|
const int* mesh = (int*)mesh_py->data;
|
|
Darray* fc2 = convert_to_darray(fc2_py);
|
|
Darray* svecs_fc2 = convert_to_darray(shortest_vectors_fc2);
|
|
Iarray* multi_fc2 = convert_to_iarray(multiplicity_fc2);
|
|
const double* masses_fc2 = (double*)atomic_masses_fc2->data;
|
|
const int* p2s_fc2 = (int*)p2s_map_fc2->data;
|
|
const int* s2p_fc2 = (int*)s2p_map_fc2->data;
|
|
const double* rec_lat = (double*)reciprocal_lattice->data;
|
|
if ((PyObject*)born_effective_charge == Py_None) {
|
|
born = NULL;
|
|
} else {
|
|
born = (double*)born_effective_charge->data;
|
|
}
|
|
if ((PyObject*)dielectric_constant == Py_None) {
|
|
dielectric = NULL;
|
|
} else {
|
|
dielectric = (double*)dielectric_constant->data;
|
|
}
|
|
if ((PyObject*)q_direction == Py_None) {
|
|
q_dir = NULL;
|
|
} else {
|
|
q_dir = (double*)q_direction->data;
|
|
}
|
|
|
|
set_phonons_for_frequency_shift(freqs,
|
|
eigvecs,
|
|
phonon_done,
|
|
grid_points,
|
|
grid_address,
|
|
mesh,
|
|
fc2,
|
|
svecs_fc2,
|
|
multi_fc2,
|
|
masses_fc2,
|
|
p2s_fc2,
|
|
s2p_fc2,
|
|
unit_conversion_factor,
|
|
born,
|
|
dielectric,
|
|
rec_lat,
|
|
q_dir,
|
|
nac_factor,
|
|
uplo);
|
|
|
|
free(freqs);
|
|
free(eigvecs);
|
|
free(grid_points);
|
|
free(fc2);
|
|
free(svecs_fc2);
|
|
free(multi_fc2);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyObject * py_distribute_fc4(PyObject *self, PyObject *args)
|
|
{
|
|
PyArrayObject* force_constants_fourth;
|
|
int fourth_atom;
|
|
PyArrayObject* rotation_cart_inv;
|
|
PyArrayObject* atom_mapping_py;
|
|
|
|
if (!PyArg_ParseTuple(args, "OiOO",
|
|
&force_constants_fourth,
|
|
&fourth_atom,
|
|
&atom_mapping_py,
|
|
&rotation_cart_inv)) {
|
|
return NULL;
|
|
}
|
|
|
|
double* fc4 = (double*)force_constants_fourth->data;
|
|
const double* rot_cart_inv = (double*)rotation_cart_inv->data;
|
|
const int* atom_mapping = (int*)atom_mapping_py->data;
|
|
const int num_atom = (int)atom_mapping_py->dimensions[0];
|
|
|
|
return PyInt_FromLong((long) distribute_fc4(fc4,
|
|
fourth_atom,
|
|
atom_mapping,
|
|
num_atom,
|
|
rot_cart_inv));
|
|
}
|
|
|
|
static PyObject * py_rotate_delta_fc3s_elem(PyObject *self, PyObject *args)
|
|
{
|
|
PyArrayObject* rotated_delta_fc3s_py;
|
|
PyArrayObject* delta_fc3s_py;
|
|
PyArrayObject* atom_mappings_of_rotations_py;
|
|
PyArrayObject* site_symmetries_cartesian_py;
|
|
int atom1, atom2, atom3;
|
|
|
|
if (!PyArg_ParseTuple(args, "OOOOiii",
|
|
&rotated_delta_fc3s_py,
|
|
&delta_fc3s_py,
|
|
&atom_mappings_of_rotations_py,
|
|
&site_symmetries_cartesian_py,
|
|
&atom1,
|
|
&atom2,
|
|
&atom3)) {
|
|
return NULL;
|
|
}
|
|
|
|
double* rotated_delta_fc3s = (double*)rotated_delta_fc3s_py->data;
|
|
const double* delta_fc3s = (double*)delta_fc3s_py->data;
|
|
const int* rot_map_syms = (int*)atom_mappings_of_rotations_py->data;
|
|
const double* site_syms_cart = (double*)site_symmetries_cartesian_py->data;
|
|
const int num_rot = (int)site_symmetries_cartesian_py->dimensions[0];
|
|
const int num_delta_fc3s = (int)delta_fc3s_py->dimensions[0];
|
|
const int num_atom = (int)delta_fc3s_py->dimensions[1];
|
|
|
|
return PyInt_FromLong((long) rotate_delta_fc3s_elem(rotated_delta_fc3s,
|
|
delta_fc3s,
|
|
rot_map_syms,
|
|
site_syms_cart,
|
|
num_rot,
|
|
num_delta_fc3s,
|
|
atom1,
|
|
atom2,
|
|
atom3,
|
|
num_atom));
|
|
}
|
|
|
|
static PyObject * py_set_translational_invariance_fc4(PyObject *self,
|
|
PyObject *args)
|
|
{
|
|
PyArrayObject* fc4_py;
|
|
int index;
|
|
|
|
if (!PyArg_ParseTuple(args, "Oi",
|
|
&fc4_py,
|
|
&index)) {
|
|
return NULL;
|
|
}
|
|
|
|
double* fc4 = (double*)fc4_py->data;
|
|
const int num_atom = (int)fc4_py->dimensions[0];
|
|
|
|
set_translational_invariance_fc4_per_index(fc4, num_atom, index);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyObject * py_set_permutation_symmetry_fc4(PyObject *self, PyObject *args)
|
|
{
|
|
PyArrayObject* fc4_py;
|
|
|
|
if (!PyArg_ParseTuple(args, "O",
|
|
&fc4_py)) {
|
|
return NULL;
|
|
}
|
|
|
|
double* fc4 = (double*)fc4_py->data;
|
|
const int num_atom = (int)fc4_py->dimensions[0];
|
|
|
|
set_permutation_symmetry_fc4(fc4, num_atom);
|
|
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
static PyObject * py_get_drift_fc4(PyObject *self, PyObject *args)
|
|
{
|
|
PyArrayObject* fc4_py;
|
|
|
|
if (!PyArg_ParseTuple(args, "O",
|
|
&fc4_py)) {
|
|
return NULL;
|
|
}
|
|
|
|
double* fc4 = (double*)fc4_py->data;
|
|
const int num_atom = (int)fc4_py->dimensions[0];
|
|
|
|
int i;
|
|
double drift[4];
|
|
PyObject* drift_py;
|
|
|
|
get_drift_fc4(drift, fc4, num_atom);
|
|
drift_py = PyList_New(4);
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
PyList_SetItem(drift_py, i, PyFloat_FromDouble(drift[i]));
|
|
}
|
|
|
|
return drift_py;
|
|
}
|