#include #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #include #include #include #define MAX_STR_LEN 512 static int verbose = 0; typedef struct { int nion; int ns; int nk; int nb; int nlmmax; int nc_flag; int isdouble; } t_params; static PyObject* io_read_plocar(PyObject *self, PyObject *args); PyObject* create_par_dictionary(t_params* p); PyArrayObject* create_plo_array(t_params* p); PyArrayObject* create_ferw_array(t_params* p); int read_arrays(FILE* fh, t_params* p, PyArrayObject* py_plo, PyArrayObject* py_ferw); // Python module descriptor static PyMethodDef c_proj_io[] = { {"parse_proj_vasp", io_parse_proj_vasp, METH_VARARGS, "Reads projectors from PROJCAR and LOCPROJ"}, {NULL, NULL, 0, NULL} }; PyMODINIT_FUNC initc_proj_io(void) { (void) Py_InitModule("c_proj_io", c_proj_io); import_array(); } /* Main function. Reads data from the specified file (default is 'PLOCAR') and returns it as a Python tuple. */ static PyObject * io_parse_proj_vasp(PyObject *self, PyObject *args) { PyArrayObject *py_plo = NULL; PyArrayObject *py_ferw = NULL; PyObject *par_dict = NULL; PyObject *ret_tuple = NULL; char *fname = "PLOCAR"; char *fname_locproj = "LOCPROJ"; char *fname_projcar = "PROJCAR"; char errmsg[MAX_STR_LEN] = {"\0"}; FILE* fh_l, fh_p; int prec; t_params params; // if(!PyArg_ParseTuple(args, "|s", &fname)) // return NULL; if(verbose) printf(" Reading projectors from PROJCAR and LOCPROJ\n"); // // Read the first line from LOCPROJ // fh_l = fopen(fname_locproj, "r"); fh_p = fopen(fname_projcar, "r"); if(fh_l == NULL) { // Treat this error separately because no clean-up is necessary snprintf(errmsg, MAX_STR_LEN, "Error opening %s\n%s", fname_locproj, strerror(errno)); PyErr_SetString(PyExc_IOError, errmsg); return NULL; } if(fh_p == NULL) { // Treat this error separately because no clean-up is necessary snprintf(errmsg, MAX_STR_LEN, "Error opening %s\n%s", fname_projcar, strerror(errno)); PyErr_SetString(PyExc_IOError, errmsg); return NULL; } /* if(!fread(&prec, 4, 1, fh)) goto ioerror; if(!fread(¶ms.nion, 4, 1, fh)) goto ioerror; if(!fread(¶ms.ns, 4, 1, fh)) goto ioerror; if(!fread(¶ms.nk, 4, 1, fh)) goto ioerror; if(!fread(¶ms.nb, 4, 1, fh)) goto ioerror; if(!fread(¶ms.nlmmax, 4, 1, fh)) goto ioerror; if(!fread(¶ms.nc_flag, 4, 1, fh)) goto ioerror; switch(prec) { case 8: params.isdouble = 1; if(verbose) printf(" Data in double precision\n"); break; case 4: params.isdouble = 0; if(verbose) printf(" Data in single precision\n"); break; default: PyErr_SetString(PyExc_ValueError, "Error reading PLOCAR: only 'prec = 4, 8' are supported"); goto error; } if(verbose) { printf(" nion: %d\n", params.nion); printf(" ns: %d\n", params.ns); printf(" nk: %d\n", params.nk); printf(" nb: %d\n", params.nb); printf(" nlmmax: %d\n", params.nlmmax); printf(" nc_flag: %d\n", params.nc_flag); } // // Create parameter dictionary // par_dict = create_par_dictionary(¶ms); // // Create PLO and Fermi-weight arrays // py_plo = create_plo_array(¶ms); py_ferw = create_ferw_array(¶ms); // // Read the data from file // if(read_arrays(fh, ¶ms, py_plo, py_ferw)) goto ioerror; // // Create return tuple // ret_tuple = PyTuple_New(3); if(PyTuple_SetItem(ret_tuple, 0, par_dict) < 0) { PyErr_SetString(PyExc_ValueError, "Error adding element to the return tuple (parameter dictionary)"); goto error; } if(PyTuple_SetItem(ret_tuple, 1, (PyObject *)py_plo) < 0) { PyErr_SetString(PyExc_ValueError, "Error adding element to the return tuple (PLO array)"); goto error; } if(PyTuple_SetItem(ret_tuple, 2, (PyObject *)py_ferw) < 0) { PyErr_SetString(PyExc_ValueError, "Error adding element to the return tuple (Fermi-weight array)"); goto error; } // Py_DECREF(par_dict); fclose(fh); return ret_tuple; // // Handle IO-errors // ioerror: if(feof(fh)) { snprintf(errmsg, MAX_STR_LEN, "End-of-file reading %s", fname); PyErr_SetString(PyExc_IOError, errmsg); } else { snprintf(errmsg, MAX_STR_LEN, "Error reading %s: %s", fname, strerror(errno)); PyErr_SetString(PyExc_IOError, errmsg); } */ // // Clean-up after an error // error: fclose(fh); Py_XDECREF(par_dict); Py_XDECREF(py_plo); Py_XDECREF(py_ferw); Py_XDECREF(ret_tuple); return NULL; } // // Auxiliary functions // PyObject* create_par_dictionary(t_params* p) { PyObject *par_dict = PyDict_New(); PyDict_SetItemString(par_dict, "nion", PyInt_FromLong((long)p->nion)); PyDict_SetItemString(par_dict, "ns", PyInt_FromLong((long)p->ns)); PyDict_SetItemString(par_dict, "nk", PyInt_FromLong((long)p->nk)); PyDict_SetItemString(par_dict, "nb", PyInt_FromLong((long)p->nb)); PyDict_SetItemString(par_dict, "nc_flag", PyInt_FromLong((long)p->nc_flag)); return par_dict; } PyArrayObject* create_plo_array(t_params* p) { double complex *plo; npy_intp *dims; int ntot = p->nion * p->ns * p->nk * p->nb * p->nlmmax; int ndim = 5; plo = (double complex*)malloc(ntot * sizeof(double complex)); memset(plo, 0, ntot * sizeof(double complex)); dims = (npy_intp *)malloc(ndim * sizeof(npy_intp)); dims[0] = p->nion; dims[1] = p->ns; dims[2] = p->nk; dims[3] = p->nb; dims[4] = p->nlmmax; return (PyArrayObject *)PyArray_SimpleNewFromData(ndim, dims, NPY_CDOUBLE, plo); } PyArrayObject* create_ferw_array(t_params* p) { double *ferw; npy_intp *dims; int ntot = p->nion * p->ns * p->nk * p->nb; int ndim = 4; ferw = (double *)malloc(ntot * sizeof(double)); memset(ferw, 0, ntot * sizeof(double)); dims = (npy_intp *)malloc(ndim * sizeof(npy_intp)); dims[0] = p->nion; dims[1] = p->ns; dims[2] = p->nk; dims[3] = p->nb; return (PyArrayObject *)PyArray_SimpleNewFromData(ndim, dims, NPY_DOUBLE, ferw); } int read_arrays(FILE* fh, t_params* p, PyArrayObject* py_plo, PyArrayObject* py_ferw) { double complex *plo; double *ferw; npy_intp idx5[5]; int ilm; int nlm; float rtmp; float complex rbuf[50]; double dtmp; double complex dbuf[50]; idx5[4] = 0; for(idx5[0] = 0; idx5[0] < p->nion; idx5[0]++) { if(fread(&nlm, 4, 1, fh) < 1) goto error; // printf(" nlm = %d\n", nlm); for(idx5[1] = 0; idx5[1] < p->ns; idx5[1]++) for(idx5[2] = 0; idx5[2] < p->nk; idx5[2]++) for(idx5[3] = 0; idx5[3] < p->nb; idx5[3]++) { // Get the pointers to corresponding elements according to the new API plo = (double complex *)PyArray_GetPtr(py_plo, idx5); // Here, only the first 4 elements of idx5 are used ferw = (double *)PyArray_GetPtr(py_ferw, idx5); if(p->isdouble) { if(fread(&dtmp, sizeof(double), 1, fh) < 1) goto error; if(fread(dbuf, sizeof(double complex), nlm, fh) < nlm) goto error; ferw[0] = dtmp; // printf("%5d %5d %5d %5d %lf\n", ion, is, ik, ib, dtmp); memcpy(plo, dbuf, nlm * sizeof(double complex)); } else { if(fread(&rtmp, sizeof(float), 1, fh) < 1) goto error; if(fread(rbuf, sizeof(float complex), nlm, fh) < nlm) goto error; ferw[0] = (double)rtmp; // printf("%5d %5d %5d %5d %f\n", ion, is, ik, ib, rtmp); // In this case destination and source arrays are not compatible, // we have to copy element-wise for(ilm = 0; ilm < nlm; ilm++) { plo[ilm] = (double complex)rbuf[ilm]; // printf("%5d %5d %f\n", ilm, ind2 + ilm, rbuf[ilm]); } } // if p->isdouble } } return 0; error: return -1; }