Change of build system using cmake

Following issue#99, attempting changing build system.
This commit includes the build system by combination with cmake.
This commit is contained in:
Atsushi Togo 2022-08-28 07:59:41 +09:00
parent 01742d44cb
commit 756ada6e07
10 changed files with 312 additions and 434 deletions

View File

@ -9,36 +9,42 @@ on:
jobs:
build-linux:
runs-on: ubuntu-latest
defaults:
run:
shell: bash -l {0}
strategy:
matrix:
python-version: [3.7, 3.8, 3.9]
python-version: ["3.7", "3.8", "3.9", "3.10"]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
# Use conda-incubator/setup-miniconda for precise control of conda infrastructure
- uses: conda-incubator/setup-miniconda@v2
with:
auto-update-conda: true
channels: conda-forge
channel-priority: strict
python-version: ${{ matrix.python-version }}
- name: Add conda to system path
- name: Install dependent packages
run: |
# $CONDA is an environment variable pointing to the root of the miniconda directory
echo $CONDA/bin >> $GITHUB_PATH
- name: Install dependencies
conda activate test
conda install --yes python=${{ matrix.python-version }}
#conda install --yes matplotlib-base pyyaml openblas h5py scipy pytest codecov pytest-cov spglib alm cmake c-compiler
conda install --yes matplotlib-base pyyaml "libblas=*=*mkl" mkl-include h5py scipy pytest codecov pytest-cov spglib alm cmake c-compiler
- name: Install phonopy
run: |
conda install --yes -c conda-forge python=${{ matrix.python-version }}
conda install --yes -c conda-forge matplotlib-base pyyaml openblas gcc_linux-64 h5py scipy pytest codecov pytest-cov spglib alm
pip install https://github.com/phonopy/phonopy/archive/develop.zip --user
- name: Set up phono3py
conda activate test
git clone --depth 1 https://github.com/phonopy/phonopy.git
cd phonopy
pip install -e . -vvv
cd ..
- name: Install phono3py
run: |
export CONDA_PREFIX=$CONDA
echo "[phono3py]" > site.cfg
echo "extra_compile_args = -fopenmp" >> site.cfg
echo "extra_link_args = -lgomp" >> site.cfg
python setup.py build
pip install -e .
- name: Test with pytest
conda activate test
pip install -e . -vvv
- name: Run pytest
run: |
pytest --cov=./ --cov-report=xml
pytest --cov=./ --cov-report=xml test
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
with:

View File

@ -9,10 +9,10 @@ if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif(NOT CMAKE_BUILD_TYPE)
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS "CMAKE_SYSTEM_PREFIX_PATH: ${CMAKE_SYSTEM_PREFIX_PATH}")
include(GNUInstallDirs)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# Version numbers
@ -24,19 +24,38 @@ set(phono3py_micro_version ${CMAKE_MATCH_3})
set(serial "${phono3py_major_version}.${phono3py_minor_version}.${phono3py_micro_version}")
set(soserial "1")
if (USE_CONDA_PATH)
message(STATUS "$ENV{CONDA_PREFIX}")
set(CMAKE_MODULE_PATH $ENV{CONDA_PREFIX})
set(MY_INCLUDES $ENV{CONDA_PREFIX}/include ${PROJECT_SOURCE_DIR}/c)
link_directories($ENV{CONDA_PREFIX}/lib)
else()
set(MY_INCLUDES ${PROJECT_SOURCE_DIR}/c)
endif()
find_package(OpenMP)
if (OpenMP_FOUND)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
message(STATUS "OpenMP lib ${OpenMP_C_LIBRARIES}")
message(STATUS "OpenMP libs: ${OpenMP_C_LIBRARIES}")
message(STATUS "OpenMP flags: ${OpenMP_C_FLAGS}")
endif()
# include_directories($ENV{CONDA_PREFIX}/include)
# link_directories($ENV{CONDA_PREFIX}/lib)
if (PHONO3PY OR PHONONMOD)
find_package(BLAS REQUIRED) # set BLAS_LIBRARIES
if (BLAS_FOUND)
message(STATUS "BLAS libs: ${BLAS_LIBRARIES}")
message(STATUS "BLAS flags: ${BLAS_LINKER_FLAGS}")
endif()
find_package(LAPACK REQUIRED) # set LAPACK_LIBRARIES
if (LAPACK_FOUND)
message(STATUS "LAPACK libs: ${LAPACK_LIBRARIES}")
message(STATUS "LAPACK flags: ${LAPACK_LINKER_FLAGS}")
endif()
endif()
if (PHONO3PY OR PHONONMOD)
if (BLAS_LIBRARIES MATCHES "libmkl")
message(STATUS "MKL library detected")
add_compile_definitions(MKL_LAPACKE) # phono3py macro
endif()
endif()
@ -46,7 +65,6 @@ endif()
############
if (PHONO3PY)
# Source code
include_directories("${PROJECT_SOURCE_DIR}/c")
set(SOURCES_PHONO3PY
${PROJECT_SOURCE_DIR}/c/bzgrid.c
${PROJECT_SOURCE_DIR}/c/collision_matrix.c
@ -69,18 +87,20 @@ if (PHONO3PY)
${PROJECT_SOURCE_DIR}/c/triplet_grid.c
${PROJECT_SOURCE_DIR}/c/triplet_iw.c)
if (BUILD_SHARED_LIBRARIES)
# Shared library
add_library(ph3py SHARED ${SOURCES_PHONO3PY})
if(NOT MSVC)
target_link_libraries(ph3py m ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES} ${OpenMP_C_LIBRARIES})
endif()
target_include_directories(ph3py PRIVATE ${MY_INCLUDES})
set_property(TARGET ph3py PROPERTY VERSION ${serial})
set_property(TARGET ph3py PROPERTY SOVERSION ${soserial})
install(TARGETS ph3py LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
# Static link library
add_library(ph3py_static STATIC ${SOURCES_PHONO3PY})
target_link_libraries(ph3py_static m ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES} ${OpenMP_C_LIBRARIES})
target_include_directories(ph3py_static PRIVATE ${MY_INCLUDES})
set_property(TARGET ph3py_static PROPERTY VERSION ${serial})
set_property(TARGET ph3py_static PROPERTY SOVERSION ${soserial})
set_property(TARGET ph3py_static PROPERTY OUTPUT_NAME ph3py)
@ -101,18 +121,20 @@ if (PHONONMOD)
${PROJECT_SOURCE_DIR}/c/phonon.c
${PROJECT_SOURCE_DIR}/c/phononmod.c)
if (BUILD_SHARED_LIBRARIES)
# Shared library
add_library(phmod SHARED ${SOURCES_PHONONMOD})
if(NOT MSVC)
target_link_libraries(phmod m ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES} ${OpenMP_C_LIBRARIES})
endif()
target_include_directories(phmod PRIVATE ${MY_INCLUDES})
set_property(TARGET phmod PROPERTY VERSION ${serial})
set_property(TARGET phmod PROPERTY SOVERSION ${soserial})
install(TARGETS phmod LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
# Static link library
add_library(phmod_static STATIC ${SOURCES_PHONONMOD})
target_link_libraries(phmod_static m ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES} ${OpenMP_C_LIBRARIES})
target_include_directories(phmod_static PRIVATE ${MY_INCLUDES})
set_property(TARGET phmod_static PROPERTY VERSION ${serial})
set_property(TARGET phmod_static PROPERTY SOVERSION ${soserial})
set_property(TARGET phmod_static PROPERTY OUTPUT_NAME phmod)
@ -139,18 +161,21 @@ if (GRIDSYS)
${PROJECT_SOURCE_DIR}/c/triplet_grid.c
${PROJECT_SOURCE_DIR}/c/triplet_iw.c)
if (BUILD_SHARED_LIBRARIES)
# Shared library
add_library(gridsysmod SHARED ${SOURCES_GRIDSYSMOD})
if(NOT MSVC)
target_link_libraries(gridsysmod m ${OpenMP_C_LIBRARIES})
endif()
target_include_directories(gridsysmod PRIVATE ${MY_INCLUDES})
set_property(TARGET gridsysmod PROPERTY VERSION ${serial})
set_property(TARGET gridsysmod PROPERTY SOVERSION ${soserial})
install(TARGETS gridsysmod LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
# Static link library
add_library(gridsysmod_static STATIC ${SOURCES_GRIDSYSMOD})
target_link_libraries(gridsysmod_static m ${OpenMP_C_LIBRARIES})
target_include_directories(gridsysmod_static PRIVATE ${MY_INCLUDES})
set_property(TARGET gridsysmod_static PROPERTY VERSION ${serial})
set_property(TARGET gridsysmod_static PROPERTY SOVERSION ${soserial})
set_property(TARGET gridsysmod_static PROPERTY OUTPUT_NAME gridsysmod)

View File

@ -1,175 +0,0 @@
/* 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 <Python.h>
#include <assert.h>
#include <numpy/arrayobject.h>
#include <stdio.h>
#include "lapack_wrapper.h"
static PyObject *py_phonopy_pinv(PyObject *self, PyObject *args);
static PyObject *py_phonopy_zheev(PyObject *self, PyObject *args);
struct module_state {
PyObject *error;
};
#if PY_MAJOR_VERSION >= 3
#define GETSTATE(m) ((struct module_state *)PyModule_GetState(m))
#else
#define GETSTATE(m) (&_state)
static struct module_state _state;
#endif
static PyObject *error_out(PyObject *m) {
struct module_state *st = GETSTATE(m);
PyErr_SetString(st->error, "something bad happened");
return NULL;
}
static PyMethodDef _lapackepy_methods[] = {
{"error_out", (PyCFunction)error_out, METH_NOARGS, NULL},
{"pinv", py_phonopy_pinv, METH_VARARGS,
"Pseudo-inverse using Lapack dgesvd"},
{"zheev", py_phonopy_zheev, METH_VARARGS, "Lapack zheev wrapper"},
{NULL, NULL, 0, NULL}};
#if PY_MAJOR_VERSION >= 3
static int _lapackepy_traverse(PyObject *m, visitproc visit, void *arg) {
Py_VISIT(GETSTATE(m)->error);
return 0;
}
static int _lapackepy_clear(PyObject *m) {
Py_CLEAR(GETSTATE(m)->error);
return 0;
}
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT, "_lapackepy", NULL,
sizeof(struct module_state), _lapackepy_methods, NULL,
_lapackepy_traverse, _lapackepy_clear, NULL};
#define INITERROR return NULL
PyObject *PyInit__lapackepy(void)
#else
#define INITERROR return
void init_lapackepy(void)
#endif
{
#if PY_MAJOR_VERSION >= 3
PyObject *module = PyModule_Create(&moduledef);
#else
PyObject *module = Py_InitModule("_lapackepy", _lapackepy_methods);
#endif
struct module_state *st;
if (module == NULL) INITERROR;
st = GETSTATE(module);
st->error = PyErr_NewException("_lapackepy.Error", NULL, NULL);
if (st->error == NULL) {
Py_DECREF(module);
INITERROR;
}
#if PY_MAJOR_VERSION >= 3
return module;
#endif
}
static PyObject *py_phonopy_zheev(PyObject *self, PyObject *args) {
PyArrayObject *dynamical_matrix;
PyArrayObject *eigenvalues;
int dimension;
npy_cdouble *dynmat;
double *eigvals;
lapack_complex_double *a;
int i, info;
if (!PyArg_ParseTuple(args, "OO", &dynamical_matrix, &eigenvalues)) {
return NULL;
}
dimension = (int)PyArray_DIMS(dynamical_matrix)[0];
dynmat = (npy_cdouble *)PyArray_DATA(dynamical_matrix);
eigvals = (double *)PyArray_DATA(eigenvalues);
a = (lapack_complex_double *)malloc(sizeof(lapack_complex_double) *
dimension * dimension);
for (i = 0; i < dimension * dimension; i++) {
a[i] = lapack_make_complex_double(dynmat[i].real, dynmat[i].imag);
}
info = phonopy_zheev(eigvals, a, dimension, 'L');
for (i = 0; i < dimension * dimension; i++) {
dynmat[i].real = lapack_complex_double_real(a[i]);
dynmat[i].imag = lapack_complex_double_imag(a[i]);
}
free(a);
return PyLong_FromLong((long)info);
}
static PyObject *py_phonopy_pinv(PyObject *self, PyObject *args) {
PyArrayObject *data_in_py;
PyArrayObject *data_out_py;
double cutoff;
int m;
int n;
double *data_in;
double *data_out;
int info;
if (!PyArg_ParseTuple(args, "OOd", &data_out_py, &data_in_py, &cutoff)) {
return NULL;
}
m = (int)PyArray_DIMS(data_in_py)[0];
n = (int)PyArray_DIMS(data_in_py)[1];
data_in = (double *)PyArray_DATA(data_in_py);
data_out = (double *)PyArray_DATA(data_out_py);
info = phonopy_pinv(data_out, data_in, m, n, cutoff);
return PyLong_FromLong((long)info);
}

View File

@ -40,10 +40,15 @@
#include <stdio.h>
#include <stdlib.h>
#include "lapack_wrapper.h"
// #include "lapack_wrapper.h"
#include "phono3py.h"
#include "phonoc_array.h"
typedef struct {
double re;
double im;
} _lapack_complex_double;
static PyObject *py_get_interaction(PyObject *self, PyObject *args);
static PyObject *py_get_pp_collision(PyObject *self, PyObject *args);
static PyObject *py_get_pp_collision_with_sigma(PyObject *self, PyObject *args);
@ -92,10 +97,8 @@ static PyObject *py_diagonalize_collision_matrix(PyObject *self,
PyObject *args);
static PyObject *py_pinv_from_eigensolution(PyObject *self, PyObject *args);
static PyObject *py_get_default_colmat_solver(PyObject *self, PyObject *args);
static PyObject *py_lapacke_pinv(PyObject *self, PyObject *args);
static void pinv_from_eigensolution(double *data, const double *eigvals,
const long size, const double cutoff,
const long pinv_method);
static void show_colmat_info(const PyArrayObject *collision_matrix_py,
const long i_sigma, const long i_temp,
const long adrs_shift);
@ -206,6 +209,8 @@ static PyMethodDef _phono3py_methods[] = {
METH_VARARGS, "Pseudo-inverse from eigensolution"},
{"default_colmat_solver", (PyCFunction)py_get_default_colmat_solver,
METH_VARARGS, "Return default collison matrix solver by integer value"},
{"lapacke_pinv", (PyCFunction)py_lapacke_pinv, METH_VARARGS,
"Pseudo inversion using lapacke."},
{NULL, NULL, 0, NULL}};
#if PY_MAJOR_VERSION >= 3
@ -276,7 +281,7 @@ static PyObject *py_get_interaction(PyObject *self, PyObject *args) {
Darray *fc3_normal_squared;
Darray *freqs;
lapack_complex_double *eigvecs;
_lapack_complex_double *eigvecs;
long(*triplets)[3];
long num_triplets;
char *g_zero;
@ -307,7 +312,7 @@ static PyObject *py_get_interaction(PyObject *self, PyObject *args) {
freqs = convert_to_darray(py_frequencies);
/* npy_cdouble and lapack_complex_double may not be compatible. */
/* So eigenvectors should not be used in Python side */
eigvecs = (lapack_complex_double *)PyArray_DATA(py_eigenvectors);
eigvecs = (_lapack_complex_double *)PyArray_DATA(py_eigenvectors);
triplets = (long(*)[3])PyArray_DATA(py_triplets);
num_triplets = (long)PyArray_DIMS(py_triplets)[0];
g_zero = (char *)PyArray_DATA(py_g_zero);
@ -371,7 +376,7 @@ static PyObject *py_get_pp_collision(PyObject *self, PyObject *args) {
double *gamma;
long(*relative_grid_address)[4][3];
double *frequencies;
lapack_complex_double *eigenvectors;
_lapack_complex_double *eigenvectors;
long(*triplets)[3];
long num_triplets;
long *triplet_weights;
@ -405,7 +410,7 @@ static PyObject *py_get_pp_collision(PyObject *self, PyObject *args) {
relative_grid_address =
(long(*)[4][3])PyArray_DATA(py_relative_grid_address);
frequencies = (double *)PyArray_DATA(py_frequencies);
eigenvectors = (lapack_complex_double *)PyArray_DATA(py_eigenvectors);
eigenvectors = (_lapack_complex_double *)PyArray_DATA(py_eigenvectors);
triplets = (long(*)[3])PyArray_DATA(py_triplets);
num_triplets = (long)PyArray_DIMS(py_triplets)[0];
triplet_weights = (long *)PyArray_DATA(py_triplet_weights);
@ -471,7 +476,7 @@ static PyObject *py_get_pp_collision_with_sigma(PyObject *self,
double *gamma;
double *frequencies;
lapack_complex_double *eigenvectors;
_lapack_complex_double *eigenvectors;
long(*triplets)[3];
long num_triplets;
long *triplet_weights;
@ -502,7 +507,7 @@ static PyObject *py_get_pp_collision_with_sigma(PyObject *self,
gamma = (double *)PyArray_DATA(py_gamma);
frequencies = (double *)PyArray_DATA(py_frequencies);
eigenvectors = (lapack_complex_double *)PyArray_DATA(py_eigenvectors);
eigenvectors = (_lapack_complex_double *)PyArray_DATA(py_eigenvectors);
triplets = (long(*)[3])PyArray_DATA(py_triplets);
num_triplets = (long)PyArray_DIMS(py_triplets)[0];
triplet_weights = (long *)PyArray_DATA(py_triplet_weights);
@ -910,7 +915,7 @@ static PyObject *py_get_isotope_strength(PyObject *self, PyObject *args) {
double *gamma;
double *frequencies;
lapack_complex_double *eigenvectors;
_lapack_complex_double *eigenvectors;
long *band_indices;
double *mass_variances;
long num_band, num_band0;
@ -924,7 +929,7 @@ static PyObject *py_get_isotope_strength(PyObject *self, PyObject *args) {
gamma = (double *)PyArray_DATA(py_gamma);
frequencies = (double *)PyArray_DATA(py_frequencies);
eigenvectors = (lapack_complex_double *)PyArray_DATA(py_eigenvectors);
eigenvectors = (_lapack_complex_double *)PyArray_DATA(py_eigenvectors);
band_indices = (long *)PyArray_DATA(py_band_indices);
mass_variances = (double *)PyArray_DATA(py_mass_variances);
num_band = (long)PyArray_DIMS(py_frequencies)[1];
@ -954,7 +959,7 @@ static PyObject *py_get_thm_isotope_strength(PyObject *self, PyObject *args) {
double *frequencies;
long *ir_grid_points;
long *weights;
lapack_complex_double *eigenvectors;
_lapack_complex_double *eigenvectors;
long *band_indices;
double *mass_variances;
long num_band, num_band0, num_ir_grid_points;
@ -971,7 +976,7 @@ static PyObject *py_get_thm_isotope_strength(PyObject *self, PyObject *args) {
frequencies = (double *)PyArray_DATA(py_frequencies);
ir_grid_points = (long *)PyArray_DATA(py_ir_grid_points);
weights = (long *)PyArray_DATA(py_weights);
eigenvectors = (lapack_complex_double *)PyArray_DATA(py_eigenvectors);
eigenvectors = (_lapack_complex_double *)PyArray_DATA(py_eigenvectors);
band_indices = (long *)PyArray_DATA(py_band_indices);
mass_variances = (double *)PyArray_DATA(py_mass_variances);
num_band = (long)PyArray_DIMS(py_frequencies)[1];
@ -1763,92 +1768,29 @@ static PyObject *py_get_default_colmat_solver(PyObject *self, PyObject *args) {
#endif
}
static void pinv_from_eigensolution(double *data, const double *eigvals,
const long size, const double cutoff,
const long pinv_method) {
long i, ib, j, k, max_l, i_s, j_s;
double *tmp_data;
double e, sum;
long *l;
static PyObject *py_lapacke_pinv(PyObject *self, PyObject *args) {
PyArrayObject *data_in_py;
PyArrayObject *data_out_py;
double cutoff;
l = NULL;
tmp_data = NULL;
int m;
int n;
double *data_in;
double *data_out;
int info;
tmp_data = (double *)malloc(sizeof(double) * size * size);
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (i = 0; i < size * size; i++) {
tmp_data[i] = data[i];
if (!PyArg_ParseTuple(args, "OOd", &data_out_py, &data_in_py, &cutoff)) {
return NULL;
}
l = (long *)malloc(sizeof(long) * size);
max_l = 0;
for (i = 0; i < size; i++) {
if (pinv_method == 0) {
e = fabs(eigvals[i]);
} else {
e = eigvals[i];
}
if (e > cutoff) {
l[max_l] = i;
max_l++;
}
}
m = (int)PyArray_DIMS(data_in_py)[0];
n = (int)PyArray_DIMS(data_in_py)[1];
data_in = (double *)PyArray_DATA(data_in_py);
data_out = (double *)PyArray_DATA(data_out_py);
#ifdef _OPENMP
#pragma omp parallel for private(ib, j, k, i_s, j_s, sum)
#endif
for (i = 0; i < size / 2; i++) {
/* from front */
i_s = i * size;
for (j = i; j < size; j++) {
j_s = j * size;
sum = 0;
for (k = 0; k < max_l; k++) {
sum +=
tmp_data[i_s + l[k]] * tmp_data[j_s + l[k]] / eigvals[l[k]];
}
data[i_s + j] = sum;
data[j_s + i] = sum;
}
/* from back */
ib = size - i - 1;
i_s = ib * size;
for (j = ib; j < size; j++) {
j_s = j * size;
sum = 0;
for (k = 0; k < max_l; k++) {
sum +=
tmp_data[i_s + l[k]] * tmp_data[j_s + l[k]] / eigvals[l[k]];
}
data[i_s + j] = sum;
data[j_s + ib] = sum;
}
}
info = phonopy_pinv(data_out, data_in, m, n, cutoff);
/* when size is odd */
if ((size % 2) == 1) {
i = (size - 1) / 2;
i_s = i * size;
for (j = i; j < size; j++) {
j_s = j * size;
sum = 0;
for (k = 0; k < max_l; k++) {
sum +=
tmp_data[i_s + l[k]] * tmp_data[j_s + l[k]] / eigvals[l[k]];
}
data[i_s + j] = sum;
data[j_s + i] = sum;
}
}
free(l);
l = NULL;
free(tmp_data);
tmp_data = NULL;
return PyLong_FromLong((long)info);
}
static void show_colmat_info(const PyArrayObject *py_collision_matrix,

View File

@ -35,9 +35,14 @@
#include <Python.h>
#include <numpy/arrayobject.h>
#include "lapack_wrapper.h"
// #include "lapack_wrapper.h"
#include "phononmod.h"
typedef struct {
double re;
double im;
} _lapack_complex_double;
static PyObject *py_get_phonons_at_gridpoints(PyObject *self, PyObject *args);
struct module_state {
@ -139,7 +144,7 @@ static PyObject *py_get_phonons_at_gridpoints(PyObject *self, PyObject *args) {
double(*dielectric)[3];
double *q_dir;
double *freqs;
lapack_complex_double *eigvecs;
_lapack_complex_double *eigvecs;
char *phonon_done;
long *grid_points;
long(*grid_address)[3];
@ -168,7 +173,7 @@ static PyObject *py_get_phonons_at_gridpoints(PyObject *self, PyObject *args) {
}
freqs = (double *)PyArray_DATA(py_frequencies);
eigvecs = (lapack_complex_double *)PyArray_DATA(py_eigenvectors);
eigvecs = (_lapack_complex_double *)PyArray_DATA(py_eigenvectors);
phonon_done = (char *)PyArray_DATA(py_phonon_done);
grid_points = (long *)PyArray_DATA(py_grid_points);
grid_address = (long(*)[3])PyArray_DATA(py_grid_address);

View File

@ -34,6 +34,8 @@
#include "lapack_wrapper.h"
#include <math.h>
#define min(a, b) ((a) > (b) ? (b) : (a))
#if defined(MKL_LAPACKE) || defined(SCIPY_MKL_H)
@ -194,3 +196,91 @@ lapack_complex_double phonoc_complex_prod(const lapack_complex_double a,
lapack_complex_double_real(a) * lapack_complex_double_imag(b));
return c;
}
void pinv_from_eigensolution(double *data, const double *eigvals,
const long size, const double cutoff,
const long pinv_method) {
long i, ib, j, k, max_l, i_s, j_s;
double *tmp_data;
double e, sum;
long *l;
l = NULL;
tmp_data = NULL;
tmp_data = (double *)malloc(sizeof(double) * size * size);
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (i = 0; i < size * size; i++) {
tmp_data[i] = data[i];
}
l = (long *)malloc(sizeof(long) * size);
max_l = 0;
for (i = 0; i < size; i++) {
if (pinv_method == 0) {
e = fabs(eigvals[i]);
} else {
e = eigvals[i];
}
if (e > cutoff) {
l[max_l] = i;
max_l++;
}
}
#ifdef _OPENMP
#pragma omp parallel for private(ib, j, k, i_s, j_s, sum)
#endif
for (i = 0; i < size / 2; i++) {
/* from front */
i_s = i * size;
for (j = i; j < size; j++) {
j_s = j * size;
sum = 0;
for (k = 0; k < max_l; k++) {
sum +=
tmp_data[i_s + l[k]] * tmp_data[j_s + l[k]] / eigvals[l[k]];
}
data[i_s + j] = sum;
data[j_s + i] = sum;
}
/* from back */
ib = size - i - 1;
i_s = ib * size;
for (j = ib; j < size; j++) {
j_s = j * size;
sum = 0;
for (k = 0; k < max_l; k++) {
sum +=
tmp_data[i_s + l[k]] * tmp_data[j_s + l[k]] / eigvals[l[k]];
}
data[i_s + j] = sum;
data[j_s + ib] = sum;
}
}
/* when size is odd */
if ((size % 2) == 1) {
i = (size - 1) / 2;
i_s = i * size;
for (j = i; j < size; j++) {
j_s = j * size;
sum = 0;
for (k = 0; k < max_l; k++) {
sum +=
tmp_data[i_s + l[k]] * tmp_data[j_s + l[k]] / eigvals[l[k]];
}
data[i_s + j] = sum;
data[j_s + i] = sum;
}
}
free(l);
l = NULL;
free(tmp_data);
tmp_data = NULL;
}

View File

@ -59,4 +59,7 @@ int phonopy_dsyev(double *data, double *eigvals, const int size,
lapack_complex_double phonoc_complex_prod(const lapack_complex_double a,
const lapack_complex_double b);
void pinv_from_eigensolution(double *data, const double *eigvals,
const long size, const double cutoff,
const long pinv_method);
#endif

View File

@ -444,7 +444,7 @@ def _solve_fc3(
solver = "numpy.linalg.pinv"
else:
try:
import phono3py._lapackepy as lapackepy
import phono3py._phono3py as phono3c
solver = "lapacke-dgesvd"
except ImportError:
@ -496,7 +496,7 @@ def _solve_fc3(
inv_U = np.zeros(
(rot_disps.shape[1], rot_disps.shape[0]), dtype="double", order="C"
)
lapackepy.pinv(inv_U, rot_disps, 1e-13)
phono3c.lapacke_pinv(inv_U, rot_disps, 1e-13)
fc3 = np.zeros((num_atom, num_atom, 3, 3, 3), dtype="double", order="C")

View File

@ -1,5 +1,7 @@
[build-system]
requires = ["setuptools", "wheel", "numpy", "oldest-supported-numpy"]
requires = ["setuptools", "wheel", "numpy"]
#requires = ["setuptools", "wheel", "numpy", "oldest-supported-numpy"]
#build-backend = "setuptools.build_meta"
[tool.flake8]
max-line-length = 88

204
setup.py
View File

@ -1,135 +1,113 @@
"""Phono3py setup.py."""
"""Phono3py setup.py.
The build steps are as follows:
mkdir _build && cd _build
cmake -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=1 \
-DPHONONMOD=on -DPHONO3PY=on -DCMAKE_INSTALL_PREFIX="" ..
cmake --build . -v
cd ..
python setup.py build
pip install -e .
"""
import os
import pathlib
import shutil
import subprocess
import numpy
import setuptools
# Ensure that 'site.cfg' exists.
if not os.path.exists("site.cfg"):
msg_list = [
'"site.cfg" file is needed to run setup.py.',
"See about installation at https://phonopy.github.io/phono3py/install.html.",
"A minimum setting of site.cfg to build with openmp support is:",
"# ------------------------------",
"[phono3py]",
"extra_compile_args = -fopenmp",
"# ------------------------------",
"Please create an emply site.cfg (no-openmp support) to run setup.py",
"unless any custom setting is needed, although this is considered unusual.",
def _run_cmake(build_dir):
build_dir.mkdir()
args = [
"cmake",
"-S",
".",
"-B",
"_build",
"-DPHONONMOD=on",
"-DPHONO3PY=on",
"-DCMAKE_INSTALL_PREFIX=.",
]
# if "CONDA_PREFIX" in os.environ:
# args.append("-DUSE_CONDA_PATH=on")
# if "CC" in os.environ:
# args.append(f'-DCMAKE_C_COMPILER={os.environ["CC"]}')
raise FileNotFoundError("\n".join(msg_list))
cmake_output = subprocess.check_output(args)
print(cmake_output.decode("utf-8"))
subprocess.check_call(["cmake", "--build", "_build", "-v"])
return cmake_output
# Retrieve the default flags from the numpy installation
# This also means one can override this with a site.cfg
# configuration file
from numpy.distutils.system_info import dict_append, get_info, system_info
def _clean_cmake(build_dir):
shutil.rmtree(build_dir)
build_dir = pathlib.Path.cwd() / "_build"
found_extra_link_args = []
found_extra_compile_args = []
define_macros = []
use_mkl_lapacke = False
if build_dir.exists():
pass
else:
cmake_output = _run_cmake(build_dir)
found_flags = {}
found_libs = {}
for line in cmake_output.decode("utf-8").split("\n"):
for key in ["BLAS", "LAPACK", "OpenMP"]:
if f"{key} libs" in line and len(line.split()) > 3:
found_libs[key] = line.split()[3].split(";")
if f"{key} flags" in line and len(line.split()) > 3:
found_flags[key] = line.split()[3].split(";")
for key, value in found_libs.items():
found_extra_link_args += value
for element in value:
if "libmkl" in element:
use_mkl_lapacke = True
for key, value in found_flags.items():
found_extra_compile_args += value
if use_mkl_lapacke:
define_macros.append(("MKL_LAPACKE", None))
print("=============================================")
print(found_extra_compile_args)
print(found_extra_link_args)
print(define_macros)
print("=============================================")
git_num = None
# use flags defined in numpy
all_info_d = get_info("ALL")
lapack_info_d = get_info("lapack_opt")
class phono3py_info(system_info):
"""See system_info in numpy."""
section = "phono3py"
def calc_info(self):
"""Read in *all* options in the [phono3py] section of site.cfg."""
info = self.calc_libraries_info()
dict_append(info, **self.calc_extra_info())
dict_append(info, include_dirs=self.get_include_dirs())
self.set_info(**info)
macros = []
# in numpy>=1.16.0, silence build warnings about deprecated API usage
macros.append(("NPY_NO_DEPRECATED_API", "0"))
# Avoid divergence in tetrahedron method by ensuring denominator > 1e-10.
# macros.append(("THM_EPSILON", "1e-10"))
with_threaded_blas = False
with_mkl = False
# define options
# these are the basic definitions for all extensions
opts = lapack_info_d.copy()
if "mkl" in opts.get("libraries", ""):
with_mkl = True
if with_mkl:
with_threaded_blas = True
# generally this should not be needed since the numpy distutils
# finding of MKL creates the SCIPY_MKL_H flag
macros.append(("MKL_LAPACKE", None))
if with_threaded_blas:
macros.append(("MULTITHREADED_BLAS", None))
# Create the dictionary for compiling the codes
dict_append(opts, **all_info_d)
dict_append(opts, include_dirs=["c"])
dict_append(opts, define_macros=macros)
# Add numpy's headers
include_dirs = numpy.get_include()
if include_dirs is not None:
dict_append(opts, include_dirs=[include_dirs])
# Add any phono3py manual flags from here
add_opts = phono3py_info().get_info()
dict_append(opts, **add_opts)
include_dirs = ["c", numpy.get_include()]
# if "CONDA_PREFIX" in os.environ:
# include_dirs.append(os.environ["CONDA_PREFIX"] + "/include")
# Different extensions
extensions = []
# Define the modules
sources_phono3py = [
"c/_phono3py.c",
"c/bzgrid.c",
"c/collision_matrix.c",
"c/fc3.c",
"c/grgrid.c",
"c/imag_self_energy_with_g.c",
"c/interaction.c",
"c/isotope.c",
"c/lagrid.c",
"c/lapack_wrapper.c",
"c/phono3py.c",
"c/phonoc_utils.c",
"c/pp_collision.c",
"c/real_self_energy.c",
"c/real_to_reciprocal.c",
"c/reciprocal_to_normal.c",
"c/snf3x3.c",
"c/tetrahedron_method.c",
"c/triplet.c",
"c/triplet_grid.c",
"c/triplet_iw.c",
]
extensions.append(
setuptools.Extension("phono3py._phono3py", sources=sources_phono3py, **opts)
setuptools.Extension(
"phono3py._phono3py",
sources=["c/_phono3py.c"],
extra_link_args=["_build/libph3py.a"] + found_extra_link_args,
include_dirs=include_dirs,
extra_compile_args=found_extra_compile_args,
define_macros=define_macros,
)
)
sources_phononmod = [
"c/_phononmod.c",
"c/dynmat.c",
"c/lapack_wrapper.c",
"c/phonon.c",
"c/phononmod.c",
]
extensions.append(
setuptools.Extension("phono3py._phononmod", sources=sources_phononmod, **opts)
setuptools.Extension(
"phono3py._phononmod",
sources=["c/_phononmod.c"],
extra_link_args=["_build/libphmod.a"] + found_extra_link_args,
include_dirs=include_dirs,
extra_compile_args=found_extra_compile_args,
define_macros=define_macros,
)
sources_lapackepy = ["c/_lapackepy.c", "c/lapack_wrapper.c"]
extensions.append(
setuptools.Extension("phono3py._lapackepy", sources=sources_lapackepy, **opts)
)
packages_phono3py = [
@ -204,3 +182,5 @@ if __name__ == "__main__":
scripts=scripts_phono3py,
ext_modules=extensions,
)
_clean_cmake(build_dir)