gpaw-0.11.0.13004/0000775000175000017500000000000012553644063013453 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/LICENSE0000664000175000017500000000111412553643466014463 0ustar jensjjensj00000000000000GPAW is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GPAW is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GPAW. If not, see . gpaw-0.11.0.13004/c/0000775000175000017500000000000012553644063013675 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/c/utilities.c0000664000175000017500000005406412553643466016073 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2008 CAMd * Copyright (C) 2008-2010 CSC - IT Center for Science Ltd. * Copyright (C) 2011 Argonne National Laboratory * Please see the accompanying LICENSE file for further information. */ #include #define PY_ARRAY_UNIQUE_SYMBOL GPAW_ARRAY_API #define NO_IMPORT_ARRAY #include #include "extensions.h" #include #include #ifdef __DARWIN_UNIX03 /* Allows for special MaxOS magic */ #include #endif #ifdef __linux__ /* stdlib.h does not define mallinfo (it should!) */ #include #endif #ifdef GPAW_HPM void HPM_Start(char *); void HPM_Stop(char *); void summary_start(void); void summary_stop(void); PyObject* ibm_hpm_start(PyObject *self, PyObject *args) { char* s; if (!PyArg_ParseTuple(args, "s", &s)) return NULL; HPM_Start(s); Py_RETURN_NONE; } PyObject* ibm_hpm_stop(PyObject *self, PyObject *args) { char* s; if (!PyArg_ParseTuple(args, "s", &s)) return NULL; HPM_Stop(s); Py_RETURN_NONE; } PyObject* ibm_mpi_start(PyObject *self) { summary_start(); Py_RETURN_NONE; } PyObject* ibm_mpi_stop(PyObject *self) { summary_stop(); Py_RETURN_NONE; } #endif #ifdef CRAYPAT #include PyObject* craypat_region_begin(PyObject *self, PyObject *args) { int n; char* s; if (!PyArg_ParseTuple(args, "is", &n, &s)) return NULL; PAT_region_begin(n, s); Py_RETURN_NONE; } PyObject* craypat_region_end(PyObject *self, PyObject *args) { int n; if (!PyArg_ParseTuple(args, "i", &n)) return NULL; PAT_region_end(n); Py_RETURN_NONE; } #endif #ifdef PARALLEL #include struct eval { double val; int rank; }; static void coll_print(FILE *fp, const char *label, double val, int print_aggregate, MPI_Comm Comm){ double sum; struct eval in; struct eval out; int rank, numranks; MPI_Comm_size(Comm, &numranks); MPI_Comm_rank(Comm, &rank); in.val=val; in.rank=rank; MPI_Reduce(&val, &sum, 1, MPI_DOUBLE, MPI_SUM, 0, Comm); if(rank==0) { if(print_aggregate) fprintf(fp,"#%19s %14.3f %10.3f ",label,sum,sum/numranks); else fprintf(fp,"#%19s %10.3f ",label,sum/numranks); } MPI_Reduce(&in, &out, 1, MPI_DOUBLE_INT, MPI_MINLOC, 0, Comm); if(rank==0){ fprintf(fp,"%4d %10.3f ", out.rank, out.val); } MPI_Reduce(&in, &out, 1, MPI_DOUBLE_INT, MPI_MAXLOC, 0, Comm); if(rank==0){ fprintf(fp,"%4d %10.3f\n",out.rank, out.val); } } // Utilities for performance measurement with PAPI #ifdef GPAW_PAPI #include #define NUM_PAPI_EV 1 static long_long papi_start_usec_p; static long_long papi_start_usec_r; // Returns PAPI_dmem_info structure in Python dictionary // Units used by PAPI are kB PyObject* papi_mem_info(PyObject *self, PyObject *args) { PAPI_dmem_info_t dmem; PyObject* py_dmem; PAPI_get_dmem_info(&dmem); py_dmem = PyDict_New(); PyDict_SetItemString(py_dmem, "peak", PyLong_FromLongLong(dmem.peak)); PyDict_SetItemString(py_dmem, "size", PyLong_FromLongLong(dmem.size)); PyDict_SetItemString(py_dmem, "resident", PyLong_FromLongLong(dmem.resident)); PyDict_SetItemString(py_dmem, "high_water_mark", PyLong_FromLongLong(dmem.high_water_mark)); PyDict_SetItemString(py_dmem, "shared", PyLong_FromLongLong(dmem.shared)); PyDict_SetItemString(py_dmem, "text", PyLong_FromLongLong(dmem.text)); PyDict_SetItemString(py_dmem, "library", PyLong_FromLongLong(dmem.library)); PyDict_SetItemString(py_dmem, "heap", PyLong_FromLongLong(dmem.heap)); PyDict_SetItemString(py_dmem, "stack", PyLong_FromLongLong(dmem.stack)); PyDict_SetItemString(py_dmem, "pagesize", PyLong_FromLongLong(dmem.pagesize)); PyDict_SetItemString(py_dmem, "pte", PyLong_FromLongLong(dmem.pte)); return py_dmem; } int gpaw_perf_init() { int events[NUM_PAPI_EV]; events[0] = PAPI_FP_OPS; // events[1] = PAPI_L1_DCM; // events[2] = PAPI_L1_DCH; // events[3] = PAPI_TOT_INS; PAPI_start_counters(events, NUM_PAPI_EV); papi_start_usec_r = PAPI_get_real_usec(); papi_start_usec_p = PAPI_get_virt_usec(); return 0; } void gpaw_perf_finalize() { long long papi_values[NUM_PAPI_EV]; double rtime,ptime; double avegflops; double gflop_opers; PAPI_dmem_info_t dmem; int error = 0; double l1hitratio; long_long papi_end_usec_p; long_long papi_end_usec_r; int rank, numranks; MPI_Comm Comm = MPI_COMM_WORLD; //get papi info, first time it intializes PAPI counters papi_end_usec_r = PAPI_get_real_usec(); papi_end_usec_p = PAPI_get_virt_usec(); MPI_Comm_size(Comm, &numranks); MPI_Comm_rank(Comm, &rank); FILE *fp; if (rank == 0) fp = fopen("gpaw_perf.log", "w"); else fp = NULL; if(PAPI_read_counters(papi_values, NUM_PAPI_EV) != PAPI_OK) error++; if(PAPI_get_dmem_info(&dmem) != PAPI_OK) error++; rtime=(double)(papi_end_usec_r - papi_start_usec_r)/1e6; ptime=(double)(papi_end_usec_p - papi_start_usec_p)/1e6; avegflops=(double)papi_values[0]/rtime/1e9; gflop_opers = (double)papi_values[0]/1e9; // l1hitratio=100.0*(double)papi_values[1]/(papi_values[0] + papi_values[1]); if (rank==0 ) { fprintf(fp,"######## GPAW PERFORMANCE REPORT (PAPI) ########\n"); fprintf(fp,"# MPI tasks %d\n", numranks); fprintf(fp,"# aggregated average min(rank/val) max(rank/val) \n"); } coll_print(fp, "Real time (s)", rtime, 1, Comm); coll_print(fp, "Process time (s)", ptime, 1, Comm); coll_print(fp, "Flops (GFlop/s)", avegflops, 1, Comm); coll_print(fp, "Flp-opers (10^9)", gflop_opers, 1, Comm); // coll_print(fp, "L1 hit ratio (%)", l1hitratio, 0, Comm); coll_print(fp, "Peak mem size (MB)", (double)dmem.peak/1.0e3, 0, Comm ); coll_print(fp, "Peak resident (MB)", (double)dmem.high_water_mark/1.0e3 , 0, Comm); if(rank==0) { fflush(fp); fclose(fp); } } #elif GPAW_HPM void HPM_Start(char *); int gpaw_perf_init() { HPM_Start("GPAW"); return 0; } void gpaw_perf_finalize() { HPM_Stop("GPAW"); } #else // Use just MPI_Wtime static double t0; int gpaw_perf_init(void) { t0 = MPI_Wtime(); return 0; } void gpaw_perf_finalize(void) { double rtime; int rank, numranks; MPI_Comm Comm = MPI_COMM_WORLD; MPI_Comm_size(Comm, &numranks); MPI_Comm_rank(Comm, &rank); double t1 = MPI_Wtime(); rtime = t1 - t0; FILE *fp; if (rank == 0) fp = fopen("gpaw_perf.log", "w"); else fp = NULL; if (rank==0 ) { fprintf(fp,"######## GPAW PERFORMANCE REPORT (MPI_Wtime) ########\n"); fprintf(fp,"# MPI tasks %d\n", numranks); fprintf(fp,"# aggregated average min(rank/val) max(rank/val) \n"); } coll_print(fp, "Real time (s)", rtime, 1, Comm); if(rank==0) { fflush(fp); fclose(fp); } } #endif #endif // returns the distance between two 3d double vectors double distance(double *a, double *b) { double sum = 0; double diff; for (int c = 0; c < 3; c++) { diff = a[c] - b[c]; sum += diff*diff; } return sqrt(sum); } /* get heap memory using mallinfo. There is a UNIX version and a Mac OS X version is not well tested but seems to give credible values in simple tests.*/ PyObject* heap_mallinfo(PyObject *self) { double heap; #ifdef __linux__ unsigned int mmap, arena, small; struct mallinfo mi; /* structure in bytes */ mi = mallinfo(); mmap = mi.hblkhd; arena = mi.uordblks; small = mi.usmblks; heap = ((double)(mmap + arena + small))/1024.0; /* convert to KB */ #elif defined(__DARWIN_UNIX03) /* Mac OS X specific hack */ struct malloc_statistics_t mi; /* structure in bytes */ malloc_zone_statistics(NULL, &mi); heap = ((double)(mi.size_in_use))/1024.0; /* convert to KB */ #else heap = -1; #endif return Py_BuildValue("d",heap); } /* elementwise multiply and add result to another vector * * c[i] += a[i] * b[i] , for i = every element in the vectors */ PyObject* elementwise_multiply_add(PyObject *self, PyObject *args) { PyArrayObject* aa; PyArrayObject* bb; PyArrayObject* cc; if (!PyArg_ParseTuple(args, "OOO", &aa, &bb, &cc)) return NULL; const double* const a = DOUBLEP(aa); const double* const b = DOUBLEP(bb); double* const c = DOUBLEP(cc); int n = 1; for (int d = 0; d < PyArray_NDIM(aa); d++) n *= PyArray_DIMS(aa)[d]; for (int i = 0; i < n; i++) { c[i] += a[i] * b[i]; } Py_RETURN_NONE; } PyObject* utilities_gaussian_wave(PyObject *self, PyObject *args) { Py_complex A_obj; PyArrayObject* r_cG_obj; PyArrayObject* r0_c_obj; Py_complex sigma_obj; // imaginary part ignored PyArrayObject* k_c_obj; PyArrayObject* gs_G_obj; if (!PyArg_ParseTuple(args, "DOODOO", &A_obj, &r_cG_obj, &r0_c_obj, &sigma_obj, &k_c_obj, &gs_G_obj)) return NULL; int C, G; C = PyArray_DIMS(r_cG_obj)[0]; G = PyArray_DIMS(r_cG_obj)[1]; for (int i = 2; i < PyArray_NDIM(r_cG_obj); i++) G *= PyArray_DIMS(r_cG_obj)[i]; double* r_cG = DOUBLEP(r_cG_obj); // XXX not ideally strided double* r0_c = DOUBLEP(r0_c_obj); double dr2, kr, alpha = -0.5/pow(sigma_obj.real, 2); int gammapoint = 1; double* k_c = DOUBLEP(k_c_obj); for (int c=0; ctype_num == NPY_DOUBLE) { double* gs_G = DOUBLEP(gs_G_obj); if(gammapoint) for(int g=0; g0) for(int g=0; g 1 ? } } else { double_complex* gs_G = COMPLEXP(gs_G_obj); double_complex A = A_obj.real+I*A_obj.imag; if(gammapoint) for(int g=0; g0) for(int g=0; g 1 ? } } Py_RETURN_NONE; } /* vdot * * If a and b are input vectors, * a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + ... * is returned. */ PyObject* utilities_vdot(PyObject *self, PyObject *args) { PyArrayObject* aa; PyArrayObject* bb; if (!PyArg_ParseTuple(args, "OO", &aa, &bb)) return NULL; const double* const a = DOUBLEP(aa); const double* const b = DOUBLEP(bb); double sum = 0.0; int n = 1; for (int d = 0; d < PyArray_NDIM(aa); d++) n *= PyArray_DIMS(aa)[d]; for (int i = 0; i < n; i++) { sum += a[i] * b[i]; } return PyFloat_FromDouble(sum); } /* vdot * * If a is the input vector, * a[0]*a[0] + a[1]*a[1] + a[2]*a[2] + ... * is returned. */ PyObject* utilities_vdot_self(PyObject *self, PyObject *args) { PyArrayObject* aa; if (!PyArg_ParseTuple(args, "O", &aa)) return NULL; const double* const a = DOUBLEP(aa); double sum = 0.0; int n = 1; for (int d = 0; d < PyArray_NDIM(aa); d++) n *= PyArray_DIMS(aa)[d]; for (int i = 0; i < n; i++) { sum += a[i] * a[i]; } return PyFloat_FromDouble(sum); } PyObject* errorfunction(PyObject *self, PyObject *args) { double x; if (!PyArg_ParseTuple(args, "d", &x)) return NULL; return Py_BuildValue("d", erf(x)); } PyObject* pack(PyObject *self, PyObject *args) { PyArrayObject* a_obj; if (!PyArg_ParseTuple(args, "O", &a_obj)) return NULL; a_obj = PyArray_GETCONTIGUOUS(a_obj); int n = PyArray_DIMS(a_obj)[0]; npy_intp dims[1] = {n * (n + 1) / 2}; int typenum = PyArray_DESCR(a_obj)->type_num; PyArrayObject* b_obj = (PyArrayObject*) PyArray_SimpleNew(1, dims, typenum); if (b_obj == NULL) return NULL; if (typenum == NPY_DOUBLE) { double* a = (double*)PyArray_DATA(a_obj); double* b = (double*)PyArray_DATA(b_obj); for (int r = 0; r < n; r++) { *b++ = a[r + n * r]; for (int c = r + 1; c < n; c++) *b++ = a[r + n * c] + a[c + n * r]; } } else { double complex* a = (double complex*)PyArray_DATA(a_obj); double complex* b = (double complex*)PyArray_DATA(b_obj); for (int r = 0; r < n; r++) { *b++ = a[r + n * r]; for (int c = r + 1; c < n; c++) *b++ = a[r + n * c] + a[c + n * r]; } } Py_DECREF(a_obj); PyObject* value = Py_BuildValue("O", b_obj); Py_DECREF(b_obj); return value; } PyObject* unpack(PyObject *self, PyObject *args) { PyArrayObject* ap; PyArrayObject* a; if (!PyArg_ParseTuple(args, "OO", &ap, &a)) return NULL; int n = PyArray_DIMS(a)[0]; double* datap = DOUBLEP(ap); double* data = DOUBLEP(a); for (int r = 0; r < n; r++) for (int c = r; c < n; c++) { double d = *datap++; data[c + r * n] = d; data[r + c * n] = d; } Py_RETURN_NONE; } PyObject* unpack_complex(PyObject *self, PyObject *args) { PyArrayObject* ap; PyArrayObject* a; if (!PyArg_ParseTuple(args, "OO", &ap, &a)) return NULL; int n = PyArray_DIMS(a)[0]; double_complex* datap = COMPLEXP(ap); double_complex* data = COMPLEXP(a); for (int r = 0; r < n; r++) for (int c = r; c < n; c++) { double_complex d = *datap++; data[c + r * n] = d; data[r + c * n] = conj(d); } Py_RETURN_NONE; } PyObject* hartree(PyObject *self, PyObject *args) { int l; PyArrayObject* nrdr_obj; PyArrayObject* r_obj; PyArrayObject* vr_obj; if (!PyArg_ParseTuple(args, "iOOO", &l, &nrdr_obj, &r_obj, &vr_obj)) return NULL; const int M = PyArray_DIM(nrdr_obj, 0); const double* nrdr = DOUBLEP(nrdr_obj); const double* r = DOUBLEP(r_obj); double* vr = DOUBLEP(vr_obj); double p = 0.0; double q = 0.0; for (int g = M - 1; g > 0; g--) { double R = r[g]; double rl = pow(R, l); double dp = nrdr[g] / rl; double rlp1 = rl * R; double dq = nrdr[g] * rlp1; vr[g] = (p + 0.5 * dp) * rlp1 - (q + 0.5 * dq) / rl; p += dp; q += dq; } vr[0] = 0.0; double f = 4.0 * M_PI / (2 * l + 1); for (int g = 1; g < M; g++) { double R = r[g]; vr[g] = f * (vr[g] + q / pow(R, l)); } Py_RETURN_NONE; } PyObject* localize(PyObject *self, PyObject *args) { PyArrayObject* Z_nnc; PyArrayObject* U_nn; if (!PyArg_ParseTuple(args, "OO", &Z_nnc, &U_nn)) return NULL; int n = PyArray_DIMS(U_nn)[0]; double complex (*Z)[n][3] = (double complex (*)[n][3])COMPLEXP(Z_nnc); double (*U)[n] = (double (*)[n])DOUBLEP(U_nn); double value = 0.0; for (int a = 0; a < n; a++) { for (int b = a + 1; b < n; b++) { double complex* Zaa = Z[a][a]; double complex* Zab = Z[a][b]; double complex* Zbb = Z[b][b]; double x = 0.0; double y = 0.0; for (int c = 0; c < 3; c++) { x += (0.25 * creal(Zbb[c] * conj(Zbb[c])) + 0.25 * creal(Zaa[c] * conj(Zaa[c])) - 0.5 * creal(Zaa[c] * conj(Zbb[c])) - creal(Zab[c] * conj(Zab[c]))); y += creal((Zaa[c] - Zbb[c]) * conj(Zab[c])); } double t = 0.25 * atan2(y, x); double C = cos(t); double S = sin(t); for (int i = 0; i < a; i++) for (int c = 0; c < 3; c++) { double complex Ziac = Z[i][a][c]; Z[i][a][c] = C * Ziac + S * Z[i][b][c]; Z[i][b][c] = C * Z[i][b][c] - S * Ziac; } for (int c = 0; c < 3; c++) { double complex Zaac = Zaa[c]; double complex Zabc = Zab[c]; double complex Zbbc = Zbb[c]; Zaa[c] = C * C * Zaac + 2 * C * S * Zabc + S * S * Zbbc; Zbb[c] = C * C * Zbbc - 2 * C * S * Zabc + S * S * Zaac; Zab[c] = S * C * (Zbbc - Zaac) + (C * C - S * S) * Zabc; } for (int i = a + 1; i < b; i++) for (int c = 0; c < 3; c++) { double complex Zaic = Z[a][i][c]; Z[a][i][c] = C * Zaic + S * Z[i][b][c]; Z[i][b][c] = C * Z[i][b][c] - S * Zaic; } for (int i = b + 1; i < n; i++) for (int c = 0; c < 3; c++) { double complex Zaic = Z[a][i][c]; Z[a][i][c] = C * Zaic + S * Z[b][i][c]; Z[b][i][c] = C * Z[b][i][c] - S * Zaic; } for (int i = 0; i < n; i++) { double Uia = U[i][a]; U[i][a] = C * Uia + S * U[i][b]; U[i][b] = C * U[i][b] - S * Uia; } } double complex* Zaa = Z[a][a]; for (int c = 0; c < 3; c++) value += creal(Zaa[c] * conj(Zaa[c])); } return Py_BuildValue("d", value); } PyObject* spherical_harmonics(PyObject *self, PyObject *args) { int l; PyArrayObject* R_obj_c; PyArrayObject* Y_obj_m; if (!PyArg_ParseTuple(args, "iOO", &l, &R_obj_c, &Y_obj_m)) return NULL; double* R_c = DOUBLEP(R_obj_c); double* Y_m = DOUBLEP(Y_obj_m); if (l == 0) Y_m[0] = 0.28209479177387814; else { double x = R_c[0]; double y = R_c[1]; double z = R_c[2]; if (l == 1) { Y_m[0] = 0.48860251190291992 * y; Y_m[1] = 0.48860251190291992 * z; Y_m[2] = 0.48860251190291992 * x; } else { double r2 = x*x+y*y+z*z; if (l == 2) { Y_m[0] = 1.0925484305920792 * x*y; Y_m[1] = 1.0925484305920792 * y*z; Y_m[2] = 0.31539156525252005 * (3*z*z-r2); Y_m[3] = 1.0925484305920792 * x*z; Y_m[4] = 0.54627421529603959 * (x*x-y*y); } else if (l == 3) { Y_m[0] = 0.59004358992664352 * (-y*y*y+3*x*x*y); Y_m[1] = 2.8906114426405538 * x*y*z; Y_m[2] = 0.45704579946446577 * (-y*r2+5*y*z*z); Y_m[3] = 0.3731763325901154 * (5*z*z*z-3*z*r2); Y_m[4] = 0.45704579946446577 * (5*x*z*z-x*r2); Y_m[5] = 1.4453057213202769 * (x*x*z-y*y*z); Y_m[6] = 0.59004358992664352 * (x*x*x-3*x*y*y); } else if (l == 4) { Y_m[0] = 2.5033429417967046 * (x*x*x*y-x*y*y*y); Y_m[1] = 1.7701307697799307 * (-y*y*y*z+3*x*x*y*z); Y_m[2] = 0.94617469575756008 * (-x*y*r2+7*x*y*z*z); Y_m[3] = 0.66904654355728921 * (-3*y*z*r2+7*y*z*z*z); Y_m[4] = 0.10578554691520431 * (-30*z*z*r2+3*r2*r2+35*z*z*z*z); Y_m[5] = 0.66904654355728921 * (7*x*z*z*z-3*x*z*r2); Y_m[6] = 0.47308734787878004 * (-x*x*r2+7*x*x*z*z+y*y*r2-7*y*y*z*z); Y_m[7] = 1.7701307697799307 * (x*x*x*z-3*x*y*y*z); Y_m[8] = 0.62583573544917614 * (-6*x*x*y*y+x*x*x*x+y*y*y*y); } else if (l == 5) { Y_m[0] = 0.65638205684017015 * (y*y*y*y*y+5*x*x*x*x*y-10*x*x*y*y*y); Y_m[1] = 8.3026492595241645 * (x*x*x*y*z-x*y*y*y*z); Y_m[2] = 0.48923829943525038 * (y*y*y*r2-9*y*y*y*z*z-3*x*x*y*r2+27*x*x*y*z*z); Y_m[3] = 4.7935367849733241 * (3*x*y*z*z*z-x*y*z*r2); Y_m[4] = 0.45294665119569694 * (-14*y*z*z*r2+y*r2*r2+21*y*z*z*z*z); Y_m[5] = 0.1169503224534236 * (63*z*z*z*z*z+15*z*r2*r2-70*z*z*z*r2); Y_m[6] = 0.45294665119569694 * (x*r2*r2-14*x*z*z*r2+21*x*z*z*z*z); Y_m[7] = 2.3967683924866621 * (-3*y*y*z*z*z+y*y*z*r2+3*x*x*z*z*z-x*x*z*r2); Y_m[8] = 0.48923829943525038 * (9*x*x*x*z*z-27*x*y*y*z*z-x*x*x*r2+3*x*y*y*r2); Y_m[9] = 2.0756623148810411 * (y*y*y*y*z-6*x*x*y*y*z+x*x*x*x*z); Y_m[10] = 0.65638205684017015 * (-10*x*x*x*y*y+5*x*y*y*y*y+x*x*x*x*x); } else if (l == 6) { Y_m[0] = 1.3663682103838286 * (-10*x*x*x*y*y*y+3*x*x*x*x*x*y+3*x*y*y*y*y*y); Y_m[1] = 2.3666191622317521 * (y*y*y*y*y*z-10*x*x*y*y*y*z+5*x*x*x*x*y*z); Y_m[2] = 2.0182596029148967 * (-x*x*x*y*r2+x*y*y*y*r2-11*x*y*y*y*z*z+11*x*x*x*y*z*z); Y_m[3] = 0.92120525951492349 * (-11*y*y*y*z*z*z-9*x*x*y*z*r2+33*x*x*y*z*z*z+3*y*y*y*z*r2); Y_m[4] =0.92120525951492349 * (x*y*r2*r2+33*x*y*z*z*z*z-18*x*y*z*z*r2); Y_m[5] = 0.58262136251873142 * (5*y*z*r2*r2+33*y*z*z*z*z*z-30*y*z*z*z*r2); Y_m[6] = 0.063569202267628425 * (231*z*z*z*z*z*z-5*r2*r2*r2+105*z*z*r2*r2-315*z*z*z*z*r2); Y_m[7] = 0.58262136251873142 * (-30*x*z*z*z*r2+33*x*z*z*z*z*z+5*x*z*r2*r2); Y_m[8] = 0.46060262975746175 * (33*x*x*z*z*z*z+x*x*r2*r2-y*y*r2*r2-18*x*x*z*z*r2+18*y*y*z*z*r2-33*y*y*z*z*z*z); Y_m[9] = 0.92120525951492349 * (-3*x*x*x*z*r2-33*x*y*y*z*z*z+9*x*y*y*z*r2+11*x*x*x*z*z*z); Y_m[10] = 0.50456490072872417 * (11*y*y*y*y*z*z-66*x*x*y*y*z*z-x*x*x*x*r2+6*x*x*y*y*r2+11*x*x*x*x*z*z-y*y*y*y*r2); Y_m[11] = 2.3666191622317521 * (5*x*y*y*y*y*z+x*x*x*x*x*z-10*x*x*x*y*y*z); Y_m[12] = 0.6831841051919143 * (x*x*x*x*x*x+15*x*x*y*y*y*y-15*x*x*x*x*y*y-y*y*y*y*y*y); } } } Py_RETURN_NONE; } gpaw-0.11.0.13004/c/blas.c0000664000175000017500000003221612553643466014774 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2009 CAMd * Copyright (C) 2007 CSC - IT Center for Science Ltd. * Please see the accompanying LICENSE file for further information. */ #include #define PY_ARRAY_UNIQUE_SYMBOL GPAW_ARRAY_API #define NO_IMPORT_ARRAY #include #include "extensions.h" #ifdef GPAW_NO_UNDERSCORE_BLAS # define dscal_ dscal # define zscal_ zscal # define daxpy_ daxpy # define zaxpy_ zaxpy # define dsyrk_ dsyrk # define zher_ zher # define zherk_ zherk # define dsyr2k_ dsyr2k # define zher2k_ zher2k # define dgemm_ dgemm # define zgemm_ zgemm # define dgemv_ dgemv # define zgemv_ zgemv # define ddot_ ddot #endif void dscal_(int*n, double* alpha, double* x, int* incx); void zscal_(int*n, void* alpha, void* x, int* incx); void daxpy_(int* n, double* alpha, double* x, int *incx, double* y, int *incy); void zaxpy_(int* n, void* alpha, void* x, int *incx, void* y, int *incy); void dsyrk_(char *uplo, char *trans, int *n, int *k, double *alpha, double *a, int *lda, double *beta, double *c, int *ldc); void zher_(char *uplo, int *n, double *alpha, void *x, int *incx, void *a, int *lda); void zherk_(char *uplo, char *trans, int *n, int *k, double *alpha, void *a, int *lda, double *beta, void *c, int *ldc); void dsyr2k_(char *uplo, char *trans, int *n, int *k, double *alpha, double *a, int *lda, double *b, int *ldb, double *beta, double *c, int *ldc); void zher2k_(char *uplo, char *trans, int *n, int *k, void *alpha, void *a, int *lda, void *b, int *ldb, double *beta, void *c, int *ldc); void dgemm_(char *transa, char *transb, int *m, int * n, int *k, double *alpha, double *a, int *lda, double *b, int *ldb, double *beta, double *c, int *ldc); void zgemm_(char *transa, char *transb, int *m, int * n, int *k, void *alpha, void *a, int *lda, void *b, int *ldb, void *beta, void *c, int *ldc); void dgemv_(char *trans, int *m, int * n, double *alpha, double *a, int *lda, double *x, int *incx, double *beta, double *y, int *incy); void zgemv_(char *trans, int *m, int * n, void *alpha, void *a, int *lda, void *x, int *incx, void *beta, void *y, int *incy); double ddot_(int *n, void *dx, int *incx, void *dy, int *incy); PyObject* scal(PyObject *self, PyObject *args) { Py_complex alpha; PyArrayObject* x; if (!PyArg_ParseTuple(args, "DO", &alpha, &x)) return NULL; int n = PyArray_DIMS(x)[0]; for (int d = 1; d < PyArray_NDIM(x); d++) n *= PyArray_DIMS(x)[d]; int incx = 1; if (PyArray_DESCR(x)->type_num == NPY_DOUBLE) dscal_(&n, &(alpha.real), DOUBLEP(x), &incx); else zscal_(&n, &alpha, (void*)COMPLEXP(x), &incx); Py_RETURN_NONE; } PyObject* gemm(PyObject *self, PyObject *args) { Py_complex alpha; PyArrayObject* a; PyArrayObject* b; Py_complex beta; PyArrayObject* c; char t = 'n'; char* transa = &t; if (!PyArg_ParseTuple(args, "DOODO|s", &alpha, &a, &b, &beta, &c, &transa)) return NULL; int m, k, lda, ldb, ldc; if (*transa == 'n') { m = PyArray_DIMS(a)[1]; for (int i = 2; i < PyArray_NDIM(a); i++) m *= PyArray_DIMS(a)[i]; k = PyArray_DIMS(a)[0]; lda = MAX(1, PyArray_STRIDES(a)[0] / PyArray_STRIDES(a)[PyArray_NDIM(a) - 1]); ldb = MAX(1, PyArray_STRIDES(b)[0] / PyArray_STRIDES(b)[1]); ldc = MAX(1, PyArray_STRIDES(c)[0] / PyArray_STRIDES(c)[PyArray_NDIM(c) - 1]); } else { k = PyArray_DIMS(a)[1]; for (int i = 2; i < PyArray_NDIM(a); i++) k *= PyArray_DIMS(a)[i]; m = PyArray_DIMS(a)[0]; lda = MAX(1, k); ldb = MAX(1, PyArray_STRIDES(b)[0] / PyArray_STRIDES(b)[PyArray_NDIM(b) - 1]); ldc = MAX(1, PyArray_STRIDES(c)[0] / PyArray_STRIDES(c)[1]); } int n = PyArray_DIMS(b)[0]; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) dgemm_(transa, "n", &m, &n, &k, &(alpha.real), DOUBLEP(a), &lda, DOUBLEP(b), &ldb, &(beta.real), DOUBLEP(c), &ldc); else zgemm_(transa, "n", &m, &n, &k, &alpha, (void*)COMPLEXP(a), &lda, (void*)COMPLEXP(b), &ldb, &beta, (void*)COMPLEXP(c), &ldc); Py_RETURN_NONE; } PyObject* mmm(PyObject *self, PyObject *args) { Py_complex alpha; PyArrayObject* M1; char* trans1; PyArrayObject* M2; char* trans2; Py_complex beta; PyArrayObject* M3; if (!PyArg_ParseTuple(args, "DOsOsDO", &alpha, &M1, &trans1, &M2, &trans2, &beta, &M3)) return NULL; int m = PyArray_DIM(M3, 1); int n = PyArray_DIM(M3, 0); int k; int bytes = PyArray_ITEMSIZE(M3); int lda = MAX(1, PyArray_STRIDE(M2, 0) / bytes); int ldb = MAX(1, PyArray_STRIDE(M1, 0) / bytes); int ldc = MAX(1, PyArray_STRIDE(M3, 0) / bytes); void* a = PyArray_DATA(M2); void* b = PyArray_DATA(M1); void* c = PyArray_DATA(M3); if (*trans2 == 'n') k = PyArray_DIM(M2, 0); else k = PyArray_DIM(M2, 1); if (bytes == 8) dgemm_(trans2, trans1, &m, &n, &k, &(alpha.real), a, &lda, b, &ldb, &(beta.real), c, &ldc); else zgemm_(trans2, trans1, &m, &n, &k, &alpha, a, &lda, b, &ldb, &beta, c, &ldc); Py_RETURN_NONE; } PyObject* gemv(PyObject *self, PyObject *args) { Py_complex alpha; PyArrayObject* a; PyArrayObject* x; Py_complex beta; PyArrayObject* y; char t = 't'; char* trans = &t; if (!PyArg_ParseTuple(args, "DOODO|s", &alpha, &a, &x, &beta, &y, &trans)) return NULL; int m, n, lda, itemsize, incx, incy; if (*trans == 'n') { m = PyArray_DIMS(a)[1]; for (int i = 2; i < PyArray_NDIM(a); i++) m *= PyArray_DIMS(a)[i]; n = PyArray_DIMS(a)[0]; lda = MAX(1, m); } else { n = PyArray_DIMS(a)[0]; for (int i = 1; i < PyArray_NDIM(a)-1; i++) n *= PyArray_DIMS(a)[i]; m = PyArray_DIMS(a)[PyArray_NDIM(a)-1]; lda = MAX(1, m); } if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) itemsize = sizeof(double); else itemsize = sizeof(double_complex); incx = PyArray_STRIDES(x)[0]/itemsize; incy = 1; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) dgemv_(trans, &m, &n, &(alpha.real), DOUBLEP(a), &lda, DOUBLEP(x), &incx, &(beta.real), DOUBLEP(y), &incy); else zgemv_(trans, &m, &n, &alpha, (void*)COMPLEXP(a), &lda, (void*)COMPLEXP(x), &incx, &beta, (void*)COMPLEXP(y), &incy); Py_RETURN_NONE; } PyObject* axpy(PyObject *self, PyObject *args) { Py_complex alpha; PyArrayObject* x; PyArrayObject* y; if (!PyArg_ParseTuple(args, "DOO", &alpha, &x, &y)) return NULL; int n = PyArray_DIMS(x)[0]; for (int d = 1; d < PyArray_NDIM(x); d++) n *= PyArray_DIMS(x)[d]; int incx = 1; int incy = 1; if (PyArray_DESCR(x)->type_num == NPY_DOUBLE) daxpy_(&n, &(alpha.real), DOUBLEP(x), &incx, DOUBLEP(y), &incy); else zaxpy_(&n, &alpha, (void*)COMPLEXP(x), &incx, (void*)COMPLEXP(y), &incy); Py_RETURN_NONE; } PyObject* czher(PyObject *self, PyObject *args) { double alpha; PyArrayObject* x; PyArrayObject* a; if (!PyArg_ParseTuple(args, "dOO", &alpha, &x, &a)) return NULL; int n = PyArray_DIMS(x)[0]; for (int d = 1; d < PyArray_NDIM(x); d++) n *= PyArray_DIMS(x)[d]; int incx = 1; int lda = MAX(1, n); zher_("l", &n, &(alpha), (void*)COMPLEXP(x), &incx, (void*)COMPLEXP(a), &lda); Py_RETURN_NONE; } PyObject* rk(PyObject *self, PyObject *args) { double alpha; PyArrayObject* a; double beta; PyArrayObject* c; char t = 'c'; char* trans = &t; if (!PyArg_ParseTuple(args, "dOdO|s", &alpha, &a, &beta, &c, &trans)) return NULL; int n = PyArray_DIMS(c)[0]; int k, lda; if (*trans == 'c') { k = PyArray_DIMS(a)[1]; for (int d = 2; d < PyArray_NDIM(a); d++) k *= PyArray_DIMS(a)[d]; lda = k; } else { k = PyArray_DIMS(a)[0]; lda = n; } int ldc = PyArray_STRIDES(c)[0] / PyArray_STRIDES(c)[1]; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) dsyrk_("u", trans, &n, &k, &alpha, DOUBLEP(a), &lda, &beta, DOUBLEP(c), &ldc); else zherk_("u", trans, &n, &k, &alpha, (void*)COMPLEXP(a), &lda, &beta, (void*)COMPLEXP(c), &ldc); Py_RETURN_NONE; } PyObject* r2k(PyObject *self, PyObject *args) { Py_complex alpha; PyArrayObject* a; PyArrayObject* b; double beta; PyArrayObject* c; if (!PyArg_ParseTuple(args, "DOOdO", &alpha, &a, &b, &beta, &c)) return NULL; int n = PyArray_DIMS(a)[0]; int k = PyArray_DIMS(a)[1]; for (int d = 2; d < PyArray_NDIM(a); d++) k *= PyArray_DIMS(a)[d]; int ldc = PyArray_STRIDES(c)[0] / PyArray_STRIDES(c)[1]; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) dsyr2k_("u", "t", &n, &k, (double*)(&alpha), DOUBLEP(a), &k, DOUBLEP(b), &k, &beta, DOUBLEP(c), &ldc); else zher2k_("u", "c", &n, &k, (void*)(&alpha), (void*)COMPLEXP(a), &k, (void*)COMPLEXP(b), &k, &beta, (void*)COMPLEXP(c), &ldc); Py_RETURN_NONE; } PyObject* dotc(PyObject *self, PyObject *args) { PyArrayObject* a; PyArrayObject* b; if (!PyArg_ParseTuple(args, "OO", &a, &b)) return NULL; int n = PyArray_DIMS(a)[0]; for (int i = 1; i < PyArray_NDIM(a); i++) n *= PyArray_DIMS(a)[i]; int incx = 1; int incy = 1; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { double result; result = ddot_(&n, (void*)DOUBLEP(a), &incx, (void*)DOUBLEP(b), &incy); return PyFloat_FromDouble(result); } else { double_complex* ap = COMPLEXP(a); double_complex* bp = COMPLEXP(b); double_complex z = 0.0; for (int i = 0; i < n; i++) z += conj(ap[i]) * bp[i]; return PyComplex_FromDoubles(creal(z), cimag(z)); } } PyObject* dotu(PyObject *self, PyObject *args) { PyArrayObject* a; PyArrayObject* b; if (!PyArg_ParseTuple(args, "OO", &a, &b)) return NULL; int n = PyArray_DIMS(a)[0]; for (int i = 1; i < PyArray_NDIM(a); i++) n *= PyArray_DIMS(a)[i]; int incx = 1; int incy = 1; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { double result; result = ddot_(&n, (void*)DOUBLEP(a), &incx, (void*)DOUBLEP(b), &incy); return PyFloat_FromDouble(result); } else { double_complex* ap = COMPLEXP(a); double_complex* bp = COMPLEXP(b); double_complex z = 0.0; for (int i = 0; i < n; i++) z += ap[i] * bp[i]; return PyComplex_FromDoubles(creal(z), cimag(z)); } } PyObject* multi_dotu(PyObject *self, PyObject *args) { PyArrayObject* a; PyArrayObject* b; PyArrayObject* c; if (!PyArg_ParseTuple(args, "OOO", &a, &b, &c)) return NULL; int n0 = PyArray_DIMS(a)[0]; int n = PyArray_DIMS(a)[1]; for (int i = 2; i < PyArray_NDIM(a); i++) n *= PyArray_DIMS(a)[i]; int incx = 1; int incy = 1; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { double *ap = DOUBLEP(a); double *bp = DOUBLEP(b); double *cp = DOUBLEP(c); for (int i = 0; i < n0; i++) { cp[i] = ddot_(&n, (void*)ap, &incx, (void*)bp, &incy); ap += n; bp += n; } } else { double_complex* ap = COMPLEXP(a); double_complex* bp = COMPLEXP(b); double_complex* cp = COMPLEXP(c); for (int i = 0; i < n0; i++) { cp[i] = 0.0; for (int j = 0; j < n; j++) cp[i] += ap[j] * bp[j]; ap += n; bp += n; } } Py_RETURN_NONE; } PyObject* multi_axpy(PyObject *self, PyObject *args) { PyArrayObject* alpha; PyArrayObject* x; PyArrayObject* y; if (!PyArg_ParseTuple(args, "OOO", &alpha, &x, &y)) return NULL; int n0 = PyArray_DIMS(x)[0]; int n = PyArray_DIMS(x)[1]; for (int d = 2; d < PyArray_NDIM(x); d++) n *= PyArray_DIMS(x)[d]; int incx = 1; int incy = 1; if (PyArray_DESCR(alpha)->type_num == NPY_DOUBLE) { if (PyArray_DESCR(x)->type_num == NPY_CDOUBLE) n *= 2; double *ap = DOUBLEP(alpha); double *xp = DOUBLEP(x); double *yp = DOUBLEP(y); for (int i = 0; i < n0; i++) { daxpy_(&n, &ap[i], (void*)xp, &incx, (void*)yp, &incy); xp += n; yp += n; } } else { double_complex *ap = COMPLEXP(alpha); double_complex *xp = COMPLEXP(x); double_complex *yp = COMPLEXP(y); for (int i = 0; i < n0; i++) { zaxpy_(&n, (void*)(&ap[i]), (void*)xp, &incx, (void*)yp, &incy); xp += n; yp += n; } } Py_RETURN_NONE; } gpaw-0.11.0.13004/c/plane_wave.c0000664000175000017500000000203712553643466016172 0ustar jensjjensj00000000000000#include "extensions.h" #include PyObject *plane_wave_grid(PyObject *self, PyObject *args) { PyArrayObject* beg_c; PyArrayObject* end_c; PyArrayObject* h_c; PyArrayObject* k_c; PyArrayObject* r0_c; PyArrayObject* pw_g; if (!PyArg_ParseTuple(args, "OOOOOO", &beg_c, &end_c, &h_c, &k_c, &r0_c, &pw_g)) return NULL; long *beg = LONGP(beg_c); long *end = LONGP(end_c); double *h = DOUBLEP(h_c); double *vk = DOUBLEP(k_c); double *vr0 = DOUBLEP(r0_c); double_complex *pw = COMPLEXP(pw_g); double kr[3], kr0[3]; int n[3], ij; for (int c = 0; c < 3; c++) { n[c] = end[c] - beg[c]; kr0[c] = vk[c] * vr0[c]; } for (int i = 0; i < n[0]; i++) { kr[0] = vk[0] * h[0] * (beg[0] + i) - kr0[0]; for (int j = 0; j < n[1]; j++) { kr[1] = kr[0] + vk[1] * h[1] * (beg[1] + j) - kr0[1]; ij = (i*n[1] + j)*n[2]; for (int k = 0; k < n[2]; k++) { kr[2] = kr[1] + vk[2] * h[2] * (beg[2] + k) - kr0[2]; pw[ij + k] = cos(kr[2]) + I * sin(kr[2]); } } } Py_RETURN_NONE; } gpaw-0.11.0.13004/c/blacs.c0000664000175000017500000015153612553643466015146 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2009 CAMd * Copyright (C) 2010 Argonne National Laboratory * Please see the accompanying LICENSE file for further information. */ #ifdef PARALLEL #include #ifdef GPAW_WITH_SL #define PY_ARRAY_UNIQUE_SYMBOL GPAW_ARRAY_API #define NO_IMPORT_ARRAY #include #include #include #include #include "extensions.h" #include "mympi.h" // BLACS #define BLOCK_CYCLIC_2D 1 #ifdef GPAW_NO_UNDERSCORE_CBLACS #define Cblacs_barrier_ Cblacs_barrier #define Cblacs_gridexit_ Cblacs_gridexit #define Cblacs_gridinfo_ Cblacs_gridinfo #define Cblacs_gridinit_ Cblacs_gridinit #define Cblacs_pinfo_ Cblacs_pinfo #define Csys2blacs_handle_ Csys2blacs_handle #endif void Cblacs_barrier_(int ConTxt, char *scope); void Cblacs_gridexit_(int ConTxt); void Cblacs_gridinfo_(int ConTxt, int* nprow, int* npcol, int* myrow, int* mycol); void Cblacs_gridinit_(int* ConTxt, char* order, int nprow, int npcol); void Cblacs_pinfo_(int* mypnum, int* nprocs); int Csys2blacs_handle_(MPI_Comm SysCtxt); // End of BLACS // ScaLAPACK #ifdef GPAW_NO_UNDERSCORE_SCALAPACK #define numroc_ numroc #define pdlamch_ pdlamch #define pdlaset_ pdlaset #define pzlaset_ pzlaset #define pdpotrf_ pdpotrf #define pzpotrf_ pzpotrf #define pzpotri_ pzpotri #define pdtrtri_ pdtrtri #define pztrtri_ pztrtri #define pzgesv_ pzgesv #define pdgesv_ pdgesv #define pdsyevd_ pdsyevd #define pzheevd_ pzheevd #define pdsyevx_ pdsyevx #define pzheevx_ pzheevx #define pdsygvx_ pdsygvx #define pzhegvx_ pzhegvx #define pdsyngst_ pdsyngst #define pzhengst_ pzhengst #ifdef GPAW_MR3 #define pdsyevr_ pdsyevr #define pzheevr_ pzheevr #endif // GPAW_MR3 #define pdtran_ pdtran #define pztranc_ pztranc #define pdgemm_ pdgemm #define pzgemm_ pzgemm #define pdgemv_ pdgemv #define pzgemv_ pzgemv #define pdsyr2k_ pdsyr2k #define pzher2k_ pzher2k #define pdsyrk_ pdsyrk #define pzherk_ pzherk #define pdtrsm_ pdtrsm #define pztrsm_ pztrsm #define pzhemm_ pzhemm #define pdsymm_ pdsymm #endif #ifdef GPAW_NO_UNDERSCORE_CSCALAPACK #define Cpdgemr2d_ Cpdgemr2d #define Cpzgemr2d_ Cpzgemr2d #define Cpdtrmr2d_ Cpdtrmr2d #define Cpztrmr2d_ Cpztrmr2d #endif // tools int numroc_(int* n, int* nb, int* iproc, int* isrcproc, int* nprocs); void Cpdgemr2d_(int m, int n, double* a, int ia, int ja, int* desca, double* b, int ib, int jb, int* descb, int gcontext); void Cpzgemr2d_(int m, int n, void* a, int ia, int ja, int* desca, void* b, int ib, int jb, int* descb, int gcontext); void Cpdtrmr2d_(char* uplo, char* diag, int m, int n, double* a, int ia, int ja, int* desca, double* b, int ib, int jb, int* descb, int gcontext); void Cpztrmr2d_(char* uplo, char* diag, int m, int n, void* a, int ia, int ja, int* desca, void* b, int ib, int jb, int* descb, int gcontext); double pdlamch_(int* ictxt, char* cmach); void pzpotri_(char* uplo, int* n, void* a, int *ia, int* ja, int* desca, int* info); void pzgetri_(int* n, void* a, int *ia, int* ja, int* desca, int* info); void pdlaset_(char* uplo, int* m, int* n, double* alpha, double* beta, double* a, int* ia, int* ja, int* desca); void pzlaset_(char* uplo, int* m, int* n, void* alpha, void* beta, void* a, int* ia, int* ja, int* desca); // cholesky void pdpotrf_(char* uplo, int* n, double* a, int* ia, int* ja, int* desca, int* info); void pzpotrf_(char* uplo, int* n, void* a, int* ia, int* ja, int* desca, int* info); void pzgesv_(int* n, int* nrhs, void* a, int* ia, int* ja, int* desca, int* ipiv, void* b, int* ib, int* jb, int* descb, int* info); void pdgesv_(int *n, int *nrhs, void *a, int *ia, int *ja, int* desca, int *ipiv, void* b, int* ib, int* jb, int* descb, int* info); void pdtrtri_(char* uplo, char* diag, int* n, double* a, int *ia, int* ja, int* desca, int* info); void pztrtri_(char* uplo, char* diag, int* n, void* a, int *ia, int* ja, int* desca, int* info); // diagonalization void pdsyevd_(char* jobz, char* uplo, int* n, double* a, int* ia, int* ja, int* desca, double* w, double* z, int* iz, int* jz, int* descz, double* work, int* lwork, int* iwork, int* liwork, int* info); void pzheevd_(char* jobz, char* uplo, int* n, void* a, int* ia, int* ja, int* desca, double* w, void* z, int* iz, int* jz, int* descz, void* work, int* lwork, double* rwork, int* lrwork, int* iwork, int* liwork, int* info); void pdsyevx_(char* jobz, char* range, char* uplo, int* n, double* a, int* ia, int* ja, int* desca, double* vl, double* vu, int* il, int* iu, double* abstol, int* m, int* nz, double* w, double* orfac, double* z, int* iz, int* jz, int* descz, double* work, int* lwork, int* iwork, int* liwork, int* ifail, int* iclustr, double* gap, int* info); void pzheevx_(char* jobz, char* range, char* uplo, int* n, void* a, int* ia, int* ja, int* desca, double* vl, double* vu, int* il, int* iu, double* abstol, int* m, int* nz, double* w, double* orfac, void* z, int* iz, int* jz, int* descz, void* work, int* lwork, double* rwork, int* lrwork, int* iwork, int* liwork, int* ifail, int* iclustr, double* gap, int* info); void pdsygvx_(int* ibtype, char* jobz, char* range, char* uplo, int* n, double* a, int* ia, int* ja, int* desca, double* b, int *ib, int* jb, int* descb, double* vl, double* vu, int* il, int* iu, double* abstol, int* m, int* nz, double* w, double* orfac, double* z, int* iz, int* jz, int* descz, double* work, int* lwork, int* iwork, int* liwork, int* ifail, int* iclustr, double* gap, int* info); void pzhegvx_(int* ibtype, char* jobz, char* range, char* uplo, int* n, void* a, int* ia, int* ja, int* desca, void* b, int *ib, int* jb, int* descb, double* vl, double* vu, int* il, int* iu, double* abstol, int* m, int* nz, double* w, double* orfac, void* z, int* iz, int* jz, int* descz, void* work, int* lwork, double* rwork, int* lrwork, int* iwork, int* liwork, int* ifail, int* iclustr, double* gap, int* info); void pdsyngst_(int* ibtype, char* uplo, int* n, double* a, int* ia, int* ja, int* desca, double* b, int* ib, int* jb, int* descb, double* scale, double* work, int* lwork, int* info); void pzhengst_(int* ibtype, char* uplo, int* n, void* a, int* ia, int* ja, int* desca, void* b, int* ib, int* jb, int* descb, double* scale, void* work, int* lwork, int* info); #ifdef GPAW_MR3 void pdsyevr_(char* jobz, char* range, char* uplo, int* n, double* a, int* ia, int* ja, int* desca, double* vl, double* vu, int* il, int* iu, int* m, int* nz, double* w, double* z, int* iz, int* jz, int* descz, double* work, int* lwork, int* iwork, int* liwork, int* info); void pzheevr_(char* jobz, char* range, char* uplo, int* n, void* a, int* ia, int* ja, int* desca, double* vl, double* vu, int* il, int* iu, int* m, int* nz, double* w, void* z, int* iz, int* jz, int* descz, void* work, int* lwork, double* rwork, int* lrwork, int* iwork, int* liwork, int* info); #endif // GPAW_MR3 // pblas void pdtran_(int* m, int* n, double* alpha, double* a, int* ia, int* ja, int* desca, double* beta, double* c, int* ic, int* jc, int* descc); void pztranc_(int* m, int* n, void* alpha, void* a, int* ia, int* ja, int* desca, void* beta, void* c, int* ic, int* jc, int* descc); void pdgemm_(char* transa, char* transb, int* m, int* n, int* k, double* alpha, double* a, int* ia, int* ja, int* desca, double* b, int* ib, int* jb, int* descb, double* beta, double* c, int* ic, int* jc, int* descc); void pzgemm_(char* transa, char* transb, int* m, int* n, int* k, void* alpha, void* a, int* ia, int* ja, int* desca, void* b, int* ib, int* jb, int* descb, void* beta, void* c, int* ic, int* jc, int* descc); void pzhemm_(char* side, char* uplo, int* m, int* n, void* alpha, void* a, int* ia, int* ja, int* desca, void* b, int* ib, int* jb, int* descb, void* beta, void* c, int* ic, int* jc, int* descc); void pdsymm_(char* side, char* uplo, int* m, int* n, void* alpha, void* a, int* ia, int* ja, int* desca, void* b, int* ib, int* jb, int* descb, void* beta, void* c, int* ic, int* jc, int* descc); void pdgemv_(char* transa, int* m, int* n, double* alpha, double* a, int* ia, int* ja, int* desca, double* x, int* ix, int* jx, int* descx, int* incx, double* beta, double* y, int* iy, int* jy, int* descy, int* incy); void pzgemv_(char* transa, int* m, int* n, void* alpha, void* a, int* ia, int* ja, int* desca, void* x, int* ix, int* jx, int* descx, int* incx, void* beta, void* y, int* iy, int* jy, int* descy, int* incy); void pdsyr2k_(char* uplo, char* trans, int* n, int* k, double* alpha, double* a, int* ia, int* ja, int* desca, double* b, int* ib, int* jb, int* descb, double* beta, double* c, int* ic, int *jc, int* descc); void pzher2k_(char* uplo, char* trans, int* n, int* k, void* alpha, void* a, int* ia, int* ja, int* desca, void* b, int* ib, int* jb, int* descb, void* beta, void* c, int* ic, int* jc, int* descc); void pdsyrk_(char* uplo, char* trans, int* n, int* k, double* alpha, double* a, int* ia, int* ja, int* desca, double* beta, double* c, int* ic, int* jc, int* descc); void pzherk_(char* uplo, char* trans, int* n, int* k, void* alpha, void* a, int* ia, int* ja, int* desca, void* beta, void* c, int* ic, int* jc, int* descc); void pdtrsm_(char* side, char* uplo, char* trans, char* diag, int* m, int *n, double* alpha, double* a, int* ia, int* ja, int* desca, double* b, int* ib, int* jb, int* descb); void pztrsm_(char* side, char* uplo, char* trans, char* diag, int* m, int *n, void* alpha, void* a, int* ia, int* ja, int* desca, void* b, int* ib, int* jb, int* descb); PyObject* pblas_tran(PyObject *self, PyObject *args) { int m, n; Py_complex alpha; Py_complex beta; PyArrayObject *a, *c; PyArrayObject *desca, *descc; if (!PyArg_ParseTuple(args, "iiDODOOO", &m, &n, &alpha, &a, &beta, &c, &desca, &descc)) return NULL; int one = 1; if (PyArray_DESCR(c)->type_num == NPY_DOUBLE) pdtran_(&m, &n, &(alpha.real), DOUBLEP(a), &one, &one, INTP(desca), &(beta.real), DOUBLEP(c), &one, &one, INTP(descc)); else pztranc_(&m, &n, &alpha, (void*)PyArray_DATA(a), &one, &one, INTP(desca), &beta, (void*)PyArray_DATA(c), &one, &one, INTP(descc)); Py_RETURN_NONE; } PyObject* pblas_gemm(PyObject *self, PyObject *args) { char transa; char transb; int m, n, k; Py_complex alpha; Py_complex beta; PyArrayObject *a, *b, *c; PyArrayObject *desca, *descb, *descc; int one = 1; if (!PyArg_ParseTuple(args, "iiiDOODOOOOcc", &m, &n, &k, &alpha, &a, &b, &beta, &c, &desca, &descb, &descc, &transa, &transb)) { return NULL; } // cdesc // int c_ConTxt = INTP(descc)[1]; // If process not on BLACS grid, then return. // if (c_ConTxt == -1) Py_RETURN_NONE; if (PyArray_DESCR(c)->type_num == NPY_DOUBLE) pdgemm_(&transa, &transb, &m, &n, &k, &(alpha.real), DOUBLEP(a), &one, &one, INTP(desca), DOUBLEP(b), &one, &one, INTP(descb), &(beta.real), DOUBLEP(c), &one, &one, INTP(descc)); else pzgemm_(&transa, &transb, &m, &n, &k, &alpha, (void*)COMPLEXP(a), &one, &one, INTP(desca), (void*)COMPLEXP(b), &one, &one, INTP(descb), &beta, (void*)COMPLEXP(c), &one, &one, INTP(descc)); Py_RETURN_NONE; } PyObject* pblas_hemm(PyObject *self, PyObject *args) { char side; char uplo; int m, n; Py_complex alpha; Py_complex beta; PyArrayObject *a, *b, *c; PyArrayObject *desca, *descb, *descc; int one = 1; if (!PyArg_ParseTuple(args, "cciiDOOdOOOO", &side, &uplo, &n, &m, &alpha, &a, &b, &beta, &c, &desca, &descb, &descc)) { return NULL; } if (PyArray_DESCR(c)->type_num == NPY_DOUBLE) { pdsymm_(&side, &uplo, &n, &m, &alpha, (void*)DOUBLEP(a), &one, &one, INTP(desca), (void*)DOUBLEP(b), &one, &one, INTP(descb), &beta, (void*)DOUBLEP(c), &one, &one, INTP(descc)); } else { pzhemm_(&side, &uplo, &n, &m, &alpha, (void*)COMPLEXP(a), &one, &one, INTP(desca), (void*)COMPLEXP(b), &one, &one, INTP(descb), &beta, (void*)COMPLEXP(c), &one, &one, INTP(descc)); } Py_RETURN_NONE; } PyObject* pblas_gemv(PyObject *self, PyObject *args) { char transa; int m, n; Py_complex alpha; Py_complex beta; PyArrayObject *a, *x, *y; int incx = 1, incy = 1; // what should these be? PyArrayObject *desca, *descx, *descy; int one = 1; if (!PyArg_ParseTuple(args, "iiDOODOOOOc", &m, &n, &alpha, &a, &x, &beta, &y, &desca, &descx, &descy, &transa)) { return NULL; } // ydesc // int y_ConTxt = INTP(descy)[1]; // If process not on BLACS grid, then return. // if (y_ConTxt == -1) Py_RETURN_NONE; if (PyArray_DESCR(y)->type_num == NPY_DOUBLE) pdgemv_(&transa, &m, &n, &(alpha.real), DOUBLEP(a), &one, &one, INTP(desca), DOUBLEP(x), &one, &one, INTP(descx), &incx, &(beta.real), DOUBLEP(y), &one, &one, INTP(descy), &incy); else pzgemv_(&transa, &m, &n, &alpha, (void*)COMPLEXP(a), &one, &one, INTP(desca), (void*)COMPLEXP(x), &one, &one, INTP(descx), &incx, &beta, (void*)COMPLEXP(y), &one, &one, INTP(descy), &incy); Py_RETURN_NONE; } PyObject* pblas_r2k(PyObject *self, PyObject *args) { char uplo; int n, k; Py_complex alpha; Py_complex beta; PyArrayObject *a, *b, *c; PyArrayObject *desca, *descb, *descc; int one = 1; if (!PyArg_ParseTuple(args, "iiDOODOOOOc", &n, &k, &alpha, &a, &b, &beta, &c, &desca, &descb, &descc, &uplo)) { return NULL; } // cdesc // int c_ConTxt = INTP(descc)[1]; // If process not on BLACS grid, then return. // if (c_ConTxt == -1) Py_RETURN_NONE; if (PyArray_DESCR(c)->type_num == NPY_DOUBLE) pdsyr2k_(&uplo, "T", &n, &k, &(alpha.real), DOUBLEP(a), &one, &one, INTP(desca), DOUBLEP(b), &one, &one, INTP(descb), &(beta.real), DOUBLEP(c), &one, &one, INTP(descc)); else pzher2k_(&uplo, "C", &n, &k, &alpha, (void*)COMPLEXP(a), &one, &one, INTP(desca), (void*)COMPLEXP(b), &one, &one, INTP(descb), &beta, (void*)COMPLEXP(c), &one, &one, INTP(descc)); Py_RETURN_NONE; } PyObject* pblas_rk(PyObject *self, PyObject *args) { char uplo; int n, k; Py_complex alpha; Py_complex beta; PyArrayObject *a, *c; PyArrayObject *desca, *descc; int one = 1; if (!PyArg_ParseTuple(args, "iiDODOOOc", &n, &k, &alpha, &a, &beta, &c, &desca, &descc, &uplo)) { return NULL; } // cdesc // int c_ConTxt = INTP(descc)[1]; // If process not on BLACS grid, then return. // if (c_ConTxt == -1) Py_RETURN_NONE; if (PyArray_DESCR(c)->type_num == NPY_DOUBLE) pdsyrk_(&uplo, "T", &n, &k, &(alpha.real), DOUBLEP(a), &one, &one, INTP(desca), &(beta.real), DOUBLEP(c), &one, &one, INTP(descc)); else pzherk_(&uplo, "C", &n, &k, &alpha, (void*)COMPLEXP(a), &one, &one, INTP(desca), &beta, (void*)COMPLEXP(c), &one, &one, INTP(descc)); Py_RETURN_NONE; } PyObject* new_blacs_context(PyObject *self, PyObject *args) { PyObject* comm_obj; int nprow, npcol; int iam, nprocs; int ConTxt; char order; if (!PyArg_ParseTuple(args, "Oiic", &comm_obj, &nprow, &npcol, &order)){ return NULL; } // Create blacs grid on this communicator MPI_Comm comm = ((MPIObject*)comm_obj)->comm; // Get my id and nprocs. This is for debugging purposes only Cblacs_pinfo_(&iam, &nprocs); MPI_Comm_size(comm, &nprocs); // Create blacs grid on this communicator continued ConTxt = Csys2blacs_handle_(comm); Cblacs_gridinit_(&ConTxt, &order, nprow, npcol); PyObject* returnvalue = Py_BuildValue("i", ConTxt); return returnvalue; } PyObject* get_blacs_gridinfo(PyObject *self, PyObject *args) { int ConTxt, nprow, npcol; int myrow, mycol; if (!PyArg_ParseTuple(args, "iii", &ConTxt, &nprow, &npcol)) { return NULL; } Cblacs_gridinfo_(ConTxt, &nprow, &npcol, &myrow, &mycol); return Py_BuildValue("(ii)", myrow, mycol); } PyObject* get_blacs_local_shape(PyObject *self, PyObject *args) { int ConTxt; int m, n, mb, nb, rsrc, csrc; int nprow, npcol, myrow, mycol; int locM, locN; if (!PyArg_ParseTuple(args, "iiiiiii", &ConTxt, &m, &n, &mb, &nb, &rsrc, &csrc)){ return NULL; } Cblacs_gridinfo_(ConTxt, &nprow, &npcol, &myrow, &mycol); locM = numroc_(&m, &mb, &myrow, &rsrc, &nprow); locN = numroc_(&n, &nb, &mycol, &csrc, &npcol); return Py_BuildValue("(ii)", locM, locN); } PyObject* blacs_destroy(PyObject *self, PyObject *args) { int ConTxt; if (!PyArg_ParseTuple(args, "i", &ConTxt)) return NULL; Cblacs_gridexit_(ConTxt); Py_RETURN_NONE; } PyObject* scalapack_set(PyObject *self, PyObject *args) { PyArrayObject* a; // matrix; PyArrayObject* desca; // descriptor Py_complex alpha; Py_complex beta; int m, n; int ia, ja; char uplo; if (!PyArg_ParseTuple(args, "OODDciiii", &a, &desca, &alpha, &beta, &uplo, &m, &n, &ia, &ja)) return NULL; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) pdlaset_(&uplo, &m, &n, &(alpha.real), &(beta.real), DOUBLEP(a), &ia, &ja, INTP(desca)); else pzlaset_(&uplo, &m, &n, &alpha, &beta, (void*)COMPLEXP(a), &ia, &ja, INTP(desca)); Py_RETURN_NONE; } PyObject* scalapack_redist(PyObject *self, PyObject *args) { PyArrayObject* a; // source matrix PyArrayObject* b; // destination matrix PyArrayObject* desca; // source descriptor PyArrayObject* descb; // destination descriptor char uplo; char diag='N'; // copy the diagonal int c_ConTxt; int m; int n; int ia, ja, ib, jb; if (!PyArg_ParseTuple(args, "OOOOiiiiiiic", &desca, &descb, &a, &b, &m, &n, &ia, &ja, &ib, &jb, &c_ConTxt, &uplo)) return NULL; if (uplo == 'G') // General matrix { if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) Cpdgemr2d_(m, n, DOUBLEP(a), ia, ja, INTP(desca), DOUBLEP(b), ib, jb, INTP(descb), c_ConTxt); else Cpzgemr2d_(m, n, (void*)COMPLEXP(a), ia, ja, INTP(desca), (void*)COMPLEXP(b), ib, jb, INTP(descb), c_ConTxt); } else // Trapezoidal matrix { if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) Cpdtrmr2d_(&uplo, &diag, m, n, DOUBLEP(a), ia, ja, INTP(desca), DOUBLEP(b), ib, jb, INTP(descb), c_ConTxt); else Cpztrmr2d_(&uplo, &diag, m, n, (void*)COMPLEXP(a), ia, ja, INTP(desca), (void*)COMPLEXP(b), ib, jb, INTP(descb), c_ConTxt); } Py_RETURN_NONE; } PyObject* scalapack_diagonalize_dc(PyObject *self, PyObject *args) { // Standard driver for divide and conquer algorithm // Computes all eigenvalues and eigenvectors PyArrayObject* a; // symmetric matrix PyArrayObject* desca; // symmetric matrix description vector PyArrayObject* z; // eigenvector matrix PyArrayObject* w; // eigenvalue array int one = 1; char jobz = 'V'; // eigenvectors also char uplo; if (!PyArg_ParseTuple(args, "OOcOO", &a, &desca, &uplo, &z, &w)) return NULL; // adesc // int a_ConTxt = INTP(desca)[1]; int a_m = INTP(desca)[2]; int a_n = INTP(desca)[3]; // zdesc = adesc; this can be relaxed a bit according to pdsyevd.f // Only square matrices assert (a_m == a_n); int n = a_n; // If process not on BLACS grid, then return. // if (a_ConTxt == -1) Py_RETURN_NONE; // Query part, need to find the optimal size of a number of work arrays int info; int querywork = -1; int* iwork; int liwork; int lwork; int lrwork; int i_work; double d_work; double_complex c_work; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { pdsyevd_(&jobz, &uplo, &n, DOUBLEP(a), &one, &one, INTP(desca), DOUBLEP(w), DOUBLEP(z), &one, &one, INTP(desca), &d_work, &querywork, &i_work, &querywork, &info); lwork = (int)(d_work); } else { pzheevd_(&jobz, &uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), DOUBLEP(w), (void*)COMPLEXP(z), &one, &one, INTP(desca), (void*)&c_work, &querywork, &d_work, &querywork, &i_work, &querywork, &info); lwork = (int)(c_work); lrwork = (int)(d_work); } if (info != 0) { PyErr_SetString(PyExc_RuntimeError, "scalapack_diagonalize_dc error in query."); return NULL; } // Computation part liwork = i_work; iwork = GPAW_MALLOC(int, liwork); if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { double* work = GPAW_MALLOC(double, lwork); pdsyevd_(&jobz, &uplo, &n, DOUBLEP(a), &one, &one, INTP(desca), DOUBLEP(w), DOUBLEP(z), &one, &one, INTP(desca), work, &lwork, iwork, &liwork, &info); free(work); } else { double_complex *work = GPAW_MALLOC(double_complex, lwork); double* rwork = GPAW_MALLOC(double, lrwork); pzheevd_(&jobz, &uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), DOUBLEP(w), (void*)COMPLEXP(z), &one, &one, INTP(desca), (void*)work, &lwork, rwork, &lrwork, iwork, &liwork, &info); free(rwork); free(work); } free(iwork); PyObject* returnvalue = Py_BuildValue("i", info); return returnvalue; } PyObject* scalapack_diagonalize_ex(PyObject *self, PyObject *args) { // Standard driver for bisection and inverse iteration algorithm // Computes 'iu' eigenvalues and eigenvectors PyArrayObject* a; // Hamiltonian matrix PyArrayObject* desca; // Hamintonian matrix descriptor PyArrayObject* z; // eigenvector matrix PyArrayObject* w; // eigenvalue array int a_mycol = -1; int a_myrow = -1; int a_nprow, a_npcol; int il = 1; // not used when range = 'A' or 'V' int iu; int eigvalm, nz; int one = 1; double vl, vu; // not used when range = 'A' or 'I' char jobz = 'V'; // eigenvectors also char range = 'I'; // eigenvalues il-th thru iu-th char uplo; if (!PyArg_ParseTuple(args, "OOciOO", &a, &desca, &uplo, &iu, &z, &w)) return NULL; // a desc int a_ConTxt = INTP(desca)[1]; int a_m = INTP(desca)[2]; int a_n = INTP(desca)[3]; // Only square matrices assert (a_m == a_n); int n = a_n; // zdesc = adesc = bdesc; required by pdsyevx.f // If process not on BLACS grid, then return. // if (a_ConTxt == -1) Py_RETURN_NONE; Cblacs_gridinfo_(a_ConTxt, &a_nprow, &a_npcol, &a_myrow, &a_mycol); // Convergence tolerance double abstol = 1.0e-8; // char cmach = 'U'; // most orthogonal eigenvectors // char cmach = 'S'; // most acccurate eigenvalues // double abstol = pdlamch_(&a_ConTxt, &cmach); // most orthogonal eigenvectors // double abstol = 2.0*pdlamch_(&a_ConTxt, &cmach); // most accurate eigenvalues double orfac = -1.0; // Query part, need to find the optimal size of a number of work arrays int info; int *ifail; ifail = GPAW_MALLOC(int, n); int *iclustr; iclustr = GPAW_MALLOC(int, 2*a_nprow*a_npcol); double *gap; gap = GPAW_MALLOC(double, a_nprow*a_npcol); int querywork = -1; int* iwork; int liwork; int lwork; // workspace size must be at least 3 int lrwork; // workspace size must be at least 3 int i_work; double d_work[3]; double_complex c_work; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { pdsyevx_(&jobz, &range, &uplo, &n, DOUBLEP(a), &one, &one, INTP(desca), &vl, &vu, &il, &iu, &abstol, &eigvalm, &nz, DOUBLEP(w), &orfac, DOUBLEP(z), &one, &one, INTP(desca), d_work, &querywork, &i_work, &querywork, ifail, iclustr, gap, &info); lwork = MAX(3, (int)(d_work[0])); } else { pzheevx_(&jobz, &range, &uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), &vl, &vu, &il, &iu, &abstol, &eigvalm, &nz, DOUBLEP(w), &orfac, (void*)COMPLEXP(z), &one, &one, INTP(desca), (void*)&c_work, &querywork, d_work, &querywork, &i_work, &querywork, ifail, iclustr, gap, &info); lwork = MAX(3, (int)(c_work)); lrwork = MAX(3, (int)(d_work[0])); } if (info != 0) { printf ("info = %d", info); PyErr_SetString(PyExc_RuntimeError, "scalapack_diagonalize_ex error in query."); return NULL; } // Computation part // lwork = lwork + (n-1)*n; // this is a ridiculous amount of workspace liwork = i_work; iwork = GPAW_MALLOC(int, liwork); if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { double* work = GPAW_MALLOC(double, lwork); pdsyevx_(&jobz, &range, &uplo, &n, DOUBLEP(a), &one, &one, INTP(desca), &vl, &vu, &il, &iu, &abstol, &eigvalm, &nz, DOUBLEP(w), &orfac, DOUBLEP(z), &one, &one, INTP(desca), work, &lwork, iwork, &liwork, ifail, iclustr, gap, &info); free(work); } else { double_complex* work = GPAW_MALLOC(double_complex, lwork); double* rwork = GPAW_MALLOC(double, lrwork); pzheevx_(&jobz, &range, &uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), &vl, &vu, &il, &iu, &abstol, &eigvalm, &nz, DOUBLEP(w), &orfac, (void*)COMPLEXP(z), &one, &one, INTP(desca), (void*)work, &lwork, rwork, &lrwork, iwork, &liwork, ifail, iclustr, gap, &info); free(rwork); free(work); } free(iwork); free(gap); free(iclustr); free(ifail); // If this fails, fewer eigenvalues than requested were computed. assert (eigvalm == iu); PyObject* returnvalue = Py_BuildValue("i", info); return returnvalue; } #ifdef GPAW_MR3 PyObject* scalapack_diagonalize_mr3(PyObject *self, PyObject *args) { // Standard driver for MRRR algorithm // Computes 'iu' eigenvalues and eigenvectors // http://icl.cs.utk.edu/lapack-forum/archives/scalapack/msg00159.html PyArrayObject* a; // Hamiltonian matrix PyArrayObject* desca; // Hamintonian matrix descriptor PyArrayObject* z; // eigenvector matrix PyArrayObject* w; // eigenvalue array int il = 1; // not used when range = 'A' or 'V' int iu; int eigvalm, nz; int one = 1; double vl, vu; // not used when range = 'A' or 'I' char jobz = 'V'; // eigenvectors also char range = 'I'; // eigenvalues il-th thru iu-th char uplo; if (!PyArg_ParseTuple(args, "OOciOO", &a, &desca, &uplo, &iu, &z, &w)) return NULL; // a desc // int a_ConTxt = INTP(desca)[1]; int a_m = INTP(desca)[2]; int a_n = INTP(desca)[3]; // Only square matrices assert (a_m == a_n); int n = a_n; // zdesc = adesc = bdesc; required by pdsyevx.f // If process not on BLACS grid, then return. // if (a_ConTxt == -1) Py_RETURN_NONE; // Query part, need to find the optimal size of a number of work arrays int info; int querywork = -1; int* iwork; int liwork; int lwork; int lrwork; int i_work; double d_work[3]; double_complex c_work; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { pdsyevr_(&jobz, &range, &uplo, &n, DOUBLEP(a), &one, &one, INTP(desca), &vl, &vu, &il, &iu, &eigvalm, &nz, DOUBLEP(w), DOUBLEP(z), &one, &one, INTP(desca), d_work, &querywork, &i_work, &querywork, &info); lwork = (int)(d_work[0]); } else { pzheevr_(&jobz, &range, &uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), &vl, &vu, &il, &iu, &eigvalm, &nz, DOUBLEP(w), (void*)COMPLEXP(z), &one, &one, INTP(desca), (void*)&c_work, &querywork, d_work, &querywork, &i_work, &querywork, &info); lwork = (int)(c_work); lrwork = (int)(d_work[0]); } if (info != 0) { printf ("info = %d", info); PyErr_SetString(PyExc_RuntimeError, "scalapack_diagonalize_evr error in query."); return NULL; } // Computation part liwork = i_work; iwork = GPAW_MALLOC(int, liwork); if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { double* work = GPAW_MALLOC(double, lwork); pdsyevr_(&jobz, &range, &uplo, &n, DOUBLEP(a), &one, &one, INTP(desca), &vl, &vu, &il, &iu, &eigvalm, &nz, DOUBLEP(w), DOUBLEP(z), &one, &one, INTP(desca), work, &lwork, iwork, &liwork, &info); free(work); } else { double_complex* work = GPAW_MALLOC(double_complex, lwork); double* rwork = GPAW_MALLOC(double, lrwork); pzheevr_(&jobz, &range, &uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), &vl, &vu, &il, &iu, &eigvalm, &nz, DOUBLEP(w), (void*)COMPLEXP(z), &one, &one, INTP(desca), (void*)work, &lwork, rwork, &lrwork, iwork, &liwork, &info); free(rwork); free(work); } free(iwork); // If this fails, fewer eigenvalues than requested were computed. assert (eigvalm == iu); PyObject* returnvalue = Py_BuildValue("i", info); return returnvalue; } #endif PyObject* scalapack_general_diagonalize_dc(PyObject *self, PyObject *args) { // General driver for divide and conquer algorithm // Computes *all* eigenvalues and eigenvectors PyArrayObject* a; // Hamiltonian matrix PyArrayObject* b; // overlap matrix PyArrayObject* desca; // Hamintonian matrix descriptor PyArrayObject* z; // eigenvector matrix PyArrayObject* w; // eigenvalue array int ibtype = 1; // Solve H*psi = lambda*S*psi int one = 1; char jobz = 'V'; // eigenvectors also char uplo; double scale; if (!PyArg_ParseTuple(args, "OOcOOO", &a, &desca, &uplo, &b, &z, &w)) return NULL; // a desc // int a_ConTxt = INTP(desca)[1]; int a_m = INTP(desca)[2]; int a_n = INTP(desca)[3]; // Only square matrices assert (a_m == a_n); int n = a_n; // zdesc = adesc = bdesc can be relaxed a bit according to pdsyevd.f // If process not on BLACS grid, then return. // if (a_ConTxt == -1) Py_RETURN_NONE; // Cholesky Decomposition int info; if (PyArray_DESCR(b)->type_num == NPY_DOUBLE) pdpotrf_(&uplo, &n, DOUBLEP(b), &one, &one, INTP(desca), &info); else pzpotrf_(&uplo, &n, (void*)COMPLEXP(b), &one, &one, INTP(desca), &info); if (info != 0) { PyErr_SetString(PyExc_RuntimeError, "scalapack_general_diagonalize_dc error in Cholesky."); return NULL; } // Query variables int querywork = -1; int* iwork; int liwork; int lwork; int lrwork; int i_work; double d_work; double_complex c_work; // NGST Query if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { pdsyngst_(&ibtype, &uplo, &n, DOUBLEP(a), &one, &one, INTP(desca), DOUBLEP(b), &one, &one, INTP(desca), &scale, &d_work, &querywork, &info); lwork = (int)(d_work); } else { pzhengst_(&ibtype, &uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), (void*)COMPLEXP(b), &one, &one, INTP(desca), &scale, (void*)&c_work, &querywork, &info); lwork = (int)(c_work); } if (info != 0) { PyErr_SetString(PyExc_RuntimeError, "scalapack_general_diagonalize_dc error in NGST query."); return NULL; } // NGST Compute if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { double* work = GPAW_MALLOC(double, lwork); pdsyngst_(&ibtype, &uplo, &n, DOUBLEP(a), &one, &one, INTP(desca), DOUBLEP(b), &one, &one, INTP(desca), &scale, work, &lwork, &info); free(work); } else { double_complex* work = GPAW_MALLOC(double_complex, lwork); pzhengst_(&ibtype, &uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), (void*)COMPLEXP(b), &one, &one, INTP(desca), &scale, (void*)work, &lwork, &info); free(work); } if (info != 0) { PyErr_SetString(PyExc_RuntimeError, "scalapack_general_diagonalize_dc error in NGST compute."); return NULL; } // NOTE: Scale is always equal to 1.0 above. In future version of ScaLAPACK, we // may need to rescale eigenvalues by scale. This can be accomplised by using // the BLAS1 d/zscal. See pdsygvx.f // EVD Query if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { pdsyevd_(&jobz, &uplo, &n, DOUBLEP(a), &one, &one, INTP(desca), DOUBLEP(w), DOUBLEP(z), &one, &one, INTP(desca), &d_work, &querywork, &i_work, &querywork, &info); lwork = (int)(d_work); } else { pzheevd_(&jobz, &uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), DOUBLEP(w), (void*)COMPLEXP(z), &one, &one, INTP(desca), (void*)&c_work, &querywork, &d_work, &querywork, &i_work, &querywork, &info); lwork = (int)(c_work); lrwork = (int)(d_work); } if (info != 0) { PyErr_SetString(PyExc_RuntimeError, "scalapack_general_diagonalize_dc error in EVD query."); return NULL; } // EVD Computation liwork = i_work; iwork = GPAW_MALLOC(int, liwork); if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { double* work = GPAW_MALLOC(double, lwork); pdsyevd_(&jobz, &uplo, &n, DOUBLEP(a), &one, &one, INTP(desca), DOUBLEP(w), DOUBLEP(z), &one, &one, INTP(desca), work, &lwork, iwork, &liwork, &info); free(work); } else { double_complex *work = GPAW_MALLOC(double_complex, lwork); double* rwork = GPAW_MALLOC(double, lrwork); pzheevd_(&jobz, &uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), DOUBLEP(w), (void*)COMPLEXP(z), &one, &one, INTP(desca), (void*)work, &lwork, rwork, &lrwork, iwork, &liwork, &info); free(rwork); free(work); } free(iwork); // Backtransformation to the original problem char trans; double d_one = 1.0; double_complex c_one = 1.0; if (uplo == 'U') trans = 'N'; else trans = 'T'; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) pdtrsm_("L", &uplo, &trans, "N", &n, &n, &d_one, DOUBLEP(b), &one, &one, INTP(desca), DOUBLEP(z), &one, &one, INTP(desca)); else pztrsm_("L", &uplo, &trans, "N", &n, &n, (void*)&c_one, (void*)COMPLEXP(b), &one, &one, INTP(desca), (void*)COMPLEXP(z), &one, &one, INTP(desca)); PyObject* returnvalue = Py_BuildValue("i", info); return returnvalue; } PyObject* scalapack_general_diagonalize_ex(PyObject *self, PyObject *args) { // General driver for bisection and inverse iteration algorithm // Computes 'iu' eigenvalues and eigenvectors PyArrayObject* a; // Hamiltonian matrix PyArrayObject* b; // overlap matrix PyArrayObject* desca; // Hamintonian matrix descriptor PyArrayObject* z; // eigenvector matrix PyArrayObject* w; // eigenvalue array int ibtype = 1; // Solve H*psi = lambda*S*psi int a_mycol = -1; int a_myrow = -1; int a_nprow, a_npcol; int il = 1; // not used when range = 'A' or 'V' int iu; // int eigvalm, nz; int one = 1; double vl, vu; // not used when range = 'A' or 'I' char jobz = 'V'; // eigenvectors also char range = 'I'; // eigenvalues il-th thru iu-th char uplo; if (!PyArg_ParseTuple(args, "OOciOOO", &a, &desca, &uplo, &iu, &b, &z, &w)) return NULL; // a desc int a_ConTxt = INTP(desca)[1]; int a_m = INTP(desca)[2]; int a_n = INTP(desca)[3]; // Only square matrices assert (a_m == a_n); int n = a_n; // zdesc = adesc = bdesc; required by pdsygvx.f // If process not on BLACS grid, then return. // if (a_ConTxt == -1) Py_RETURN_NONE; Cblacs_gridinfo_(a_ConTxt, &a_nprow, &a_npcol, &a_myrow, &a_mycol); // Convergence tolerance double abstol = 1.0e-8; // char cmach = 'U'; // most orthogonal eigenvectors // char cmach = 'S'; // most acccurate eigenvalues // double abstol = pdlamch_(&a_ConTxt, &cmach); // most orthogonal eigenvectors // double abstol = 2.0*pdlamch_(&a_ConTxt, &cmach); // most accurate eigenvalues double orfac = -1.0; // Query part, need to find the optimal size of a number of work arrays int info; int *ifail; ifail = GPAW_MALLOC(int, n); int *iclustr; iclustr = GPAW_MALLOC(int, 2*a_nprow*a_npcol); double *gap; gap = GPAW_MALLOC(double, a_nprow*a_npcol); int querywork = -1; int* iwork; int liwork; int lwork; // workspace size must be at least 3 int lrwork; // workspace size must be at least 3 int i_work; double d_work[3]; double_complex c_work; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { pdsygvx_(&ibtype, &jobz, &range, &uplo, &n, DOUBLEP(a), &one, &one, INTP(desca), DOUBLEP(b), &one, &one, INTP(desca), &vl, &vu, &il, &iu, &abstol, &eigvalm, &nz, DOUBLEP(w), &orfac, DOUBLEP(z), &one, &one, INTP(desca), d_work, &querywork, &i_work, &querywork, ifail, iclustr, gap, &info); lwork = MAX(3, (int)(d_work[0])); } else { pzhegvx_(&ibtype, &jobz, &range, &uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), (void*)COMPLEXP(b), &one, &one, INTP(desca), &vl, &vu, &il, &iu, &abstol, &eigvalm, &nz, DOUBLEP(w), &orfac, (void*)COMPLEXP(z), &one, &one, INTP(desca), (void*)&c_work, &querywork, d_work, &querywork, &i_work, &querywork, ifail, iclustr, gap, &info); lwork = MAX(3, (int)(c_work)); lrwork = MAX(3, (int)(d_work[0])); } if (info != 0) { PyErr_SetString(PyExc_RuntimeError, "scalapack_general_diagonalize_ex error in query."); return NULL; } // Computation part // lwork = lwork + (n-1)*n; // this is a ridiculous amount of workspace liwork = i_work; iwork = GPAW_MALLOC(int, liwork); if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { double* work = GPAW_MALLOC(double, lwork); pdsygvx_(&ibtype, &jobz, &range, &uplo, &n, DOUBLEP(a), &one, &one, INTP(desca), DOUBLEP(b), &one, &one, INTP(desca), &vl, &vu, &il, &iu, &abstol, &eigvalm, &nz, DOUBLEP(w), &orfac, DOUBLEP(z), &one, &one, INTP(desca), work, &lwork, iwork, &liwork, ifail, iclustr, gap, &info); free(work); } else { double_complex* work = GPAW_MALLOC(double_complex, lwork); double* rwork = GPAW_MALLOC(double, lrwork); pzhegvx_(&ibtype, &jobz, &range, &uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), (void*)COMPLEXP(b), &one, &one, INTP(desca), &vl, &vu, &il, &iu, &abstol, &eigvalm, &nz, DOUBLEP(w), &orfac, (void*)COMPLEXP(z), &one, &one, INTP(desca), (void*)work, &lwork, rwork, &lrwork, iwork, &liwork, ifail, iclustr, gap, &info); free(rwork); free(work); } free(iwork); free(gap); free(iclustr); free(ifail); // If this fails, fewer eigenvalues than requested were computed. assert (eigvalm == iu); PyObject* returnvalue = Py_BuildValue("i", info); return returnvalue; } #ifdef GPAW_MR3 PyObject* scalapack_general_diagonalize_mr3(PyObject *self, PyObject *args) { // General driver for MRRR algorithm // Computes 'iu' eigenvalues and eigenvectors // http://icl.cs.utk.edu/lapack-forum/archives/scalapack/msg00159.html PyArrayObject* a; // Hamiltonian matrix PyArrayObject* b; // overlap matrix PyArrayObject* desca; // Hamintonian matrix descriptor PyArrayObject* z; // eigenvector matrix PyArrayObject* w; // eigenvalue array int ibtype = 1; // Solve H*psi = lambda*S*psi int il = 1; // not used when range = 'A' or 'V' int iu; int eigvalm, nz; int one = 1; double vl, vu; // not used when range = 'A' or 'I' char jobz = 'V'; // eigenvectors also char range = 'I'; // eigenvalues il-th thru iu-th char uplo; double scale; if (!PyArg_ParseTuple(args, "OOciOOO", &a, &desca, &uplo, &iu, &b, &z, &w)) return NULL; // a desc // int a_ConTxt = INTP(desca)[1]; int a_m = INTP(desca)[2]; int a_n = INTP(desca)[3]; // Only square matrices assert (a_m == a_n); int n = a_n; // zdesc = adesc = bdesc can be relaxed a bit according to pdsyevd.f // If process not on BLACS grid, then return. // if (a_ConTxt == -1) Py_RETURN_NONE; // Cholesky Decomposition int info; if (PyArray_DESCR(b)->type_num == NPY_DOUBLE) pdpotrf_(&uplo, &n, DOUBLEP(b), &one, &one, INTP(desca), &info); else pzpotrf_(&uplo, &n, (void*)COMPLEXP(b), &one, &one, INTP(desca), &info); if (info != 0) { PyErr_SetString(PyExc_RuntimeError, "scalapack_general_diagonalize_mr3 error in Cholesky."); return NULL; } // Query variables int querywork = -1; int* iwork; int liwork; int lwork; int lrwork; int i_work; double d_work[3]; double_complex c_work; // NGST Query if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { pdsyngst_(&ibtype, &uplo, &n, DOUBLEP(a), &one, &one, INTP(desca), DOUBLEP(b), &one, &one, INTP(desca), &scale, d_work, &querywork, &info); lwork = (int)(d_work[0]); } else { pzhengst_(&ibtype, &uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), (void*)COMPLEXP(b), &one, &one, INTP(desca), &scale, (void*)&c_work, &querywork, &info); lwork = (int)(c_work); } if (info != 0) { PyErr_SetString(PyExc_RuntimeError, "scalapack_general_diagonalize_mr3 error in NGST query."); return NULL; } // NGST Compute if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { double* work = GPAW_MALLOC(double, lwork); pdsyngst_(&ibtype, &uplo, &n, DOUBLEP(a), &one, &one, INTP(desca), DOUBLEP(b), &one, &one, INTP(desca), &scale, work, &lwork, &info); free(work); } else { double_complex* work = GPAW_MALLOC(double_complex, lwork); pzhengst_(&ibtype, &uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), (void*)COMPLEXP(b), &one, &one, INTP(desca), &scale, (void*)work, &lwork, &info); free(work); } if (info != 0) { PyErr_SetString(PyExc_RuntimeError, "scalapack_general_diagonalize_mr3 error in NGST compute."); return NULL; } // NOTE: Scale is always equal to 1.0 above. In future version of ScaLAPACK, we // may need to rescale eigenvalues by scale. This can be accomplised by using // the BLAS1 d/zscal. See pdsygvx.f // EVR Query if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { pdsyevr_(&jobz, &range, &uplo, &n, DOUBLEP(a), &one, &one, INTP(desca), &vl, &vu, &il, &iu, &eigvalm, &nz, DOUBLEP(w), DOUBLEP(z), &one, &one, INTP(desca), d_work, &querywork, &i_work, &querywork, &info); lwork = (int)(d_work[0]); } else { pzheevr_(&jobz, &range, &uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), &vl, &vu, &il, &iu, &eigvalm, &nz, DOUBLEP(w), (void*)COMPLEXP(z), &one, &one, INTP(desca), (void*)&c_work, &querywork, d_work, &querywork, &i_work, &querywork, &info); lwork = (int)(c_work); lrwork = (int)(d_work[0]); } if (info != 0) { printf ("info = %d", info); PyErr_SetString(PyExc_RuntimeError, "scalapack_general_diagonalize_evr error in query."); return NULL; } // EVR Computation liwork = i_work; iwork = GPAW_MALLOC(int, liwork); if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { double* work = GPAW_MALLOC(double, lwork); pdsyevr_(&jobz, &range, &uplo, &n, DOUBLEP(a), &one, &one, INTP(desca), &vl, &vu, &il, &iu, &eigvalm, &nz, DOUBLEP(w), DOUBLEP(z), &one, &one, INTP(desca), work, &lwork, iwork, &liwork, &info); free(work); } else { double_complex* work = GPAW_MALLOC(double_complex, lwork); double* rwork = GPAW_MALLOC(double, lrwork); pzheevr_(&jobz, &range, &uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), &vl, &vu, &il, &iu, &eigvalm, &nz, DOUBLEP(w), (void*)COMPLEXP(z), &one, &one, INTP(desca), (void*)work, &lwork, rwork, &lrwork, iwork, &liwork, &info); free(rwork); free(work); } free(iwork); // Backtransformation to the original problem char trans; double d_one = 1.0; double_complex c_one = 1.0; if (uplo == 'U') trans = 'N'; else trans = 'T'; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) pdtrsm_("L", &uplo, &trans, "N", &n, &n, &d_one, DOUBLEP(b), &one, &one, INTP(desca), DOUBLEP(z), &one, &one, INTP(desca)); else pztrsm_("L", &uplo, &trans, "N", &n, &n, (void*)&c_one, (void*)COMPLEXP(b), &one, &one, INTP(desca), (void*)COMPLEXP(z), &one, &one, INTP(desca)); // If this fails, fewer eigenvalues than requested were computed. assert (eigvalm == iu); PyObject* returnvalue = Py_BuildValue("i", info); return returnvalue; } #endif PyObject* scalapack_inverse_cholesky(PyObject *self, PyObject *args) { // Cholesky plus inverse of triangular matrix PyArrayObject* a; // overlap matrix PyArrayObject* desca; // symmetric matrix description vector int info; double d_zero = 0.0; double_complex c_zero = 0.0; int one = 1; int two = 2; char diag = 'N'; // non-unit triangular char uplo; if (!PyArg_ParseTuple(args, "OOc", &a, &desca, &uplo)) return NULL; // adesc // int a_ConTxt = INTP(desca)[1]; int a_m = INTP(desca)[2]; int a_n = INTP(desca)[3]; // Only square matrices assert (a_m == a_n); int n = a_n; int p = a_n - 1; // If process not on BLACS grid, then return. // if (a_ConTxt == -1) Py_RETURN_NONE; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { pdpotrf_(&uplo, &n, DOUBLEP(a), &one, &one, INTP(desca), &info); if (info == 0) { pdtrtri_(&uplo, &diag, &n, DOUBLEP(a), &one, &one, INTP(desca), &info); if (uplo == 'L') pdlaset_("U", &p, &p, &d_zero, &d_zero, DOUBLEP(a), &one, &two, INTP(desca)); else pdlaset_("L", &p, &p, &d_zero, &d_zero, DOUBLEP(a), &two, &one, INTP(desca)); } } else { pzpotrf_(&uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), &info); if (info == 0) { pztrtri_(&uplo, &diag, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), &info); if (uplo == 'L') pzlaset_("U", &p, &p, (void*)&c_zero, (void*)&c_zero, (void*)COMPLEXP(a), &one, &two, INTP(desca)); else pzlaset_("L", &p, &p, (void*)&c_zero, (void*)&c_zero, (void*)COMPLEXP(a), &two, &one, INTP(desca)); } } PyObject* returnvalue = Py_BuildValue("i", info); return returnvalue; } PyObject* scalapack_inverse(PyObject *self, PyObject *args) { // Inverse of an hermitean matrix PyArrayObject* a; // Matrix PyArrayObject* desca; // Matrix description vector char uplo; int info; int one = 1; if (!PyArg_ParseTuple(args, "OOc", &a, &desca, &uplo)) return NULL; int a_m = INTP(desca)[2]; int a_n = INTP(desca)[3]; // Only square matrices assert (a_m == a_n); int n = a_n; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { assert(1==-1); // No double version implemented } else { pzpotrf_(&uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), &info); if (info == 0) { pzpotri_(&uplo, &n, (void*)COMPLEXP(a), &one, &one, INTP(desca), &info); } } PyObject* returnvalue = Py_BuildValue("i", info); return returnvalue; } /* PyObject* scalapack_solve(PyObject *self, PyObject *args) { // Solves equation Ax = B, where A is a general matrix PyArrayObject* a; // Matrix PyArrayObject* desca; // Matrix description vector PyArrayObject* b; // Matrix PyArrayObject* descb; // Matrix description vector char uplo; int info; int one = 1; if (!PyArg_ParseTuple(args, "OOOO", &a, &desca, &b, &descb)) return NULL; int a_m = INTP(desca)[2]; int a_n = INTP(desca)[3]; // Only square matrices assert (a_m == a_n); int b_m = INTP(descb)[2]; int b_n = INTP(descb)[3]; // Equation valid assert (a_n == b_m); int n = a_n; int nrhs = b_n; int* pivot = GPAW_MALLOC(int, a_m+2000); // TODO: How long should this exaclty be? if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { assert(1==-1); // No double version implemented } else { pzgesv_(&n, &nrhs,(void*)COMPLEXP(a), &one, &one, INTP(desca), pivot, (void*)COMPLEXP(b), &one, &one, INTP(descb), &info); } free(pivot); PyObject* returnvalue = Py_BuildValue("i", info); return returnvalue; } */ PyObject* scalapack_solve(PyObject *self, PyObject *args) { // Solves equation Ax = B, where A is a general matrix PyArrayObject* a; // Matrix PyArrayObject* desca; // Matrix description vector PyArrayObject* b; // Matrix PyArrayObject* descb; // Matrix description vector char uplo; int info; int one = 1; if (!PyArg_ParseTuple(args, "OOOO", &a, &desca, &b, &descb)) return NULL; int a_ConTxt = INTP(desca)[1]; int a_m = INTP(desca)[2]; int a_n = INTP(desca)[3]; int a_mb = INTP(desca)[4]; int a_nb = INTP(desca)[5]; // Only square matrices assert (a_m == a_n); int b_ConTxt = INTP(descb)[1]; int b_m = INTP(descb)[2]; int b_n = INTP(descb)[3]; // Equation valid assert (a_n == b_m); int n = a_n; int nrhs = b_n; int nprow, npcol, myrow, mycol, locM; Cblacs_gridinfo_(a_ConTxt, &nprow, &npcol, &myrow, &mycol); // LOCr( M ) <= ceil( ceil(M/MB_A)/NPROW )*MB_A locM = (((a_m/a_mb) + 1)/nprow + 1) * a_mb; /* * IPIV (local output) INTEGER array, dimension ( LOCr(M_A)+MB_A ) * This array contains the pivoting information. * IPIV(i) -> The global row local row i was swapped with. * This array is tied to the distributed matrix A. * An upper bound for these quantities may be computed by: * LOCr( M ) <= ceil( ceil(M/MB_A)/NPROW )*MB_A * M_A (global) DESCA( M_ ) The number of rows in the global * array A. * MB_A (global) DESCA( MB_ ) The blocking factor used to distribute * the rows of the array. * NPROW (global input) INTEGER * NPROW specifies the number of process rows in the grid * to be created. */ int* pivot = GPAW_MALLOC(int, locM + a_mb); //if (a->descr->type_num == PyArray_DOUBLE) if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { pdgesv_(&n, &nrhs,(double*)DOUBLEP(a), &one, &one, INTP(desca), pivot, (double*)DOUBLEP(b), &one, &one, INTP(descb), &info); } else { pzgesv_(&n, &nrhs,(void*)COMPLEXP(a), &one, &one, INTP(desca), pivot, (void*)COMPLEXP(b), &one, &one, INTP(descb), &info); } free(pivot); PyObject* returnvalue = Py_BuildValue("i", info); return returnvalue; } #endif #endif // PARALLEL gpaw-0.11.0.13004/c/bc.c0000664000175000017500000002043212553643466014434 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2009 CAMd * Copyright (C) 2005 CSC - IT Center for Science Ltd. * Please see the accompanying LICENSE file for further information. */ // Copyright (C) 2003 CAMP // Please see the accompanying LICENSE file for further information. #include #include #include "bc.h" #include "extensions.h" #include #include boundary_conditions* bc_init(const long size1[3], const long padding[3][2], const long npadding[3][2], const long neighbors[3][2], MPI_Comm comm, bool real, bool cfd) { boundary_conditions* bc = GPAW_MALLOC(boundary_conditions, 1); for (int i = 0; i < 3; i++) { bc->size1[i] = size1[i]; bc->size2[i] = size1[i] + padding[i][0] + padding[i][1]; bc->padding[i] = padding[i][0]; } bc->comm = comm; bc->ndouble = (real ? 1 : 2); bc->cfd = cfd; int rank = 0; if (comm != MPI_COMM_NULL) MPI_Comm_rank(comm, &rank); int start[3]; int size[3]; for (int i = 0; i < 3; i++) { start[i] = padding[i][0]; size[i] = size1[i]; } for (int i = 0; i < 3; i++) { int n = bc->ndouble; for (int j = 0; j < 3; j++) if (j != i) n *= size[j]; for (int d = 0; d < 2; d++) { int ds = npadding[i][d]; int dr = padding[i][d]; for (int j = 0; j < 3; j++) { bc->sendstart[i][d][j] = start[j]; bc->sendsize[i][d][j] = size[j]; bc->recvstart[i][d][j] = start[j]; bc->recvsize[i][d][j] = size[j]; } if (d == 0) { bc->sendstart[i][d][i] = dr; bc->recvstart[i][d][i] = 0; } else { bc->sendstart[i][d][i] = padding[i][0] + size1[i] - ds; bc->recvstart[i][d][i] = padding[i][0] + size1[i]; } bc->sendsize[i][d][i] = ds; bc->recvsize[i][d][i] = dr; bc->sendproc[i][d] = DO_NOTHING; bc->recvproc[i][d] = DO_NOTHING; bc->nsend[i][d] = 0; bc->nrecv[i][d] = 0; int p = neighbors[i][d]; if (p == rank) { if (ds > 0) bc->sendproc[i][d] = COPY_DATA; if (dr > 0) bc->recvproc[i][d] = COPY_DATA; } else if (p >= 0) { // Communication required: if (ds > 0) { bc->sendproc[i][d] = p; bc->nsend[i][d] = n * ds; } if (dr > 0) { bc->recvproc[i][d] = p; bc->nrecv[i][d] = n * dr; } } } if (cfd == 0) { start[i] = 0; size[i] = bc->size2[i]; } // If the two neighboring processors along the // i'th axis are the same, then we join the two communications // into one: bc->rjoin[i] = ((bc->recvproc[i][0] == bc->recvproc[i][1]) && bc->recvproc[i][0] >= 0); bc->sjoin[i] = ((bc->sendproc[i][0] == bc->sendproc[i][1]) && bc->sendproc[i][0] >= 0); } bc->maxsend = 0; bc->maxrecv = 0; for (int i = 0; i < 3; i++) { int n = bc->nsend[i][0] + bc->nsend[i][1]; if (n > bc->maxsend) bc->maxsend = n; n = bc->nrecv[i][0] + bc->nrecv[i][1]; if (n > bc->maxrecv) bc->maxrecv = n; } return bc; } void bc_unpack1(const boundary_conditions* bc, const double* aa1, double* aa2, int i, MPI_Request recvreq[2], MPI_Request sendreq[2], double* rbuff, double* sbuff, const double_complex phases[2], int thd, int nin) { int ng = bc->ndouble * bc->size1[0] * bc->size1[1] * bc->size1[2]; int ng2 = bc->ndouble * bc->size2[0] * bc->size2[1] * bc->size2[2]; bool real = (bc->ndouble == 1); for (int m = 0; m < nin; m++) // Copy data: if (i == 0) { // Zero all of a2 array. We should only zero the bounaries // that are not periodic, but it's simpler to zero everything! // XXX memset(aa2 + m * ng2, 0, ng2 * sizeof(double)); // Copy data from a1 to central part of a2: if (real) bmgs_paste(aa1 + m * ng, bc->size1, aa2 + m * ng2, bc->size2, bc->sendstart[0][0]); else bmgs_pastez((const double_complex*)(aa1 + m * ng), bc->size1, (double_complex*)(aa2 + m * ng2), bc->size2, bc->sendstart[0][0]); } #ifdef PARALLEL // Start receiving. for (int d = 0; d < 2; d++) { int p = bc->recvproc[i][d]; if (p >= 0) { if (bc->rjoin[i]) { if (d == 0) MPI_Irecv(rbuff, (bc->nrecv[i][0] + bc->nrecv[i][1]) * nin, MPI_DOUBLE, p, 10 * thd + 1000 * i + 100000, bc->comm, &recvreq[0]); } else { MPI_Irecv(rbuff, bc->nrecv[i][d] * nin, MPI_DOUBLE, p, d + 10 * thd + 1000 * i, bc->comm, &recvreq[d]); rbuff += bc->nrecv[i][d] * nin; } } } // Prepare send-buffers and start sending: double* sbuf = sbuff; double* sbuf0 = sbuff; for (int d = 0; d < 2; d++) { sendreq[d] = 0; int p = bc->sendproc[i][d]; if (p >= 0) { const int* start = bc->sendstart[i][d]; const int* size = bc->sendsize[i][d]; for (int m = 0; m < nin; m++) if (real) bmgs_cut(aa2 + m * ng2, bc->size2, start, sbuf + m * bc->nsend[i][d], size); else bmgs_cutmz((const double_complex*)(aa2 + m * ng2), bc->size2, start, (double_complex*)(sbuf + m * bc->nsend[i][d]), size, phases[d]); if (bc->sjoin[i]) { if (d == 1) { MPI_Isend(sbuf0, (bc->nsend[i][0] + bc->nsend[i][1]) * nin, MPI_DOUBLE, p, 10 * thd + 1000 * i + 100000, bc->comm, &sendreq[0]); } } else { MPI_Isend(sbuf, bc->nsend[i][d] * nin, MPI_DOUBLE, p, 1 - d + 10 * thd + 1000 * i, bc->comm, &sendreq[d]); } sbuf += bc->nsend[i][d] * nin; } } #endif // Parallel for (int m = 0; m < nin; m++) { // Copy data for periodic boundary conditions: for (int d = 0; d < 2; d++) if (bc->sendproc[i][d] == COPY_DATA) { if (real) bmgs_translate(aa2 + m * ng2, bc->size2, bc->sendsize[i][d], bc->sendstart[i][d], bc->recvstart[i][1 - d]); else bmgs_translatemz((double_complex*)(aa2 + m * ng2), bc->size2, bc->sendsize[i][d], bc->sendstart[i][d], bc->recvstart[i][1 - d], phases[d]); } } } void bc_unpack2(const boundary_conditions* bc, double* a2, int i, MPI_Request recvreq[2], MPI_Request sendreq[2], double* rbuf, int nin) { #ifdef PARALLEL int ng2 = bc->ndouble * bc->size2[0] * bc->size2[1] * bc->size2[2]; // Store data from receive-buffer: bool real = (bc->ndouble == 1); double* rbuf0 = rbuf; for (int d = 0; d < 2; d++) if (bc->recvproc[i][d] >= 0) { if (bc->rjoin[i]) { if (d == 0) { MPI_Wait(&recvreq[0], MPI_STATUS_IGNORE); rbuf += bc->nrecv[i][1] * nin; } else rbuf = rbuf0; } else MPI_Wait(&recvreq[d], MPI_STATUS_IGNORE); for (int m = 0; m < nin; m++) if (real) bmgs_paste(rbuf + m * bc->nrecv[i][d], bc->recvsize[i][d], a2 + m * ng2, bc->size2, bc->recvstart[i][d]); else bmgs_pastez((const double_complex*)(rbuf + m * bc->nrecv[i][d]), bc->recvsize[i][d], (double_complex*)(a2 + m * ng2), bc->size2, bc->recvstart[i][d]); rbuf += bc->nrecv[i][d] * nin; } // This does not work on the ibm with gcc! We do a blocking send instead. for (int d = 0; d < 2; d++) if (sendreq[d] != 0) MPI_Wait(&sendreq[d], MPI_STATUS_IGNORE); #endif // PARALLEL } gpaw-0.11.0.13004/c/extensions.h0000664000175000017500000000267412553643466016264 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2008 CAMd * Copyright (C) 2005 CSC - IT Center for Science Ltd. * Please see the accompanying LICENSE file for further information. */ #ifndef H_EXTENSIONS #define H_EXTENSIONS #include #define PY_ARRAY_UNIQUE_SYMBOL GPAW_ARRAY_API #define NO_IMPORT_ARRAY #include #include /* If strict ANSI, then some useful macros are not defined */ #if defined(__STRICT_ANSI__) && !defined(__DARWIN_UNIX03) # define M_PI 3.14159265358979323846 /* pi */ #endif #ifndef DOUBLECOMPLEXDEFINED # define DOUBLECOMPLEXDEFINED 1 # include typedef double complex double_complex; #endif #if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 4 # define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None #endif #define INLINE inline static INLINE void* gpaw_malloc(size_t n) { void* p = malloc(n); assert(p != NULL); return p; } #ifdef GPAW_BGP #define GPAW_MALLOC(T, n) (gpaw_malloc((n) * sizeof(T))) #else #ifdef GPAW_AIX #define GPAW_MALLOC(T, n) (malloc((n) * sizeof(T))) #else #define GPAW_MALLOC(T, n) (gpaw_malloc((n) * sizeof(T))) #endif #endif #define MIN(x, y) ((x) < (y) ? (x) : (y)) #define MAX(x, y) ((x) > (y) ? (x) : (y)) #define INTP(a) ((int*)PyArray_DATA(a)) #define LONGP(a) ((long*)PyArray_DATA(a)) #define DOUBLEP(a) ((double*)PyArray_DATA(a)) #define COMPLEXP(a) ((double_complex*)PyArray_DATA(a)) #endif //H_EXTENSIONS gpaw-0.11.0.13004/c/mympi.h0000664000175000017500000000035012553643466015205 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Please see the accompanying LICENSE file for further information. */ typedef struct { PyObject_HEAD int size; int rank; MPI_Comm comm; PyObject* parent; int* members; } MPIObject; gpaw-0.11.0.13004/c/mlsqr.c0000664000175000017500000001303312553643466015205 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2009 CAMd * Please see the accompanying LICENSE file for further information. */ #include #define PY_ARRAY_UNIQUE_SYMBOL GPAW_ARRAY_API #define NO_IMPORT_ARRAY #include #include "extensions.h" #ifdef GPAW_NO_UNDERSCORE_LAPACK # define dgels_ dgels #endif // Predefine dgels function of lapack int dgels_(char* trans, int *m, int *n, int *nrhs, double* a, int *lda, double* b, int *ldb, double* work, int* lwork, int *info); int safemod(int x, int m) { return (x%m + m)%m; } // Perform a moving linear least squares interpolation to arrays // Input arguments: // order: order of polynomial used (1 or 2) // cutoff: the cutoff of weight (in grid points) // coords: scaled coords [0,1] for interpolation // N_c: number of grid points // beg_c: first grid point // data: the array used // target: the results are stored in this array PyObject* mlsqr(PyObject *self, PyObject *args) { // The order of interpolation unsigned char order = -1; // The cutoff for moving least squares double cutoff = -1; // The coordinates for interpolation: array of size (3, N) PyArrayObject* coords = 0; // Number of grid points PyArrayObject* N_c = 0; // Beginning of grid PyArrayObject* beg_c = 0; // The 3d-data to be interpolated: array of size (X, Y, Z) PyArrayObject* data; // The interpolation target: array of size (N,) PyArrayObject* target = 0; if (!PyArg_ParseTuple(args, "BdOOOOO", &order, &cutoff, &coords, &N_c, &beg_c, &data, &target)) { return NULL; } int coeffs = -1; if (order == 1) { coeffs = 4; } if (order == 2) { coeffs = 10; // 1 x y z xy yz zx xx yy zz } if (order == 3) { // 1 x y z xy yz zx xx yy zz // xxy xxz yyx yyz zzx zzy // xxx yyy zzz zyz coeffs = 20; } int points = PyArray_DIM(coords, 0); double* coord_nc = DOUBLEP(coords); double* grid_points = DOUBLEP(N_c); double* grid_start = DOUBLEP(beg_c); double* target_n = DOUBLEP(target); double* data_g = DOUBLEP(data); // TODO: Calculate fit const int sizex = (int) ceil(cutoff); const int sizey = (int) ceil(cutoff); const int sizez = (int) ceil(cutoff); // Allocate X-matrix and b-vector int source_points = (2*sizex+1)*(2*sizey+1)*(2*sizez+1); double* X = GPAW_MALLOC(double, coeffs*source_points); double* b = GPAW_MALLOC(double, source_points); double* work = GPAW_MALLOC(double, coeffs*source_points); // The multipliers for each dimension int ldx = PyArray_DIM(data, 1) * PyArray_DIM(data, 2); int ldy = PyArray_DIM(data, 2); int ldz = 1; // For each point to be interpolated for (int p=0; p< points; p++) { double x = (*coord_nc++)*grid_points[0] - grid_start[0]; double y = (*coord_nc++)*grid_points[1] - grid_start[1]; double z = (*coord_nc++)*grid_points[2] - grid_start[2]; // The grid center point int cx2 = (int) round(x); int cy2 = (int) round(y); int cz2 = (int) round(z); // Scaled to grid int cx = safemod(cx2, PyArray_DIM(data, 0)); int cy = safemod(cy2, PyArray_DIM(data, 1)); int cz = safemod(cz2, PyArray_DIM(data, 2)); double* i_X = X; double* i_b = b; // For each point to take into account for (int dx=-sizex;dx<=sizex;dx++) for (int dy=-sizey;dy<=sizey;dy++) for (int dz=-sizez;dz<=sizez;dz++) { // Coordinates centered on x,y,z double sx = (cx2 + dx) - x; double sy = (cy2 + dy) - y; double sz = (cz2 + dz) - z; // Normalized distance from center double d = sqrt(sx*sx+sy*sy+sz*sz) / cutoff; double w = 0.0; if (d < 1) { w = (1-d)*(1-d); w*=w; w*=(4*d+1); } //double w = exp(-d*d); *i_X++ = w*1.0; *i_X++ = w*sx; *i_X++ = w*sy; *i_X++ = w*sz; if (order > 1) { *i_X++ = w*sx*sy; *i_X++ = w*sy*sz; *i_X++ = w*sz*sx; *i_X++ = w*sx*sx; *i_X++ = w*sy*sy; *i_X++ = w*sz*sz; } if (order > 2) { *i_X++ = w*sx*sy*sz; // xyz *i_X++ = w*sx*sx*sx; // xxx *i_X++ = w*sy*sy*sy; // yyy *i_X++ = w*sz*sz*sz; // zzz *i_X++ = w*sx*sx*sy; // xxy *i_X++ = w*sx*sx*sz; // xxz *i_X++ = w*sy*sy*sx; // yyx *i_X++ = w*sy*sy*sz; // yyz *i_X++ = w*sz*sz*sx; // zzx *i_X++ = w*sz*sz*sy; // zzy } *i_b++ = w*data_g[ safemod(cx+dx, PyArray_DIM(data, 0)) * ldx + safemod(cy+dy, PyArray_DIM(data, 1)) * ldy + safemod(cz+dz, PyArray_DIM(data, 2)) * ldz ]; } int info = 0; int rhs = 1; int worksize = coeffs*source_points; int ldb = source_points; dgels_("T", &coeffs, // ...times 4. &source_points, // lhs is of size sourcepoints... &rhs, // one rhs. X, // provide lhs &coeffs, // Leading dimension of X b, // provide rhs &ldb, // Leading dimension of b work, // work array (and output) &worksize, // the size of work array &info); // info if (info != 0) printf("WARNING: dgels returned %d!", info); // Evaluate the polynomial // Due to centered coordinates, it's just the constant term double value = b[0]; *target_n++ = value; //Nearest neighbour //double value = data_g[ cx*data->dimensions[1]*data->dimensions[2] + cy*data->dimensions[2] + cz ]; //printf("%.5f" , value); } free(work); free(b); free(X); Py_RETURN_NONE; } gpaw-0.11.0.13004/c/f2c.h0000664000175000017500000000044112553643466014525 0ustar jensjjensj00000000000000/* Definitions needed by code transfered with f2c */ #include #include typedef int integer; typedef double doublereal; typedef struct { doublereal r, i; } doublecomplex; #ifndef STATIC_NUMERIC inline double pow_dd(double *x, double *y) { return pow(*x,*y); } #endif gpaw-0.11.0.13004/c/hdf5.c0000664000175000017500000004231012553643466014675 0ustar jensjjensj00000000000000/* * Copyright (C) 2010-2011 CSC - IT Center for Science Ltd. * Please see the accompanying LICENSE file for further information. */ /* Light weight Python interface to HDF5 functions needed by GPAW Generally, HDF5 object identifiers are integers and they are passed as such between Python and C. All other data to HDF5 functions is passed in NumPy arrays. At the moment no checks are made for ensuring that data actually is NumPy array. The Python interface functions return either object identifier as int None with the exceptions tuple from h5s_get_shape string from h5l_get_name_by_idx */ #ifdef GPAW_WITH_HDF5 #include #define PY_ARRAY_UNIQUE_SYMBOL GPAW_ARRAY_API #define NO_IMPORT_ARRAY #include #include #include "extensions.h" #ifdef PARALLEL #include #include "mympi.h" #endif // File functions PyObject* h5f_open(PyObject *self, PyObject *args) { int pid = H5P_DEFAULT; const char* name; const char mode = 'r'; if (!PyArg_ParseTuple(args, "s|ci", &name, &mode, &pid)) return NULL; unsigned flag; if (mode == 'r') flag = H5F_ACC_RDONLY; else flag = H5F_ACC_RDWR; int fid = H5Fopen(name, flag, pid); return Py_BuildValue("i", fid); } PyObject* h5f_create(PyObject *self, PyObject *args) { int pid = H5P_DEFAULT; // Property list id const char* name; if (!PyArg_ParseTuple(args, "s|i", &name, &pid)) return NULL; unsigned flag = H5F_ACC_TRUNC; // Always truncate the file int fid = H5Fcreate(name, flag, H5P_DEFAULT, pid); return Py_BuildValue("i", fid); } PyObject* h5f_close(PyObject *self, PyObject *args) { int fid; if (!PyArg_ParseTuple(args, "i", &fid)) return NULL; H5Fclose(fid); Py_RETURN_NONE; } // Group functions PyObject* h5g_open(PyObject *self, PyObject *args) { int loc_id; const char* name; if (!PyArg_ParseTuple(args, "is", &loc_id, &name)) return NULL; int gid = H5Gopen(loc_id, name, H5P_DEFAULT); return Py_BuildValue("i", gid); } PyObject* h5g_create(PyObject *self, PyObject *args) { int loc_id; const char* name; if (!PyArg_ParseTuple(args, "is", &loc_id, &name)) return NULL; int gid = H5Gcreate2(loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); return Py_BuildValue("i", gid); } PyObject* h5g_get_num_objs(PyObject *self, PyObject *args) { int id; if (!PyArg_ParseTuple(args, "i", &id)) return NULL; H5G_info_t group_info; H5Gget_info(id, &group_info); int nobjs = group_info.nlinks; return Py_BuildValue("i", nobjs); } PyObject* h5g_close(PyObject *self, PyObject *args) { int id; if (!PyArg_ParseTuple(args, "i", &id)) return NULL; H5Gclose(id); Py_RETURN_NONE; } // Attribute functions PyObject* h5a_open(PyObject *self, PyObject *args) { int loc_id; const char* name; if (!PyArg_ParseTuple(args, "is", &loc_id, &name)) return NULL; // Check first for the existence if (H5Aexists(loc_id, name) == 0 ) return PyErr_Format(PyExc_KeyError, "HDF5 Attribute %s does not exist", name); int aid = H5Aopen(loc_id, name, H5P_DEFAULT); return Py_BuildValue("i", aid); } PyObject* h5a_create(PyObject *self, PyObject *args) { int loc_id; int datatype; int dataspace; const char* name; if (!PyArg_ParseTuple(args, "isii", &loc_id, &name, &datatype, &dataspace)) return NULL; hid_t aid = H5Acreate2(loc_id, name, datatype, dataspace, H5P_DEFAULT, H5P_DEFAULT); return Py_BuildValue("i", aid); } PyObject* h5a_write(PyObject *self, PyObject *args) { int aid; int datatype; PyArrayObject* data; if (!PyArg_ParseTuple(args, "iiO", &aid, &datatype, &data)) return NULL; char* buf = PyArray_DATA(data); H5Awrite(aid, datatype, buf); Py_RETURN_NONE; } PyObject* h5a_read(PyObject *self, PyObject *args) { int aid; int datatype; PyArrayObject* data; if (!PyArg_ParseTuple(args, "iiO", &aid, &datatype, &data)) return NULL; char* buf = PyArray_DATA(data); H5Aread(aid, datatype, buf); Py_RETURN_NONE; } PyObject* h5a_get_space(PyObject *self, PyObject *args) { // Returns the dataspace as tuple int aid; if (!PyArg_ParseTuple(args, "i", &aid)) return NULL; hid_t dataspace = H5Aget_space(aid); return Py_BuildValue("i", dataspace); } PyObject* h5a_get_type(PyObject *self, PyObject *args) { // Returns the dataspace as tuple int aid; if (!PyArg_ParseTuple(args, "i", &aid)) return NULL; hid_t filetype = H5Aget_type(aid); hid_t datatype = H5Tget_native_type(filetype, H5T_DIR_ASCEND); H5Tclose(filetype); return Py_BuildValue("i", datatype); } PyObject* h5a_exists_by_name(PyObject *self, PyObject *args) { int id; const char* name; if (!PyArg_ParseTuple(args, "is", &id, &name)) return NULL; int exists = H5Aexists_by_name(id, ".", name, H5P_DEFAULT); return Py_BuildValue("b", exists); } PyObject* h5a_close(PyObject *self, PyObject *args) { int id; if (!PyArg_ParseTuple(args, "i", &id)) return NULL; H5Aclose(id); Py_RETURN_NONE; } // Datatype functions PyObject* h5t_get_class(PyObject *self, PyObject *args) { int tid; if (!PyArg_ParseTuple(args, "i", &tid)) return NULL; hid_t class = H5Tget_class(tid); return Py_BuildValue("i", class); } PyObject* h5t_get_size(PyObject *self, PyObject *args) { int tid; if (!PyArg_ParseTuple(args, "i", &tid)) return NULL; hid_t size = H5Tget_size(tid); return Py_BuildValue("i", size); } PyObject* h5_type_from_numpy(PyObject *self, PyObject *args) { PyArrayObject *array; if (!PyArg_ParseTuple(args, "O", &array)) return NULL; int type = PyArray_TYPE(array); hid_t datatype; if (type == NPY_STRING ) { datatype = H5Tcopy(H5T_C_S1); H5Tset_size(datatype, PyArray_ITEMSIZE(array)); } else if (type == NPY_DOUBLE) { datatype = H5Tcopy(H5T_NATIVE_DOUBLE); } else if (type == NPY_LONG) { datatype = H5Tcopy(H5T_NATIVE_LONG); } else if (type == NPY_INT) { datatype = H5Tcopy(H5T_NATIVE_INT); } else if (type == NPY_BOOL) { datatype = H5Tenum_create(H5T_NATIVE_INT8); int value; value = 0; // Convert the int value to int8 with HDF5 H5Tconvert(H5T_NATIVE_INT, H5T_NATIVE_INT8, 1, &value, NULL, H5P_DEFAULT); H5Tenum_insert(datatype, "FALSE", &value); value = 1; H5Tconvert(H5T_NATIVE_INT, H5T_NATIVE_INT8, 1, &value, NULL, H5P_DEFAULT); H5Tenum_insert(datatype, "TRUE", &value); } else if (type == NPY_CDOUBLE) { datatype = H5Tcreate(H5T_COMPOUND, sizeof(double complex)); H5Tinsert(datatype, "re", 0, H5T_NATIVE_DOUBLE); H5Tinsert(datatype, "im", sizeof(double), H5T_NATIVE_DOUBLE); } else { return PyErr_Format(PyExc_RuntimeError, "Unsupportted datatype"); } return Py_BuildValue("i", datatype); } PyObject* h5t_close(PyObject *self, PyObject *args) { int id; if (!PyArg_ParseTuple(args, "i", &id)) return NULL; H5Tclose(id); Py_RETURN_NONE; } // Dataspace functions PyObject* h5s_create(PyObject *self, PyObject *args) { PyArrayObject *shape; if (!PyArg_ParseTuple(args, "O", &shape)) return NULL; int rank = PyArray_DIM(shape, 0); long* dims_i = PyArray_DATA(shape); // hsize_t may be larger than long so we need to copy hsize_t* dims = (hsize_t *) malloc(rank * sizeof(hsize_t)); for (int i=0; i < rank; i++) dims[i] = dims_i[i]; int sid = H5Screate_simple(rank, dims, NULL); free(dims); return Py_BuildValue("i", sid); } PyObject* h5s_select_hyperslab(PyObject *self, PyObject *args) { int dataspace; PyArrayObject* np_offset; PyArrayObject* np_stride; PyArrayObject* np_count; PyArrayObject* np_block; if (!PyArg_ParseTuple(args, "iOOOO", &dataspace, &np_offset, &np_stride, &np_count, &np_block)) return NULL; // None can be passed to indicate use of default values e.g. NULL for // stride and block long* temp = PyArray_DATA(np_offset); int rank = PyArray_DIMS(np_offset)[0]; hsize_t* offset = (hsize_t *) malloc(rank * sizeof(hsize_t)); for (int i=0; i < rank; i++) offset[i] = temp[i]; hsize_t* stride = NULL; if ((PyObject *)np_stride != Py_None) { temp = PyArray_DATA(np_stride); stride = (hsize_t *) malloc(rank * sizeof(hsize_t)); for (int i=0; i < rank; i++) stride[i] = temp[i]; } temp = PyArray_DATA(np_count); hsize_t* count = (hsize_t *) malloc(rank * sizeof(hsize_t)); for (int i=0; i < rank; i++) count[i] = temp[i]; hsize_t* block = NULL; if ((PyObject *)np_block != Py_None) return PyErr_Format(PyExc_NotImplementedError, "Block parameter"); H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset, stride, count, block); free(offset); if (stride != NULL) free(stride); free(count); Py_RETURN_NONE; } PyObject* h5s_select_none(PyObject *self, PyObject *args) { int dataspace; if (!PyArg_ParseTuple(args, "i", &dataspace)) return NULL; H5Sselect_none(dataspace); Py_RETURN_NONE; } PyObject* h5s_get_shape(PyObject *self, PyObject *args) { // Returns the dataspace as tuple int dataspace; if (!PyArg_ParseTuple(args, "i", &dataspace)) return NULL; int rank = H5Sget_simple_extent_ndims(dataspace); hsize_t* dims = (hsize_t *) malloc(rank * sizeof(hsize_t)); rank = H5Sget_simple_extent_dims(dataspace, dims, NULL); PyObject* shape = PyTuple_New(rank); int i; for (i=0; i < rank; i++) { PyTuple_SetItem(shape, i, PyInt_FromLong(dims[i])); } free(dims); return shape; } PyObject* h5s_close(PyObject *self, PyObject *args) { int id; if (!PyArg_ParseTuple(args, "i", &id)) return NULL; H5Sclose(id); Py_RETURN_NONE; } // Dataset functions PyObject* h5d_open(PyObject *self, PyObject *args) { int loc_id; const char* name; if (!PyArg_ParseTuple(args, "is", &loc_id, &name)) return NULL; int did = H5Dopen2(loc_id, name, H5P_DEFAULT); return Py_BuildValue("i", did); } PyObject* h5d_create(PyObject *self, PyObject *args) { int loc_id; const char* name; int dtype_id; int space_id; if (!PyArg_ParseTuple(args, "isii", &loc_id, &name, &dtype_id, &space_id)) return NULL; int did = H5Dcreate2(loc_id, name, dtype_id, space_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); return Py_BuildValue("i", did); } PyObject* h5d_write(PyObject *self, PyObject *args) { int did; int memtype; int memspace; int filespace; int pid = H5P_DEFAULT; PyArrayObject* data; if (!PyArg_ParseTuple(args, "iiiiO|i", &did, &memtype, &memspace, &filespace, &data, &pid)) return NULL; char* buf = PyArray_DATA(data); H5Dwrite(did, memtype, memspace, filespace, pid, buf); Py_RETURN_NONE; } PyObject* h5d_read(PyObject *self, PyObject *args) { int did; int memtype; int memspace; int filespace; int pid = H5P_DEFAULT; PyArrayObject* data; if (!PyArg_ParseTuple(args, "iiiiO|i", &did, &memtype, &memspace, &filespace, &data, &pid)) return NULL; char* buf = PyArray_DATA(data); H5Dread(did, memtype, memspace, filespace, pid, buf); Py_RETURN_NONE; } PyObject* h5d_get_space(PyObject *self, PyObject *args) { int did; if (!PyArg_ParseTuple(args, "i", &did)) return NULL; hid_t dataspace = H5Dget_space(did); return Py_BuildValue("i", dataspace); } PyObject* h5d_get_type(PyObject *self, PyObject *args) { int did; if (!PyArg_ParseTuple(args, "i", &did)) return NULL; hid_t filetype = H5Dget_type(did); hid_t datatype = H5Tget_native_type(filetype, H5T_DIR_ASCEND); H5Tclose(filetype); return Py_BuildValue("i", datatype); } PyObject* h5d_close(PyObject *self, PyObject *args) { int id; if (!PyArg_ParseTuple(args, "i", &id)) return NULL; H5Dclose(id); Py_RETURN_NONE; } // Property list related functions PyObject* h5p_create(PyObject *self, PyObject *args) { int cls_id; if (!PyArg_ParseTuple(args, "i", &cls_id)) return NULL; int pid = H5Pcreate(cls_id); return Py_BuildValue("i", pid); } #ifdef PARALLEL PyObject* h5p_set_fapl_mpio(PyObject *self, PyObject *args) { PyObject *comm_obj; int plist_id; if (!PyArg_ParseTuple(args, "iO", &plist_id, &comm_obj)) return NULL; MPI_Comm comm = MPI_COMM_NULL; MPI_Info info = MPI_INFO_NULL; if (comm_obj != Py_None) { comm = ((MPIObject*)comm_obj)->comm; // The following was needed at some point due to bug in Cray MPI /* int nprocs; MPI_Comm_size(comm, &nprocs); char tmp[20]; MPI_Info_create(&info); sprintf(tmp,"%d", nprocs); MPI_Info_set(info,"cb_nodes",tmp); */ #ifdef __bgp__ // Wavefunction write requires large amounts of memory. // Appears to be a deficiency in the ROMIO driver. // bgl_nodes_pset controls the number of aggregator // tasks per pset. The default value is 8. // In many cases, it will also be necessary to set // DCMF_ALLTOALL_PREMALLOC = N char tmp[20]; int info_param = 32; MPI_Info_create(&info); sprintf(tmp,"%d", info_param); MPI_Info_set(info,"bgl_nodes_pset",tmp); #endif } H5Pset_fapl_mpio(plist_id, comm, info); Py_RETURN_NONE; } PyObject* h5p_set_dxpl_mpio(PyObject *self, PyObject *args) { int plist_id; if (!PyArg_ParseTuple(args, "i", &plist_id)) return NULL; H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_COLLECTIVE); Py_RETURN_NONE; } #endif PyObject* h5p_close(PyObject *self, PyObject *args) { int id; if (!PyArg_ParseTuple(args, "i", &id)) return NULL; H5Pclose(id); Py_RETURN_NONE; } // Info functions PyObject* h5i_get_type(PyObject *self, PyObject *args) { int id; if (!PyArg_ParseTuple(args, "i", &id)) return NULL; int type = H5Iget_type(id); return Py_BuildValue("i", type); } // Object functions PyObject* h5o_open(PyObject *self, PyObject *args) { int loc_id; const char* name; if (!PyArg_ParseTuple(args, "is", &loc_id, &name)) return NULL; int oid = H5Oopen(loc_id, name, H5P_DEFAULT); return Py_BuildValue("i", oid); } PyObject* h5o_close(PyObject *self, PyObject *args) { int oid; if (!PyArg_ParseTuple(args, "i", &oid)) return NULL; H5Oclose(oid); Py_RETURN_NONE; } // List functions PyObject* h5l_get_name_by_idx(PyObject *self, PyObject *args) { int id; int idx; if (!PyArg_ParseTuple(args, "ii", &id, &idx)) return NULL; ssize_t size; char *name; // Get size of the name, add 1 for NULL terminator size = 1 + H5Lget_name_by_idx(id, ".", H5_INDEX_NAME, H5_ITER_INC, idx, NULL, 0, H5P_DEFAULT); name = (char *) malloc(size); H5Lget_name_by_idx(id, ".", H5_INDEX_NAME, H5_ITER_INC, idx, name, (size_t) size, H5P_DEFAULT); PyObject* retval = Py_BuildValue("s", name); free(name); return retval; } static PyMethodDef functions[] = { {"h5f_open", h5f_open, METH_VARARGS, 0}, {"h5f_create", h5f_create, METH_VARARGS, 0}, {"h5f_close", h5f_close, METH_VARARGS, 0}, {"h5g_open", h5g_open, METH_VARARGS, 0}, {"h5g_get_num_objs", h5g_get_num_objs, METH_VARARGS, 0}, {"h5g_create", h5g_create, METH_VARARGS, 0}, {"h5g_close", h5g_close, METH_VARARGS, 0}, {"h5a_open", h5a_open, METH_VARARGS, 0}, {"h5a_create", h5a_create, METH_VARARGS, 0}, {"h5a_write", h5a_write, METH_VARARGS, 0}, {"h5a_read", h5a_read, METH_VARARGS, 0}, {"h5a_get_space", h5a_get_space, METH_VARARGS, 0}, {"h5a_get_type", h5a_get_type, METH_VARARGS, 0}, {"h5a_exists_by_name", h5a_exists_by_name, METH_VARARGS, 0}, {"h5a_close", h5a_close, METH_VARARGS, 0}, {"h5_type_from_numpy", h5_type_from_numpy, METH_VARARGS, 0}, {"h5t_get_class", h5t_get_class, METH_VARARGS, 0}, {"h5t_get_size", h5t_get_size, METH_VARARGS, 0}, {"h5t_close", h5t_close, METH_VARARGS, 0}, {"h5s_create", h5s_create, METH_VARARGS, 0}, {"h5s_select_hyperslab", h5s_select_hyperslab, METH_VARARGS, 0}, {"h5s_select_none", h5s_select_none, METH_VARARGS, 0}, {"h5s_get_shape", h5s_get_shape, METH_VARARGS, 0}, {"h5s_close", h5s_close, METH_VARARGS, 0}, {"h5d_open", h5d_open, METH_VARARGS, 0}, {"h5d_create", h5d_create, METH_VARARGS, 0}, {"h5d_write", h5d_write, METH_VARARGS, 0}, {"h5d_read", h5d_read, METH_VARARGS, 0}, {"h5d_get_space", h5d_get_space, METH_VARARGS, 0}, {"h5d_get_type", h5d_get_type, METH_VARARGS, 0}, {"h5d_close", h5d_close, METH_VARARGS, 0}, {"h5p_create", h5p_create, METH_VARARGS, 0}, #ifdef PARALLEL {"h5p_set_fapl_mpio", h5p_set_fapl_mpio, METH_VARARGS, 0}, {"h5p_set_dxpl_mpio", h5p_set_dxpl_mpio, METH_VARARGS, 0}, #endif {"h5p_close", h5p_close, METH_VARARGS, 0}, {"h5o_open", h5o_open, METH_VARARGS, 0}, {"h5o_close", h5o_close, METH_VARARGS, 0}, {"h5i_get_type", h5i_get_type, METH_VARARGS, 0}, {"h5l_get_name_by_idx", h5l_get_name_by_idx, METH_VARARGS, 0}, {0, 0, 0, 0} }; PyMODINIT_FUNC init_gpaw_hdf5(void) { PyObject *m = Py_InitModule("_gpaw_hdf5",functions); // Set some hdf5 constants as attributes PyModule_AddIntConstant(m, "H5T_FLOAT", H5T_FLOAT); PyModule_AddIntConstant(m, "H5T_INTEGER", H5T_INTEGER); PyModule_AddIntConstant(m, "H5T_COMPOUND", H5T_COMPOUND); PyModule_AddIntConstant(m, "H5T_STRING", H5T_STRING); PyModule_AddIntConstant(m, "H5T_ENUM", H5T_ENUM); PyModule_AddIntConstant(m, "H5P_DATASET_XFER", H5P_DATASET_XFER); PyModule_AddIntConstant(m, "H5P_FILE_ACCESS", H5P_FILE_ACCESS); PyModule_AddIntConstant(m, "H5P_DEFAULT", H5P_DEFAULT); PyModule_AddIntConstant(m, "H5I_GROUP", H5I_GROUP); PyModule_AddIntConstant(m, "H5I_DATASET", H5I_DATASET); } #endif gpaw-0.11.0.13004/c/lfc2.c0000664000175000017500000003143512553643466014703 0ustar jensjjensj00000000000000/* Copyright (C) 2010 CAMd * Please see the accompanying LICENSE file for further information. */ #include "extensions.h" #include "spline.h" #include "lfc.h" #include "bmgs/spherical_harmonics.h" PyObject* second_derivative(LFCObject *lfc, PyObject *args) { PyArrayObject* a_G_obj; PyArrayObject* c_Mvv_obj; PyArrayObject* h_cv_obj; PyArrayObject* n_c_obj; PyObject* spline_M_obj; PyArrayObject* beg_c_obj; PyArrayObject* pos_Wc_obj; int q; if (!PyArg_ParseTuple(args, "OOOOOOOi", &a_G_obj, &c_Mvv_obj, &h_cv_obj, &n_c_obj, &spline_M_obj, &beg_c_obj, &pos_Wc_obj, &q)) return NULL; // Copied from derivative member function int nd = PyArray_NDIM(a_G_obj); npy_intp* dims = PyArray_DIMS(a_G_obj); int nx = PyArray_MultiplyList(dims, nd - 3); int nG = PyArray_MultiplyList(dims + nd - 3, 3); int nM = PyArray_DIM(c_Mvv_obj, PyArray_NDIM(c_Mvv_obj) - 2); // These were already present const double* h_cv = (const double*)PyArray_DATA(h_cv_obj); const long* n_c = (const long*)PyArray_DATA(n_c_obj); const double (*pos_Wc)[3] = (const double (*)[3])PyArray_DATA(pos_Wc_obj); long* beg_c = LONGP(beg_c_obj); /////////////////////////////////////////////// const double Y00dv = lfc->dv / sqrt(4.0 * M_PI); if (!lfc->bloch_boundary_conditions) { const double* a_G = (const double*)PyArray_DATA(a_G_obj); double* c_Mvv = (double*)PyArray_DATA(c_Mvv_obj); // Loop over number of x-dimension in a_xG (not relevant yet) for (int x = 0; x < nx; x++) { // JJs old stuff GRID_LOOP_START(lfc, -1) { // In one grid loop iteration, only i2 changes. int i2 = Ga % n_c[2] + beg_c[2]; int i1 = (Ga / n_c[2]) % n_c[1] + beg_c[1]; int i0 = Ga / (n_c[2] * n_c[1]) + beg_c[0]; double xG = h_cv[0] * i0 + h_cv[3] * i1 + h_cv[6] * i2; double yG = h_cv[1] * i0 + h_cv[4] * i1 + h_cv[7] * i2; double zG = h_cv[2] * i0 + h_cv[5] * i1 + h_cv[8] * i2; for (int G = Ga; G < Gb; G++) { for (int i = 0; i < ni; i++) { LFVolume* vol = volume_i + i; int M = vol->M; double* c_mvv = c_Mvv + 9 * M; const bmgsspline* spline = (const bmgsspline*) \ &((const SplineObject*)PyList_GetItem(spline_M_obj, M))->spline; double x = xG - pos_Wc[vol->W][0]; double y = yG - pos_Wc[vol->W][1]; double z = zG - pos_Wc[vol->W][2]; double r2 = x * x + y * y + z * z; double r = sqrt(r2); int bin = r / spline->dr; assert(bin <= spline->nbins); double* s = spline->data + 4 * bin; double u = r - bin * spline->dr; double dfdror; if (bin == 0) dfdror = 2.0 * s[2] + 3.0 * s[3] * r; else dfdror = (s[1] + u * (2.0 * s[2] + u * 3.0 * s[3])) / r; double a = a_G[G] * Y00dv; dfdror *= a; c_mvv[0] += dfdror; c_mvv[4] += dfdror; c_mvv[8] += dfdror; if (r > 1e-15) { double b = ((2.0 * s[2] + 6.0 * s[3] * u) * a - dfdror) / r2; c_mvv[0] += b * x * x; c_mvv[1] += b * x * y; c_mvv[2] += b * x * z; c_mvv[3] += b * y * x; c_mvv[4] += b * y * y; c_mvv[5] += b * y * z; c_mvv[6] += b * z * x; c_mvv[7] += b * z * y; c_mvv[8] += b * z * z; } } xG += h_cv[6]; yG += h_cv[7]; zG += h_cv[8]; } } GRID_LOOP_STOP(lfc, -1); c_Mvv += 9 * nM; a_G += nG; } } else { const complex double* a_G = (const complex double*)PyArray_DATA(a_G_obj); complex double* c_Mvv = (complex double*)PyArray_DATA(c_Mvv_obj); for (int x = 0; x < nx; x++) { GRID_LOOP_START(lfc, q) { // In one grid loop iteration, only i2 changes. int i2 = Ga % n_c[2] + beg_c[2]; int i1 = (Ga / n_c[2]) % n_c[1] + beg_c[1]; int i0 = Ga / (n_c[2] * n_c[1]) + beg_c[0]; double xG = h_cv[0] * i0 + h_cv[3] * i1 + h_cv[6] * i2; double yG = h_cv[1] * i0 + h_cv[4] * i1 + h_cv[7] * i2; double zG = h_cv[2] * i0 + h_cv[5] * i1 + h_cv[8] * i2; for (int G = Ga; G < Gb; G++) { for (int i = 0; i < ni; i++) { LFVolume* vol = volume_i + i; int M = vol->M; complex double* c_mvv = c_Mvv + 9 * M; const bmgsspline* spline = (const bmgsspline*) \ &((const SplineObject*)PyList_GetItem(spline_M_obj, M))->spline; double x = xG - pos_Wc[vol->W][0]; double y = yG - pos_Wc[vol->W][1]; double z = zG - pos_Wc[vol->W][2]; double r2 = x * x + y * y + z * z; double r = sqrt(r2); double dfdror; // use bmgs_get_value_and_derivative instead ??!! int bin = r / spline->dr; assert(bin <= spline->nbins); double u = r - bin * spline->dr; double* s = spline->data + 4 * bin; if (bin == 0) dfdror = 2.0 * s[2] + 3.0 * s[3] * r; else dfdror = (s[1] + u * (2.0 * s[2] + u * 3.0 * s[3])) / r; // phase added here complex double a = a_G[G] * phase_i[i] * Y00dv; // dfdror *= a; c_mvv[0] += a * dfdror; c_mvv[4] += a * dfdror; c_mvv[8] += a * dfdror; if (r > 1e-15) { double b = (2.0 * s[2] + 6.0 * s[3] * u - dfdror) / r2; c_mvv[0] += a * b * x * x; c_mvv[1] += a * b * x * y; c_mvv[2] += a * b * x * z; c_mvv[3] += a * b * y * x; c_mvv[4] += a * b * y * y; c_mvv[5] += a * b * y * z; c_mvv[6] += a * b * z * x; c_mvv[7] += a * b * z * y; c_mvv[8] += a * b * z * z; } } xG += h_cv[6]; yG += h_cv[7]; zG += h_cv[8]; } } GRID_LOOP_STOP(lfc, q); c_Mvv += 9 * nM; a_G += nG; } } Py_RETURN_NONE; } PyObject* add_derivative(LFCObject *lfc, PyObject *args) { // Coefficients for the lfc's PyArrayObject* c_xM_obj; // Array PyArrayObject* a_xG_obj; PyArrayObject* h_cv_obj; PyArrayObject* n_c_obj; PyObject* spline_M_obj; PyArrayObject* beg_c_obj; PyArrayObject* pos_Wc_obj; // Atom index int a; // Cartesian coordinate int v; // k-point index int q; if (!PyArg_ParseTuple(args, "OOOOOOOiii", &c_xM_obj, &a_xG_obj, &h_cv_obj, &n_c_obj, &spline_M_obj, &beg_c_obj, &pos_Wc_obj, &a, &v, &q)) return NULL; // Number of dimensions int nd = PyArray_NDIM(a_xG_obj); // Array with lengths of array dimensions npy_intp* dims = PyArray_DIMS(a_xG_obj); // Number of extra dimensions int nx = PyArray_MultiplyList(dims, nd - 3); // Number of grid points int nG = PyArray_MultiplyList(dims + nd - 3, 3); // Number of lfc's int nM = PyArray_DIM(c_xM_obj, PyArray_NDIM(c_xM_obj) - 1); const double* h_cv = (const double*)PyArray_DATA(h_cv_obj); const long* n_c = (const long*)PyArray_DATA(n_c_obj); const double (*pos_Wc)[3] = (const double (*)[3])PyArray_DATA(pos_Wc_obj); long* beg_c = LONGP(beg_c_obj); if (!lfc->bloch_boundary_conditions) { const double* c_M = (const double*)PyArray_DATA(c_xM_obj); double* a_G = (double*)PyArray_DATA(a_xG_obj); for (int x = 0; x < nx; x++) { GRID_LOOP_START(lfc, -1) { // In one grid loop iteration, only i2 changes. int i2 = Ga % n_c[2] + beg_c[2]; int i1 = (Ga / n_c[2]) % n_c[1] + beg_c[1]; int i0 = Ga / (n_c[2] * n_c[1]) + beg_c[0]; // Grid point position double xG = h_cv[0] * i0 + h_cv[3] * i1 + h_cv[6] * i2; double yG = h_cv[1] * i0 + h_cv[4] * i1 + h_cv[7] * i2; double zG = h_cv[2] * i0 + h_cv[5] * i1 + h_cv[8] * i2; // Loop over grid points in current stride for (int G = Ga; G < Gb; G++) { // Loop over volumes at current grid point for (int i = 0; i < ni; i++) { LFVolume* vol = volume_i + i; int M = vol->M; // Check that the volume belongs to the atom in consideration later int W = vol->W; int nm = vol->nm; int l = (nm - 1) / 2; const bmgsspline* spline = (const bmgsspline*) \ &((const SplineObject*)PyList_GetItem(spline_M_obj, M))->spline; double x = xG - pos_Wc[W][0]; double y = yG - pos_Wc[W][1]; double z = zG - pos_Wc[W][2]; double R_c[] = {x, y, z}; double r2 = x * x + y * y + z * z; double r = sqrt(r2); double f; double dfdr; bmgs_get_value_and_derivative(spline, r, &f, &dfdr); // First contribution: f * d(r^l * Y)/dv double fdrlYdx_m[nm]; if (v == 0) spherical_harmonics_derivative_x(l, f, x, y, z, r2, fdrlYdx_m); else if (v == 1) spherical_harmonics_derivative_y(l, f, x, y, z, r2, fdrlYdx_m); else spherical_harmonics_derivative_z(l, f, x, y, z, r2, fdrlYdx_m); for (int m = 0; m < nm; m++) a_G[G] += fdrlYdx_m[m] * c_M[M + m]; // Second contribution: r^(l-1) * Y * df/dr * R_v if (r > 1e-15) { double rlm1Ydfdr_m[nm]; // r^(l-1) * Y * df/dr double rm1dfdr = 1. / r * dfdr; spherical_harmonics(l, rm1dfdr, x, y, z, r2, rlm1Ydfdr_m); for (int m = 0; m < nm; m++) a_G[G] += rlm1Ydfdr_m[m] * R_c[v] * c_M[M + m]; } } // Update coordinates of current grid point xG += h_cv[6]; yG += h_cv[7]; zG += h_cv[8]; } } GRID_LOOP_STOP(lfc, -1); c_M += nM; a_G += nG; } } else { const double complex* c_M = (const double complex*)PyArray_DATA(c_xM_obj); double complex* a_G = (double complex*)PyArray_DATA(a_xG_obj); for (int x = 0; x < nx; x++) { GRID_LOOP_START(lfc, q) { // In one grid loop iteration, only i2 changes. int i2 = Ga % n_c[2] + beg_c[2]; int i1 = (Ga / n_c[2]) % n_c[1] + beg_c[1]; int i0 = Ga / (n_c[2] * n_c[1]) + beg_c[0]; // Grid point position double xG = h_cv[0] * i0 + h_cv[3] * i1 + h_cv[6] * i2; double yG = h_cv[1] * i0 + h_cv[4] * i1 + h_cv[7] * i2; double zG = h_cv[2] * i0 + h_cv[5] * i1 + h_cv[8] * i2; // Loop over grid points in current stride for (int G = Ga; G < Gb; G++) { // Loop over volumes at current grid point for (int i = 0; i < ni; i++) { // Phase of volume double complex conjphase = conj(phase_i[i]); LFVolume* vol = volume_i + i; int M = vol->M; // Check that the volume belongs to the atom in consideration later int W = vol->W; int nm = vol->nm; int l = (nm - 1) / 2; const bmgsspline* spline = (const bmgsspline*) \ &((const SplineObject*)PyList_GetItem(spline_M_obj, M))->spline; double x = xG - pos_Wc[W][0]; double y = yG - pos_Wc[W][1]; double z = zG - pos_Wc[W][2]; double R_c[] = {x, y, z}; double r2 = x * x + y * y + z * z; double r = sqrt(r2); double f; double dfdr; bmgs_get_value_and_derivative(spline, r, &f, &dfdr); // First contribution: f * d(r^l * Y)/dv double fdrlYdx_m[nm]; if (v == 0) spherical_harmonics_derivative_x(l, f, x, y, z, r2, fdrlYdx_m); else if (v == 1) spherical_harmonics_derivative_y(l, f, x, y, z, r2, fdrlYdx_m); else spherical_harmonics_derivative_z(l, f, x, y, z, r2, fdrlYdx_m); for (int m = 0; m < nm; m++) a_G[G] += fdrlYdx_m[m] * c_M[M + m] * conjphase; // Second contribution: r^(l-1) * Y * df/dr * R_v if (r > 1e-15) { double rlm1Ydfdr_m[nm]; // r^(l-1) * Y * df/dr double rm1dfdr = 1. / r * dfdr; spherical_harmonics(l, rm1dfdr, x, y, z, r2, rlm1Ydfdr_m); for (int m = 0; m < nm; m++) a_G[G] += rlm1Ydfdr_m[m] * R_c[v] * c_M[M + m] * conjphase; } } // Update coordinates of current grid point xG += h_cv[6]; yG += h_cv[7]; zG += h_cv[8]; } } GRID_LOOP_STOP(lfc, q); c_M += nM; a_G += nG; } } Py_RETURN_NONE; } gpaw-0.11.0.13004/c/localized_functions.h0000664000175000017500000000147012553643466020114 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2008 CAMd * Please see the accompanying LICENSE file for further information. */ #include typedef struct { PyObject_HEAD double dv; // volume per grid point int size[3]; // dimensions of big box int start[3]; // corner of small box int size0[3]; // dimensions of small box int ng; // number of grid points in big box int ng0; // number of grid points in small box int nf; // number of localized functions int nfd; // number of derivatives: zero or 3*nf // pointers to size0 arrays: double* f; // localized functions double* fd; // xyz-derivatives of localized functions double* w; // work array for one double or double complex array } LocalizedFunctionsObject; gpaw-0.11.0.13004/c/plt.c0000664000175000017500000000601412553643466014647 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2008 CAMd * Please see the accompanying LICENSE file for further information. */ #include #define PY_ARRAY_UNIQUE_SYMBOL GPAW_ARRAY_API #define NO_IMPORT_ARRAY #include #include "extensions.h" int write_plt_file(char *fname, int nx, int ny, int nz, double x0, double y0, double z0, double dx, double dy, double dz, double *grid); /* write grid to binary plt (gOpenMol) plot file */ PyObject* WritePLT(PyObject *self, PyObject *args) { char* fname; /* file name */ PyArrayObject* ho; /* grid spacings */ PyArrayObject* go; /* grid to write */ if (!PyArg_ParseTuple(args, "sOO", &fname, &ho, &go)) return NULL; /* must be 3D */ if(PyArray_NDIM(go) != 3) return NULL; double* g = DOUBLEP(go); double* h = DOUBLEP(ho); write_plt_file(fname, PyArray_DIM(go, 0), PyArray_DIM(go, 1), PyArray_DIM(go, 2), 0.,0.,0., h[0],h[1],h[2], g); Py_RETURN_NONE; } /* ----------------------------------------------------------------- * write grid to binary plt (gOpenMol) plot file * * x0, dx etc are assumed to be atomic units * the grid is assumed to be in the format: * grid(ix,iy,iz) = grid[ ix + ( iy + iz*ny )*nx ]; * where ix=0..nx-1 etc */ /* stolen from pltfile.c */ #define FWRITE(value , size) { \ Items = fwrite(&value, size , 1L , Output_p);\ if(Items < 1) {\ printf("?ERROR - in writing contour file (*)\n");\ return(1);}} int write_plt_file(char *fname, int nx, int ny, int nz, double x0, double y0, double z0, double dx, double dy, double dz, double *grid) { FILE *Output_p; static int Items; float scale,zmin,zmax,ymin,ymax,xmin,xmax,val; int rank,TypeOfSurface; int ix,iy,iz,indx; double norm,sum,dV; Output_p = fopen(fname,"wb"); /* see http://www.csc.fi/gopenmol/developers/plt_format.phtml */ #define au_A 0.52917725 scale = au_A; /* atomic length in Angstroem */ rank=3; /* always 3 */ FWRITE(rank , sizeof(int)); TypeOfSurface=4; /* arbitrary */ FWRITE(TypeOfSurface , sizeof(int)); FWRITE(nz , sizeof(int)); FWRITE(ny , sizeof(int)); FWRITE(nx , sizeof(int)); zmin= scale * ((float) z0); zmax= scale * ((float) z0+(nz-1)*dz); /* float zmax=(float) z0+nz*dz; */ FWRITE(zmin , sizeof(float)); FWRITE(zmax , sizeof(float)); ymin= scale * ((float) y0); ymax= scale * ((float) y0+(ny-1)*dy); /* float ymax=(float) y0+ny*dy; */ FWRITE(ymin , sizeof(float)); FWRITE(ymax , sizeof(float)); xmin= scale * ((float) x0); xmax= scale * ((float) x0+(nx-1)*dx); /* float xmax=(float) x0+nx*dx; */ FWRITE(xmin , sizeof(float)); FWRITE(xmax , sizeof(float)); indx=0; norm = 0; sum=0; dV=dx*dy*dz; for(iz=0;iz %s written (sum=%g,norm=%g)\n", fname,sum*dV,norm*dV); return 0; } gpaw-0.11.0.13004/c/spline.c0000664000175000017500000000751112553643466015345 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2008 CAMd * Please see the accompanying LICENSE file for further information. */ #include "spline.h" static void spline_dealloc(SplineObject *xp) { bmgs_deletespline(&xp->spline); PyObject_DEL(xp); } static PyObject * spline_get_cutoff(SplineObject *self, PyObject *args) { return Py_BuildValue("d", self->spline.dr * self->spline.nbins); } static PyObject * spline_get_angular_momentum_number(SplineObject *self, PyObject *args) { return Py_BuildValue("i", self->spline.l); } static PyObject * spline_get_value_and_derivative(SplineObject *obj, PyObject *args, PyObject *kwargs) { double r; if (!PyArg_ParseTuple(args, "d", &r)) return NULL; double f; double dfdr; bmgs_get_value_and_derivative(&obj->spline, r, &f, &dfdr); return Py_BuildValue("(dd)", f, dfdr); } // Convert boundary point z-ranges to grid indices for the 2*l+1 boxes static PyObject * spline_get_indices_from_zranges(SplineObject *self, PyObject *args) { PyArrayObject* beg_c_obj; PyArrayObject* end_c_obj; PyArrayObject* G_b_obj; int nm = 2 * self->spline.l + 1; if (!PyArg_ParseTuple(args, "OOO", &beg_c_obj, &end_c_obj, &G_b_obj)) return NULL; long* beg_c = LONGP(beg_c_obj); long* end_c = LONGP(end_c_obj); int ngmax = ((end_c[0] - beg_c[0]) * (end_c[1] - beg_c[1]) * (end_c[2] - beg_c[2])); int* G_B = INTP(G_b_obj); int nB = PyArray_DIMS(G_b_obj)[0]; int ng = 0; for (int b = 0; b < nB; b+=2) ng += G_B[b+1]-G_B[b]; npy_intp gm_dims[2] = {ng, nm}; PyArrayObject* indices_gm_obj = (PyArrayObject*)PyArray_SimpleNew(2, gm_dims, NPY_INT); int* p = INTP(indices_gm_obj); for (int b = 0; b < nB; b += 2) { int Ga = G_B[b], Gb = G_B[b+1]; for (int G = Ga; G < Gb; G++) for (int m = 0; m < nm; m++) *p++ = m * ngmax + G; } // PyObjects created in the C code will be initialized with a refcount // of 1, for which reason we'll have to decref them when done here PyObject* values = Py_BuildValue("(Oii)", indices_gm_obj, ng, nm); Py_DECREF(indices_gm_obj); return values; } static PyMethodDef spline_methods[] = { {"get_cutoff", (PyCFunction)spline_get_cutoff, METH_VARARGS, 0}, {"get_angular_momentum_number", (PyCFunction)spline_get_angular_momentum_number, METH_VARARGS, 0}, {"get_value_and_derivative", (PyCFunction)spline_get_value_and_derivative, METH_VARARGS, 0}, {"get_indices_from_zranges", (PyCFunction)spline_get_indices_from_zranges, METH_VARARGS, 0}, {NULL, NULL, 0, NULL} }; static PyObject * spline_call(SplineObject *obj, PyObject *args, PyObject *kwargs) { double r; if (!PyArg_ParseTuple(args, "d", &r)) return NULL; return Py_BuildValue("d", bmgs_splinevalue(&obj->spline, r)); } PyTypeObject SplineType = { PyVarObject_HEAD_INIT(NULL, 0) "Spline", sizeof(SplineObject), 0, (destructor)spline_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, (ternaryfunc)spline_call, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, "Spline object", 0, 0, 0, 0, 0, 0, spline_methods }; PyObject * NewSplineObject(PyObject *self, PyObject *args) { int l; double rcut; PyArrayObject* farray; if (!PyArg_ParseTuple(args, "idO", &l, &rcut, &farray)) return NULL; SplineObject *spline = PyObject_NEW(SplineObject, &SplineType); if (spline == NULL) return NULL; int nbins = PyArray_DIMS(farray)[0] - 1; double dr = rcut / nbins; spline->spline = bmgs_spline(l, dr, nbins, DOUBLEP(farray)); return (PyObject*)spline; } gpaw-0.11.0.13004/c/symmetry.c0000664000175000017500000001712612553643466015747 0ustar jensjjensj00000000000000/* Copyright (C) 2010-2011 CAMd * Please see the accompanying LICENSE file for further information. */ #include "extensions.h" // // Apply symmetry operation op_cc to a and add result to b: // // =T_ _ // b(U g) += a(g), // // where: // // = _T // U = op_cc[c1, c2] and g = (g0, g1, g2). // c1,c2 // PyObject* symmetrize(PyObject *self, PyObject *args) { PyArrayObject* a_g_obj; PyArrayObject* b_g_obj; PyArrayObject* op_cc_obj; if (!PyArg_ParseTuple(args, "OOO", &a_g_obj, &b_g_obj, &op_cc_obj)) return NULL; const long* C = (const long*)PyArray_DATA(op_cc_obj); int ng0 = PyArray_DIMS(a_g_obj)[0]; int ng1 = PyArray_DIMS(a_g_obj)[1]; int ng2 = PyArray_DIMS(a_g_obj)[2]; const double* a_g = (const double*)PyArray_DATA(a_g_obj); double* b_g = (double*)PyArray_DATA(b_g_obj); for (int g0 = 0; g0 < ng0; g0++) for (int g1 = 0; g1 < ng1; g1++) for (int g2 = 0; g2 < ng2; g2++) { int p0 = ((C[0] * g0 + C[3] * g1 + C[6] * g2) % ng0 + ng0) % ng0; int p1 = ((C[1] * g0 + C[4] * g1 + C[7] * g2) % ng1 + ng1) % ng1; int p2 = ((C[2] * g0 + C[5] * g1 + C[8] * g2) % ng2 + ng2) % ng2; b_g[(p0 * ng1 + p1) * ng2 + p2] += *a_g++; } Py_RETURN_NONE; } PyObject* symmetrize_ft(PyObject *self, PyObject *args) { PyArrayObject* a_g_obj; PyArrayObject* b_g_obj; PyArrayObject* op_cc_obj; PyArrayObject* ft_c_obj; if (!PyArg_ParseTuple(args, "OOOO", &a_g_obj, &b_g_obj, &op_cc_obj, &ft_c_obj)) return NULL; const double* ft = (const double*)PyArray_DATA(ft_c_obj); const long* C = (const long*)PyArray_DATA(op_cc_obj); int ng0 = PyArray_DIMS(a_g_obj)[0]; int ng1 = PyArray_DIMS(a_g_obj)[1]; int ng2 = PyArray_DIMS(a_g_obj)[2]; int ft0 = (int)(ft[0]*ng0); int ft1 = (int)(ft[1]*ng1); int ft2 = (int)(ft[2]*ng2); const double* a_g = (const double*)PyArray_DATA(a_g_obj); double* b_g = (double*)PyArray_DATA(b_g_obj); for (int g0 = 0; g0 < ng0; g0++) for (int g1 = 0; g1 < ng1; g1++) for (int g2 = 0; g2 < ng2; g2++) { int p0 = ((C[0] * g0 + C[3] * g1 + C[6] * g2 - ft0) % ng0 + ng0) % ng0; int p1 = ((C[1] * g0 + C[4] * g1 + C[7] * g2 - ft1) % ng1 + ng1) % ng1; int p2 = ((C[2] * g0 + C[5] * g1 + C[8] * g2 - ft2) % ng2 + ng2) % ng2; b_g[(p0 * ng1 + p1) * ng2 + p2] += *a_g++; } Py_RETURN_NONE; } PyObject* symmetrize_wavefunction(PyObject *self, PyObject *args) { PyArrayObject* a_g_obj; PyArrayObject* b_g_obj; PyArrayObject* op_cc_obj; PyArrayObject* kpt0_obj; PyArrayObject* kpt1_obj; if (!PyArg_ParseTuple(args, "OOOOO", &a_g_obj, &b_g_obj, &op_cc_obj, &kpt0_obj, &kpt1_obj)) return NULL; const long* C = (const long*)PyArray_DATA(op_cc_obj); const double* kpt0 = (const double*) PyArray_DATA(kpt0_obj); const double* kpt1 = (const double*) PyArray_DATA(kpt1_obj); int ng0 = PyArray_DIMS(a_g_obj)[0]; int ng1 = PyArray_DIMS(a_g_obj)[1]; int ng2 = PyArray_DIMS(a_g_obj)[2]; const double complex* a_g = (const double complex*)PyArray_DATA(a_g_obj); double complex* b_g = (double complex*)PyArray_DATA(b_g_obj); for (int g0 = 0; g0 < ng0; g0++) for (int g1 = 0; g1 < ng1; g1++) for (int g2 = 0; g2 < ng2; g2++) { int p0 = ((C[0] * g0 + C[3] * g1 + C[6] * g2) % ng0 + ng0) % ng0; int p1 = ((C[1] * g0 + C[4] * g1 + C[7] * g2) % ng1 + ng1) % ng1; int p2 = ((C[2] * g0 + C[5] * g1 + C[8] * g2) % ng2 + ng2) % ng2; double complex phase = cexp(I * 2. * M_PI * (kpt1[0]/ng0*p0 + kpt1[1]/ng1*p1 + kpt1[2]/ng2*p2 - kpt0[0]/ng0*g0 - kpt0[1]/ng1*g1 - kpt0[2]/ng2*g2)); b_g[(p0 * ng1 + p1) * ng2 + p2] += (*a_g * phase); a_g++; } Py_RETURN_NONE; } PyObject* symmetrize_return_index(PyObject *self, PyObject *args) { PyArrayObject* a_g_obj; PyArrayObject* b_g_obj; PyArrayObject* op_cc_obj; PyArrayObject* kpt0_obj; PyArrayObject* kpt1_obj; if (!PyArg_ParseTuple(args, "OOOOO", &a_g_obj, &b_g_obj, &op_cc_obj, &kpt0_obj, &kpt1_obj)) return NULL; const long* C = (const long*)PyArray_DATA(op_cc_obj); const double* kpt0 = (const double*) PyArray_DATA(kpt0_obj); const double* kpt1 = (const double*) PyArray_DATA(kpt1_obj); int ng0 = PyArray_DIMS(a_g_obj)[0]; int ng1 = PyArray_DIMS(a_g_obj)[1]; int ng2 = PyArray_DIMS(a_g_obj)[2]; unsigned long* a_g = (unsigned long*)PyArray_DATA(a_g_obj); double complex* b_g = (double complex*)PyArray_DATA(b_g_obj); for (int g0 = 0; g0 < ng0; g0++) for (int g1 = 0; g1 < ng1; g1++) for (int g2 = 0; g2 < ng2; g2++) { int p0 = ((C[0] * g0 + C[3] * g1 + C[6] * g2) % ng0 + ng0) % ng0; int p1 = ((C[1] * g0 + C[4] * g1 + C[7] * g2) % ng1 + ng1) % ng1; int p2 = ((C[2] * g0 + C[5] * g1 + C[8] * g2) % ng2 + ng2) % ng2; double complex phase = cexp(I * 2. * M_PI * (kpt1[0]/ng0*p0 + kpt1[1]/ng1*p1 + kpt1[2]/ng2*p2 - kpt0[0]/ng0*g0 - kpt0[1]/ng1*g1 - kpt0[2]/ng2*g2)); *a_g++ = (p0 * ng1 + p1) * ng2 + p2; *b_g++ = phase; } Py_RETURN_NONE; } PyObject* symmetrize_with_index(PyObject *self, PyObject *args) { PyArrayObject* a_g_obj; PyArrayObject* b_g_obj; PyArrayObject* index_g_obj; PyArrayObject* phase_g_obj; if (!PyArg_ParseTuple(args, "OOOO", &a_g_obj, &b_g_obj, &index_g_obj, &phase_g_obj)) return NULL; int ng0 = PyArray_DIMS(a_g_obj)[0]; int ng1 = PyArray_DIMS(a_g_obj)[1]; int ng2 = PyArray_DIMS(a_g_obj)[2]; const unsigned long* index_g = (const unsigned long*)PyArray_DATA(index_g_obj); const double complex* phase_g = (const double complex*)PyArray_DATA(phase_g_obj); const double complex* a_g = (const double complex*)PyArray_DATA(a_g_obj); double complex* b_g = (double complex*)PyArray_DATA(b_g_obj); for (int g0 = 0; g0 < ng0; g0++) for (int g1 = 0; g1 < ng1; g1++) for (int g2 = 0; g2 < ng2; g2++) { b_g[*index_g] += (*a_g * *phase_g); a_g++; phase_g++; index_g++; } Py_RETURN_NONE; } PyObject* map_k_points(PyObject *self, PyObject *args) { PyArrayObject* bzk_kc_obj; PyArrayObject* U_scc_obj; double tol; PyArrayObject* bz2bz_ks_obj; int ka, kb; if (!PyArg_ParseTuple(args, "OOdOii", &bzk_kc_obj, &U_scc_obj, &tol, &bz2bz_ks_obj, &ka, &kb)) return NULL; const long* U_scc = (const long*)PyArray_DATA(U_scc_obj); const double* bzk_kc = (const double*)PyArray_DATA(bzk_kc_obj); long* bz2bz_ks = (long*)PyArray_DATA(bz2bz_ks_obj); int nbzkpts = PyArray_DIMS(bzk_kc_obj)[0]; int nsym = PyArray_DIMS(U_scc_obj)[0]; for (int k1 = ka; k1 < kb; k1++) { const double* q = bzk_kc + k1 * 3; for (int s = 0; s < nsym; s++) { const long* U = U_scc + s * 9; double q0 = U[0] * q[0] + U[1] * q[1] + U[2] * q[2]; double q1 = U[3] * q[0] + U[4] * q[1] + U[5] * q[2]; double q2 = U[6] * q[0] + U[7] * q[1] + U[8] * q[2]; for (int k2 = 0; k2 < nbzkpts; k2++) { double p0 = q0 - bzk_kc[k2 * 3]; if (fabs(p0 - round(p0)) > tol) continue; double p1 = q1 - bzk_kc[k2 * 3 + 1]; if (fabs(p1 - round(p1)) > tol) continue; double p2 = q2 - bzk_kc[k2 * 3 + 2]; if (fabs(p2 - round(p2)) > tol) continue; bz2bz_ks[k1 * nsym + s] = k2; break; } } } Py_RETURN_NONE; } gpaw-0.11.0.13004/c/localized_functions.c0000664000175000017500000003466612553643466020124 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2009 CAMd * Copyright (C) 2005-2008 CSC - IT Center for Science Ltd. * Please see the accompanying LICENSE file for further information. */ #include "spline.h" #include #ifdef PARALLEL # include #else typedef int* MPI_Request; // !!!!!!!??????????? typedef int* MPI_Comm; # define MPI_COMM_NULL 0 # define MPI_Comm_rank(comm, rank) *(rank) = 0 # define MPI_Bcast(buff, count, datatype, root, comm) 0 #endif #include "mympi.h" #include "localized_functions.h" #ifdef GPAW_NO_UNDERSCORE_BLAS # define dgemm_ dgemm # define dgemv_ dgemv #endif int dgemm_(char *transa, char *transb, int *m, int * n, int *k, double *alpha, double *a, int *lda, double *b, int *ldb, double *beta, double *c, int *ldc); int dgemv_(char *trans, int *m, int * n, double *alpha, double *a, int *lda, double *x, int *incx, double *beta, double *y, int *incy); static void localized_functions_dealloc(LocalizedFunctionsObject *self) { free(self->f); free(self->w); PyObject_DEL(self); } static PyObject * localized_functions_integrate(LocalizedFunctionsObject *self, PyObject *args) { PyArrayObject* aa; PyArrayObject* bb; if (!PyArg_ParseTuple(args, "OO", &aa, &bb)) return NULL; const double* a = DOUBLEP(aa); double* b = DOUBLEP(bb); int na = 1; for (int d = 0; d < PyArray_NDIM(aa) - 3; d++) na *= PyArray_DIM(aa, d); int nf = self->nf; double* f = self->f; double* w = self->w; int ng = self->ng; int ng0 = self->ng0; if (PyArray_DESCR(aa)->type_num == NPY_DOUBLE) for (int n = 0; n < na; n++) { bmgs_cut(a, self->size, self->start, w, self->size0); double zero = 0.0; int inc = 1; dgemv_("t", &ng0, &nf, &self->dv, f, &ng0, w, &inc, &zero, b, &inc); a += ng; b += nf; } else for (int n = 0; n < na; n++) { bmgs_cutz((const double_complex*)a, self->size, self->start, (double_complex*)w, self->size0); double zero = 0.0; int inc = 2; dgemm_("n", "n", &inc, &nf, &ng0, &self->dv, w, &inc, f, &ng0, &zero, b, &inc); a += 2 * ng; b += 2 * nf; } Py_RETURN_NONE; } static PyObject * localized_functions_derivative( LocalizedFunctionsObject *self, PyObject *args) { PyArrayObject* aa; PyArrayObject* bb; if (!PyArg_ParseTuple(args, "OO", &aa, &bb)) return NULL; const double* a = DOUBLEP(aa); double* b = DOUBLEP(bb); int na = 1; for (int d = 0; d < PyArray_NDIM(aa) - 3; d++) na *= PyArray_DIM(aa, d); int nf = self->nfd; double* f = self->fd; double* w = self->w; int ng = self->ng; int ng0 = self->ng0; if (PyArray_DESCR(aa)->type_num == NPY_DOUBLE) for (int n = 0; n < na; n++) { bmgs_cut(a, self->size, self->start, w, self->size0); double zero = 0.0; int inc = 1; dgemv_("t", &ng0, &nf, &self->dv, f, &ng0, w, &inc, &zero, b, &inc); a += ng; b += nf; } else for (int n = 0; n < na; n++) { bmgs_cutz((const double_complex*)a, self->size, self->start, (double_complex*)w, self->size0); double zero = 0.0; int inc = 2; dgemm_("n", "n", &inc, &nf, &ng0, &self->dv, w, &inc, f, &ng0, &zero, b, &inc); a += 2 * ng; b += 2 * nf; } Py_RETURN_NONE; } static PyObject * localized_functions_add(LocalizedFunctionsObject *self, PyObject *args) { PyArrayObject* cc; PyArrayObject* aa; if (!PyArg_ParseTuple(args, "OO", &cc, &aa)) return NULL; double* c = DOUBLEP(cc); double* a = DOUBLEP(aa); int na = 1; for (int d = 0; d < PyArray_NDIM(aa) - 3; d++) na *= PyArray_DIM(aa, d); int ng = self->ng; int ng0 = self->ng0; int nf = self->nf; double* f = self->f; double* w = self->w; if (PyArray_DESCR(aa)->type_num == NPY_DOUBLE) for (int n = 0; n < na; n++) { double zero = 0.0; double one = 1.0; int inc = 1; dgemv_("n", &ng0, &nf, &one, f, &ng0, c, &inc, &zero, w, &inc); bmgs_pastep(w, self->size0, a, self->size, self->start); a += ng; c += nf; } else for (int n = 0; n < na; n++) { double zero = 0.0; double one = 1.0; int inc = 2; dgemm_("n", "t", &inc, &ng0, &nf, &one, c, &inc, f, &ng0, &zero, w, &inc); bmgs_pastepz((const double_complex*)w, self->size0, (double_complex*)a, self->size, self->start); a += 2 * ng; c += 2 * nf; } Py_RETURN_NONE; } static PyObject * localized_functions_add_density(LocalizedFunctionsObject* self, PyObject *args) { PyArrayObject* dd; PyArrayObject* oo; if (!PyArg_ParseTuple(args, "OO", &dd, &oo)) return NULL; const double* o = DOUBLEP(oo); double* d = DOUBLEP(dd); int nf = self->nf; int ng0 = self->ng0; const double* f = self->f; double* w = self->w; memset(w, 0, ng0 * sizeof(double)); for (int i = 0; i < nf; i++) for (int n = 0; n < ng0; n++) { double g = *f++; w[n] += o[i] * g * g; } bmgs_pastep(w, self->size0, d, self->size, self->start); Py_RETURN_NONE; } static PyObject * localized_functions_add_density2(LocalizedFunctionsObject* self, PyObject *args) { PyArrayObject* dd; // density array to be added to PyArrayObject* oo; // density matrix if (!PyArg_ParseTuple(args, "OO", &dd, &oo)) return NULL; const double* o = DOUBLEP(oo); double* d = DOUBLEP(dd); int nf = self->nf; int ng0 = self->ng0; const double* f = self->f; double* w = self->w; memset(w, 0, ng0 * sizeof(double)); int p = 0; // compressed ii index double F = 0.0; // integrated value for (int i = 0; i < nf; i++) { for (int j = i; j < nf; j++) { for (int n = 0; n < ng0; n++) { double tmp = o[p] * f[n + i * ng0] * f[n + j * ng0]; F += tmp; w[n] += tmp; } p++; } } bmgs_pastep(w, self->size0, d, self->size, self->start); //Py_RETURN_NONE; return Py_BuildValue("d", F * self->dv); } static PyObject * localized_functions_norm(LocalizedFunctionsObject* self, PyObject *args) { PyArrayObject* I_obj; if (!PyArg_ParseTuple(args, "O", &I_obj)) return NULL; double (*II)[4] = (double (*)[4])DOUBLEP(I_obj); const double* f = self->f; for (int i = 0; i < self->nf; i++) { double F = 0.0; for (int n = 0; n < self->ng0; n++) F += f[n]; II[i][0] += F * self->dv; f += self->ng0; } if (self->nfd > 0) { const double* fd = self->fd; for (int i = 0; i < self->nf; i++) for (int c = 0; c < 3; c++) { double F = 0.0; for (int n = 0; n < self->ng0; n++) F += fd[n]; II[i][c + 1] += F * self->dv; fd += self->ng0; } } Py_RETURN_NONE; } static PyObject * localized_functions_normalize(LocalizedFunctionsObject* self, PyObject *args) { double I0; PyArrayObject* I_obj; if (!PyArg_ParseTuple(args, "dO", &I0, &I_obj)) return NULL; double (*II)[4] = (double (*)[4])DOUBLEP(I_obj); double* f = self->f; double s = I0 / II[0][0]; // Scale spherically symmetric function so that the integral // becomes exactly I0: for (int n = 0; n < self->ng0; n++) f[n] *= s; // Adjust all other functions (l > 0) so that they integrate to zero: for (int i = 1; i < self->nf; i++) { double *g = f + i * self->ng0; double a = -II[i][0] / I0; for (int n = 0; n < self->ng0; n++) g[n] += a * f[n]; } if (self->nfd > 0) { // Adjust derivatives: double* fd = self->fd; for (int n = 0; n < 3 * self->ng0; n++) fd[n] *= s; for (int c = 0; c < 3; c++) { double sd = II[0][c + 1] / II[0][0]; for (int n = 0; n < self->ng0; n++) fd[n + c * self->ng0] -= f[n] * sd ; } for (int i = 1; i < self->nf; i++) { double *gd = fd + 3 * i * self->ng0; double a = -II[i][0] / I0; for (int n = 0; n < 3 * self->ng0; n++) gd[n] += a * fd[n]; for (int c = 0; c < 3; c++) { double sd = II[i][c + 1] / I0; for (int n = 0; n < self->ng0; n++) gd[n + c * self->ng0] -= f[n] * sd ; } } } Py_RETURN_NONE; } static PyObject * get_functions(LocalizedFunctionsObject* self, PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; npy_intp dims[4] = {self->nf, self->size0[0], self->size0[1], self->size0[2]}; PyArrayObject* functions = (PyArrayObject*)PyArray_SimpleNew(4, dims, NPY_DOUBLE); memcpy(PyArray_DATA(functions), self->f, self->nf * self->ng0 * sizeof(double)); return (PyObject*)functions; } static PyObject * set_corner(LocalizedFunctionsObject* self, PyObject *args) { PyArrayObject* start_c_obj; if (!PyArg_ParseTuple(args, "O", &start_c_obj)) return NULL; double *start_c = DOUBLEP(start_c_obj); for (int c = 0; c < 3; c++) self->start[c] = start_c[c]; Py_RETURN_NONE; } #ifdef PARALLEL static PyObject * localized_functions_broadcast(LocalizedFunctionsObject* self, PyObject *args) { PyObject* comm_obj; int root; if (!PyArg_ParseTuple(args, "Oi", &comm_obj, &root)) return NULL; MPI_Comm comm = ((MPIObject*)comm_obj)->comm; MPI_Bcast(self->f, self->ng0 * (self->nf + self->nfd), MPI_DOUBLE, root, comm); Py_RETURN_NONE; } #endif static PyMethodDef localized_functions_methods[] = { {"integrate", (PyCFunction)localized_functions_integrate, METH_VARARGS, 0}, {"derivative", (PyCFunction)localized_functions_derivative, METH_VARARGS, 0}, {"add", (PyCFunction)localized_functions_add, METH_VARARGS, 0}, {"add_density", (PyCFunction)localized_functions_add_density, METH_VARARGS, 0}, {"add_density2", (PyCFunction)localized_functions_add_density2, METH_VARARGS, 0}, {"norm", (PyCFunction)localized_functions_norm, METH_VARARGS, 0}, {"normalize", (PyCFunction)localized_functions_normalize, METH_VARARGS, 0}, {"get_functions", (PyCFunction)get_functions, METH_VARARGS, 0}, {"set_corner", (PyCFunction)set_corner, METH_VARARGS, 0}, #ifdef PARALLEL {"broadcast", (PyCFunction)localized_functions_broadcast, METH_VARARGS, 0}, #endif {NULL, NULL, 0, NULL} }; PyTypeObject LocalizedFunctionsType = { PyVarObject_HEAD_INIT(NULL, 0) "LocalizedFunctions", sizeof(LocalizedFunctionsObject), 0, (destructor)localized_functions_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, "LF object", 0, 0, 0, 0, 0, 0, localized_functions_methods }; PyObject * NewLocalizedFunctionsObject(PyObject *obj, PyObject *args) { PyObject* radials; PyArrayObject* size0_array; PyArrayObject* size_array; PyArrayObject* start_array; PyArrayObject* h_array; PyArrayObject* C_array; int real; int forces; int compute; if (!PyArg_ParseTuple(args, "OOOOOOiii", &radials, &size0_array, &size_array, &start_array, &h_array, &C_array, &real, &forces, &compute)) return NULL; LocalizedFunctionsObject *self = PyObject_NEW(LocalizedFunctionsObject, &LocalizedFunctionsType); if (self == NULL) return NULL; const long* size0 = LONGP(size0_array); const long* size = LONGP(size_array); const long* start = LONGP(start_array); const double* h = DOUBLEP(h_array); const double* C = DOUBLEP(C_array); self->dv = h[0] * h[1] * h[2]; int ng = size[0] * size[1] * size[2]; int ng0 = size0[0] * size0[1] * size0[2]; self->ng = ng; self->ng0 = ng0; for (int i = 0; i < 3; i++) { self->size0[i] = size0[i]; self->size[i] = size[i]; self->start[i] = start[i]; } int nf = 0; int nfd = 0; int nbins = 0; double dr = 0.0; for (int j = 0; j < PyList_Size(radials); j++) { const bmgsspline* spline = &(((SplineObject*)PyList_GetItem(radials, j))->spline); int l = spline->l; assert(l <= 4); if (j == 0) { nbins = spline->nbins; dr = spline->dr; } else { assert(spline->nbins == nbins); assert(spline->dr == dr); } nf += (2 * l + 1); } if (forces) nfd = 3 * nf; self->nf = nf; self->nfd = nfd; self->f = GPAW_MALLOC(double, (nf + nfd) * ng0); if (forces) self->fd = self->f + nf * ng0; else self->fd = 0; int ndouble = (real ? 1 : 2); self->w = GPAW_MALLOC(double, ng0 * ndouble); if (compute) { int* bin = GPAW_MALLOC(int, ng0); double* d = GPAW_MALLOC(double, ng0); double* f0 = GPAW_MALLOC(double, ng0); double* fd0 = 0; if (forces) fd0 = GPAW_MALLOC(double, ng0); double* a = self->f; double* ad = self->fd; for (int j = 0; j < PyList_Size(radials); j++) { const bmgsspline* spline = &(((SplineObject*)PyList_GetItem(radials, j))->spline); if (j == 0) bmgs_radial1(spline, self->size0, C, h, bin, d); bmgs_radial2(spline, self->size0, bin, d, f0, fd0); int l = spline->l; for (int m = -l; m <= l; m++) { bmgs_radial3(spline, m, self->size0, C, h, f0, a); a += ng0; } if (forces) for (int m = -l; m <= l; m++) for (int c = 0; c < 3; c++) { bmgs_radiald3(spline, m, c, self->size0, C, h, f0, fd0, ad); ad += ng0; } } if (forces) free(fd0); free(f0); free(d); free(bin); } return (PyObject*)self; } gpaw-0.11.0.13004/c/spline.h0000664000175000017500000000034312553643466015346 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Please see the accompanying LICENSE file for further information. */ #include "extensions.h" #include "bmgs/bmgs.h" typedef struct { PyObject_HEAD bmgsspline spline; } SplineObject; gpaw-0.11.0.13004/c/fftw.c0000664000175000017500000000302512553643466015015 0ustar jensjjensj00000000000000#ifdef GPAW_WITH_FFTW #include #define PY_ARRAY_UNIQUE_SYMBOL GPAW_ARRAY_API #define NO_IMPORT_ARRAY #include #include /* Create plan and return pointer to plan as a string */ PyObject * FFTWPlan(PyObject *self, PyObject *args) { PyArrayObject* in; PyArrayObject* out; int sign; unsigned int flags; if (!PyArg_ParseTuple(args, "OOiI", &in, &out, &sign, &flags)) return NULL; fftw_plan* plan = (fftw_plan*)malloc(sizeof(fftw_plan)); if (in->descr->type_num == PyArray_DOUBLE) *plan = fftw_plan_dft_r2c(in->nd, in->dimensions, (double*)in->data, (double (*)[2])out->data, flags); else if (out->descr->type_num == PyArray_DOUBLE) *plan = fftw_plan_dft_c2r(in->nd, out->dimensions, (double (*)[2])in->data, (double*)out->data, flags); else *plan = fftw_plan_dft(in->nd, out->dimensions, (double (*)[2])in->data, (double (*)[2])out->data, sign, flags); return Py_BuildValue("s#", plan, sizeof(fftw_plan*)); } PyObject * FFTWExecute(PyObject *self, PyObject *args) { fftw_plan* plan; int n; if (!PyArg_ParseTuple(args, "s#", &plan, &n)) return NULL; fftw_execute(*plan); Py_RETURN_NONE; } PyObject * FFTWDestroy(PyObject *self, PyObject *args) { fftw_plan* plan; int n; if (!PyArg_ParseTuple(args, "s#", &plan, &n)) return NULL; fftw_destroy_plan(*plan); free(plan); Py_RETURN_NONE; } #endif // GPAW_WITH_FFTW gpaw-0.11.0.13004/c/_gpaw.c0000664000175000017500000003770712553643466015162 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2009 CAMd * Copyright (C) 2007-2010 CSC - IT Center for Science Ltd. * Please see the accompanying LICENSE file for further information. */ #include #define PY_ARRAY_UNIQUE_SYMBOL GPAW_ARRAY_API #include #ifdef GPAW_WITH_HDF5 PyMODINIT_FUNC init_gpaw_hdf5(void); #endif #ifdef GPAW_HPM PyObject* ibm_hpm_start(PyObject *self, PyObject *args); PyObject* ibm_hpm_stop(PyObject *self, PyObject *args); PyObject* ibm_mpi_start(PyObject *self); PyObject* ibm_mpi_stop(PyObject *self); #endif #ifdef CRAYPAT #include PyObject* craypat_region_begin(PyObject *self, PyObject *args); PyObject* craypat_region_end(PyObject *self, PyObject *args); #endif PyObject* symmetrize(PyObject *self, PyObject *args); PyObject* symmetrize_ft(PyObject *self, PyObject *args); PyObject* symmetrize_wavefunction(PyObject *self, PyObject *args); PyObject* symmetrize_return_index(PyObject *self, PyObject *args); PyObject* symmetrize_with_index(PyObject *self, PyObject *args); PyObject* map_k_points(PyObject *self, PyObject *args); PyObject* scal(PyObject *self, PyObject *args); PyObject* mmm(PyObject *self, PyObject *args); PyObject* gemm(PyObject *self, PyObject *args); PyObject* gemv(PyObject *self, PyObject *args); PyObject* axpy(PyObject *self, PyObject *args); PyObject* czher(PyObject *self, PyObject *args); PyObject* rk(PyObject *self, PyObject *args); PyObject* r2k(PyObject *self, PyObject *args); PyObject* dotc(PyObject *self, PyObject *args); PyObject* dotu(PyObject *self, PyObject *args); PyObject* multi_dotu(PyObject *self, PyObject *args); PyObject* multi_axpy(PyObject *self, PyObject *args); PyObject* diagonalize(PyObject *self, PyObject *args); PyObject* diagonalize_mr3(PyObject *self, PyObject *args); PyObject* general_diagonalize(PyObject *self, PyObject *args); PyObject* inverse_cholesky(PyObject *self, PyObject *args); PyObject* inverse_symmetric(PyObject *self, PyObject *args); PyObject* inverse_general(PyObject *self, PyObject *args); PyObject* linear_solve_band(PyObject *self, PyObject *args); PyObject* linear_solve_tridiag(PyObject *self, PyObject *args); PyObject* right_eigenvectors(PyObject *self, PyObject *args); PyObject* NewLocalizedFunctionsObject(PyObject *self, PyObject *args); PyObject* NewOperatorObject(PyObject *self, PyObject *args); PyObject* NewWOperatorObject(PyObject *self, PyObject *args); PyObject* NewSplineObject(PyObject *self, PyObject *args); PyObject* NewTransformerObject(PyObject *self, PyObject *args); PyObject* pc_potential(PyObject *self, PyObject *args); PyObject* pc_potential_value(PyObject *self, PyObject *args); PyObject* heap_mallinfo(PyObject *self); PyObject* elementwise_multiply_add(PyObject *self, PyObject *args); PyObject* utilities_gaussian_wave(PyObject *self, PyObject *args); PyObject* utilities_vdot(PyObject *self, PyObject *args); PyObject* utilities_vdot_self(PyObject *self, PyObject *args); PyObject* errorfunction(PyObject *self, PyObject *args); PyObject* cerf(PyObject *self, PyObject *args); PyObject* pack(PyObject *self, PyObject *args); PyObject* unpack(PyObject *self, PyObject *args); PyObject* unpack_complex(PyObject *self, PyObject *args); PyObject* hartree(PyObject *self, PyObject *args); PyObject* localize(PyObject *self, PyObject *args); PyObject* NewXCFunctionalObject(PyObject *self, PyObject *args); PyObject* NewlxcXCFunctionalObject(PyObject *self, PyObject *args); PyObject* lxcXCFuncNum(PyObject *self, PyObject *args); PyObject* exterior_electron_density_region(PyObject *self, PyObject *args); PyObject* plane_wave_grid(PyObject *self, PyObject *args); PyObject* overlap(PyObject *self, PyObject *args); PyObject* vdw(PyObject *self, PyObject *args); PyObject* vdw2(PyObject *self, PyObject *args); PyObject* spherical_harmonics(PyObject *self, PyObject *args); PyObject* spline_to_grid(PyObject *self, PyObject *args); PyObject* NewLFCObject(PyObject *self, PyObject *args); #if defined(GPAW_WITH_SL) && defined(PARALLEL) PyObject* new_blacs_context(PyObject *self, PyObject *args); PyObject* get_blacs_gridinfo(PyObject* self, PyObject *args); PyObject* get_blacs_local_shape(PyObject* self, PyObject *args); PyObject* blacs_destroy(PyObject *self, PyObject *args); PyObject* scalapack_set(PyObject *self, PyObject *args); PyObject* scalapack_redist(PyObject *self, PyObject *args); PyObject* scalapack_diagonalize_dc(PyObject *self, PyObject *args); PyObject* scalapack_diagonalize_ex(PyObject *self, PyObject *args); #ifdef GPAW_MR3 PyObject* scalapack_diagonalize_mr3(PyObject *self, PyObject *args); #endif PyObject* scalapack_general_diagonalize_dc(PyObject *self, PyObject *args); PyObject* scalapack_general_diagonalize_ex(PyObject *self, PyObject *args); #ifdef GPAW_MR3 PyObject* scalapack_general_diagonalize_mr3(PyObject *self, PyObject *args); #endif PyObject* scalapack_inverse_cholesky(PyObject *self, PyObject *args); PyObject* scalapack_inverse(PyObject *self, PyObject *args); PyObject* scalapack_solve(PyObject *self, PyObject *args); PyObject* pblas_tran(PyObject *self, PyObject *args); PyObject* pblas_gemm(PyObject *self, PyObject *args); PyObject* pblas_hemm(PyObject *self, PyObject *args); PyObject* pblas_gemv(PyObject *self, PyObject *args); PyObject* pblas_r2k(PyObject *self, PyObject *args); PyObject* pblas_rk(PyObject *self, PyObject *args); #endif #ifdef GPAW_PAPI PyObject* papi_mem_info(PyObject *self, PyObject *args); #endif // Moving least squares interpolation PyObject* mlsqr(PyObject *self, PyObject *args); static PyMethodDef functions[] = { {"symmetrize", symmetrize, METH_VARARGS, 0}, {"symmetrize_ft", symmetrize_ft, METH_VARARGS, 0}, {"symmetrize_wavefunction", symmetrize_wavefunction, METH_VARARGS, 0}, {"symmetrize_return_index", symmetrize_return_index, METH_VARARGS, 0}, {"symmetrize_with_index", symmetrize_with_index, METH_VARARGS, 0}, {"map_k_points", map_k_points, METH_VARARGS, 0}, {"scal", scal, METH_VARARGS, 0}, {"mmm", mmm, METH_VARARGS, 0}, {"gemm", gemm, METH_VARARGS, 0}, {"gemv", gemv, METH_VARARGS, 0}, {"axpy", axpy, METH_VARARGS, 0}, {"czher", czher, METH_VARARGS, 0}, {"rk", rk, METH_VARARGS, 0}, {"r2k", r2k, METH_VARARGS, 0}, {"dotc", dotc, METH_VARARGS, 0}, {"dotu", dotu, METH_VARARGS, 0}, {"multi_dotu", multi_dotu, METH_VARARGS, 0}, {"multi_axpy", multi_axpy, METH_VARARGS, 0}, {"diagonalize", diagonalize, METH_VARARGS, 0}, {"diagonalize_mr3", diagonalize_mr3, METH_VARARGS, 0}, {"general_diagonalize", general_diagonalize, METH_VARARGS, 0}, {"inverse_cholesky", inverse_cholesky, METH_VARARGS, 0}, {"inverse_symmetric", inverse_symmetric, METH_VARARGS, 0}, {"inverse_general", inverse_general, METH_VARARGS, 0}, {"linear_solve_band", linear_solve_band, METH_VARARGS, 0}, {"linear_solve_tridiag", linear_solve_tridiag, METH_VARARGS, 0}, {"right_eigenvectors", right_eigenvectors, METH_VARARGS, 0}, {"LocalizedFunctions", NewLocalizedFunctionsObject, METH_VARARGS, 0}, {"Operator", NewOperatorObject, METH_VARARGS, 0}, {"WOperator", NewWOperatorObject, METH_VARARGS, 0}, {"Spline", NewSplineObject, METH_VARARGS, 0}, {"Transformer", NewTransformerObject, METH_VARARGS, 0}, {"heap_mallinfo", (PyCFunction) heap_mallinfo, METH_NOARGS, 0}, {"elementwise_multiply_add", elementwise_multiply_add, METH_VARARGS, 0}, {"utilities_gaussian_wave", utilities_gaussian_wave, METH_VARARGS, 0}, {"utilities_vdot", utilities_vdot, METH_VARARGS, 0}, {"utilities_vdot_self", utilities_vdot_self, METH_VARARGS, 0}, {"eed_region", exterior_electron_density_region, METH_VARARGS, 0}, {"plane_wave_grid", plane_wave_grid, METH_VARARGS, 0}, {"erf", errorfunction, METH_VARARGS, 0}, {"cerf", cerf, METH_VARARGS, 0}, {"pack", pack, METH_VARARGS, 0}, {"unpack", unpack, METH_VARARGS, 0}, {"unpack_complex", unpack_complex, METH_VARARGS, 0}, {"hartree", hartree, METH_VARARGS, 0}, {"localize", localize, METH_VARARGS, 0}, {"XCFunctional", NewXCFunctionalObject, METH_VARARGS, 0}, /* {"MGGAFunctional", NewMGGAFunctionalObject, METH_VARARGS, 0},*/ {"lxcXCFunctional", NewlxcXCFunctionalObject, METH_VARARGS, 0}, {"lxcXCFuncNum", lxcXCFuncNum, METH_VARARGS, 0}, {"overlap", overlap, METH_VARARGS, 0}, {"vdw", vdw, METH_VARARGS, 0}, {"vdw2", vdw2, METH_VARARGS, 0}, {"spherical_harmonics", spherical_harmonics, METH_VARARGS, 0}, {"pc_potential", pc_potential, METH_VARARGS, 0}, {"pc_potential_value", pc_potential_value, METH_VARARGS, 0}, {"spline_to_grid", spline_to_grid, METH_VARARGS, 0}, {"LFC", NewLFCObject, METH_VARARGS, 0}, /* {"calculate_potential_matrix", calculate_potential_matrix, METH_VARARGS, 0}, {"construct_density", construct_density, METH_VARARGS, 0}, {"construct_density1", construct_density1, METH_VARARGS, 0}, */ #if defined(GPAW_WITH_SL) && defined(PARALLEL) {"new_blacs_context", new_blacs_context, METH_VARARGS, NULL}, {"get_blacs_gridinfo", get_blacs_gridinfo, METH_VARARGS, NULL}, {"get_blacs_local_shape", get_blacs_local_shape, METH_VARARGS, NULL}, {"blacs_destroy", blacs_destroy, METH_VARARGS, 0}, {"scalapack_set", scalapack_set, METH_VARARGS, 0}, {"scalapack_redist", scalapack_redist, METH_VARARGS, 0}, {"scalapack_diagonalize_dc", scalapack_diagonalize_dc, METH_VARARGS, 0}, {"scalapack_diagonalize_ex", scalapack_diagonalize_ex, METH_VARARGS, 0}, #ifdef GPAW_MR3 {"scalapack_diagonalize_mr3", scalapack_diagonalize_mr3, METH_VARARGS, 0}, #endif // GPAW_MR3 {"scalapack_general_diagonalize_dc", scalapack_general_diagonalize_dc, METH_VARARGS, 0}, {"scalapack_general_diagonalize_ex", scalapack_general_diagonalize_ex, METH_VARARGS, 0}, #ifdef GPAW_MR3 {"scalapack_general_diagonalize_mr3", scalapack_general_diagonalize_mr3, METH_VARARGS, 0}, #endif // GPAW_MR3 {"scalapack_inverse_cholesky", scalapack_inverse_cholesky, METH_VARARGS, 0}, {"scalapack_inverse", scalapack_inverse, METH_VARARGS, 0}, {"scalapack_solve", scalapack_solve, METH_VARARGS, 0}, {"pblas_tran", pblas_tran, METH_VARARGS, 0}, {"pblas_gemm", pblas_gemm, METH_VARARGS, 0}, {"pblas_hemm", pblas_hemm, METH_VARARGS, 0}, {"pblas_gemv", pblas_gemv, METH_VARARGS, 0}, {"pblas_r2k", pblas_r2k, METH_VARARGS, 0}, {"pblas_rk", pblas_rk, METH_VARARGS, 0}, #endif // GPAW_WITH_SL && PARALLEL #ifdef GPAW_HPM {"hpm_start", ibm_hpm_start, METH_VARARGS, 0}, {"hpm_stop", ibm_hpm_stop, METH_VARARGS, 0}, {"mpi_start", (PyCFunction) ibm_mpi_start, METH_NOARGS, 0}, {"mpi_stop", (PyCFunction) ibm_mpi_stop, METH_NOARGS, 0}, #endif // GPAW_HPM #ifdef CRAYPAT {"craypat_region_begin", craypat_region_begin, METH_VARARGS, 0}, {"craypat_region_end", craypat_region_end, METH_VARARGS, 0}, #endif // CRAYPAT #ifdef GPAW_PAPI {"papi_mem_info", papi_mem_info, METH_VARARGS, 0}, #endif // GPAW_PAPI {"mlsqr", mlsqr, METH_VARARGS, 0}, {0, 0, 0, 0} }; #ifdef PARALLEL extern PyTypeObject MPIType; extern PyTypeObject GPAW_MPI_Request_type; #endif extern PyTypeObject LFCType; extern PyTypeObject LocalizedFunctionsType; extern PyTypeObject OperatorType; extern PyTypeObject WOperatorType; extern PyTypeObject SplineType; extern PyTypeObject TransformerType; extern PyTypeObject XCFunctionalType; extern PyTypeObject lxcXCFunctionalType; #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "_gpaw", "C-extension for GPAW", -1, functions, NULL, NULL, NULL, NULL }; #endif #ifndef GPAW_INTERPRETER static PyObject* moduleinit(void) { #ifdef PARALLEL if (PyType_Ready(&MPIType) < 0) return NULL; if (PyType_Ready(&GPAW_MPI_Request_type) < 0) return NULL; #endif if (PyType_Ready(&LFCType) < 0) return NULL; if (PyType_Ready(&LocalizedFunctionsType) < 0) return NULL; if (PyType_Ready(&OperatorType) < 0) return NULL; if (PyType_Ready(&WOperatorType) < 0) return NULL; if (PyType_Ready(&SplineType) < 0) return NULL; if (PyType_Ready(&TransformerType) < 0) return NULL; if (PyType_Ready(&XCFunctionalType) < 0) return NULL; if (PyType_Ready(&lxcXCFunctionalType) < 0) return NULL; #if PY_MAJOR_VERSION >= 3 PyObject* m = PyModule_Create(&moduledef); #else PyObject* m = Py_InitModule3("_gpaw", functions, "C-extension for GPAW\n\n...\n"); #endif if (m == NULL) return NULL; #ifdef PARALLEL Py_INCREF(&MPIType); Py_INCREF(&GPAW_MPI_Request_type); PyModule_AddObject(m, "Communicator", (PyObject *)&MPIType); #endif Py_INCREF(&LFCType); Py_INCREF(&LocalizedFunctionsType); Py_INCREF(&OperatorType); Py_INCREF(&WOperatorType); Py_INCREF(&SplineType); Py_INCREF(&TransformerType); Py_INCREF(&XCFunctionalType); Py_INCREF(&lxcXCFunctionalType); import_array1(NULL); return m; } #if PY_MAJOR_VERSION >= 3 PyMODINIT_FUNC PyInit__gpaw(void) { return moduleinit(); } #else PyMODINIT_FUNC init_gpaw(void) { moduleinit(); } #endif #else // ifndef GPAW_INTERPRETER extern DL_EXPORT(int) Py_Main(int, char **); // Performance measurement int gpaw_perf_init(); void gpaw_perf_finalize(); #include int main(int argc, char **argv) { int status; #ifdef CRAYPAT PAT_region_begin(1, "C-Initializations"); #endif #ifndef GPAW_OMP MPI_Init(&argc, &argv); #else int granted; MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &granted); if(granted != MPI_THREAD_MULTIPLE) exit(1); #endif // GPAW_OMP // Get initial timing double t0 = MPI_Wtime(); #ifdef GPAW_PERFORMANCE_REPORT gpaw_perf_init(); #endif #ifdef GPAW_MPI_MAP int tag = 99; int myid, numprocs, i, procnamesize; char procname[MPI_MAX_PROCESSOR_NAME]; MPI_Comm_size(MPI_COMM_WORLD, &numprocs ); MPI_Comm_rank(MPI_COMM_WORLD, &myid ); MPI_Get_processor_name(procname, &procnamesize); if (myid > 0) { MPI_Send(&procnamesize, 1, MPI_INT, 0, tag, MPI_COMM_WORLD); MPI_Send(procname, procnamesize, MPI_CHAR, 0, tag, MPI_COMM_WORLD); } else { printf("MPI_COMM_SIZE is %d \n", numprocs); printf("%s \n", procname); for (i = 1; i < numprocs; ++i) { MPI_Recv(&procnamesize, 1, MPI_INT, i, tag, MPI_COMM_WORLD, MPI_STATUS_IGNORE); MPI_Recv(procname, procnamesize, MPI_CHAR, i, tag, MPI_COMM_WORLD, MPI_STATUS_IGNORE); printf("%s \n", procname); } } #endif // GPAW_MPI_MAP #ifdef GPAW_MPI_DEBUG // Default Errhandler is MPI_ERRORS_ARE_FATAL MPI_Errhandler_set(MPI_COMM_WORLD, MPI_ERRORS_RETURN); #endif // Progname seems to be needed in some circumstances to resolve // correct default sys.path Py_SetProgramName(argv[0]); Py_Initialize(); if (PyType_Ready(&MPIType) < 0) return -1; if (PyType_Ready(&LFCType) < 0) return -1; if (PyType_Ready(&LocalizedFunctionsType) < 0) return -1; if (PyType_Ready(&OperatorType) < 0) return -1; if (PyType_Ready(&WOperatorType) < 0) return -1; if (PyType_Ready(&SplineType) < 0) return -1; if (PyType_Ready(&TransformerType) < 0) return -1; if (PyType_Ready(&XCFunctionalType) < 0) return -1; if (PyType_Ready(&lxcXCFunctionalType) < 0) return -1; PyObject* m = Py_InitModule3("_gpaw", functions, "C-extension for GPAW\n\n...\n"); if (m == NULL) return -1; Py_INCREF(&MPIType); PyModule_AddObject(m, "Communicator", (PyObject *)&MPIType); // Add initial time to _gpaw object PyModule_AddObject(m, "time0", PyFloat_FromDouble(t0)); Py_INCREF(&LFCType); Py_INCREF(&LocalizedFunctionsType); Py_INCREF(&OperatorType); Py_INCREF(&WOperatorType); Py_INCREF(&SplineType); Py_INCREF(&TransformerType); Py_INCREF(&XCFunctionalType); Py_INCREF(&lxcXCFunctionalType); #ifdef GPAW_WITH_HDF5 init_gpaw_hdf5(); #endif import_array1(-1); MPI_Barrier(MPI_COMM_WORLD); #ifdef CRAYPAT PAT_region_end(1); PAT_region_begin(2, "all other"); #endif status = Py_Main(argc, argv); #ifdef CRAYPAT PAT_region_end(2); #endif #ifdef GPAW_PERFORMANCE_REPORT gpaw_perf_finalize(); #endif MPI_Finalize(); return status; } #endif // GPAW_INTERPRETER gpaw-0.11.0.13004/c/transformers.c0000664000175000017500000001560712553643466016605 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2008 CAMd * Copyright (C) 2005-2009 CSC - IT Center for Science Ltd. * Please see the accompanying LICENSE file for further information. */ #include #include #define PY_ARRAY_UNIQUE_SYMBOL GPAW_ARRAY_API #define NO_IMPORT_ARRAY #include #include "extensions.h" #include "bc.h" #include "mympi.h" #include "bmgs/bmgs.h" #ifdef GPAW_ASYNC #define GPAW_ASYNC_D 3 #else #define GPAW_ASYNC_D 1 #endif typedef struct { PyObject_HEAD boundary_conditions* bc; int p; int k; bool interpolate; MPI_Request recvreq[2]; MPI_Request sendreq[2]; int skip[3][2]; int size_out[3]; /* Size of the output grid */ } TransformerObject; static void Transformer_dealloc(TransformerObject *self) { free(self->bc); PyObject_DEL(self); } struct transapply_args{ int thread_id; TransformerObject *self; int ng; int ng2; int nin; int nthds; const double* in; double* out; int real; const double_complex* ph; }; void *transapply_worker(void *threadarg) { struct transapply_args *args = (struct transapply_args *) threadarg; boundary_conditions* bc = args->self->bc; TransformerObject *self = args->self; double* sendbuf = GPAW_MALLOC(double, bc->maxsend * GPAW_ASYNC_D); double* recvbuf = GPAW_MALLOC(double, bc->maxrecv * GPAW_ASYNC_D); double* buf = GPAW_MALLOC(double, args->ng2); int buf2size = args->ng2; if (self->interpolate) buf2size *= 16; else buf2size /= 2; double* buf2 = GPAW_MALLOC(double, buf2size); MPI_Request recvreq[2 * GPAW_ASYNC_D]; MPI_Request sendreq[2 * GPAW_ASYNC_D]; int chunksize = args->nin / args->nthds; if (!chunksize) chunksize = 1; int nstart = args->thread_id * chunksize; if (nstart >= args->nin) return NULL; int nend = nstart + chunksize; if (nend > args->nin) nend = args->nin; int out_ng = bc->ndouble * self->size_out[0] * self->size_out[1] * self->size_out[2]; for (int n = nstart; n < nend; n++) { const double* in = args->in + n * args->ng; double* out = args->out + n * out_ng; for (int i = 0; i < 3; i++) { bc_unpack1(bc, in, buf, i, recvreq, sendreq, recvbuf, sendbuf, args->ph + 2 * i, args->thread_id, 1); bc_unpack2(bc, buf, i, recvreq, sendreq, recvbuf, 1); } if (args->real) { if (self->interpolate) bmgs_interpolate(self->k, self->skip, buf, bc->size2, out, buf2); else bmgs_restrict(self->k, buf, bc->size2, out, buf2); } else { if (self->interpolate) bmgs_interpolatez(self->k, self->skip, (double_complex*)buf, bc->size2, (double_complex*)out, (double_complex*) buf2); else bmgs_restrictz(self->k, (double_complex*) buf, bc->size2, (double_complex*)out, (double_complex*) buf2); } } free(buf2); free(buf); free(recvbuf); free(sendbuf); return NULL; } static PyObject* Transformer_apply(TransformerObject *self, PyObject *args) { PyArrayObject* input; PyArrayObject* output; PyArrayObject* phases = 0; if (!PyArg_ParseTuple(args, "OO|O", &input, &output, &phases)) return NULL; int nin = 1; if (PyArray_NDIM(input) == 4) nin = PyArray_DIMS(input)[0]; boundary_conditions* bc = self->bc; const int* size1 = bc->size1; const int* size2 = bc->size2; int ng = bc->ndouble * size1[0] * size1[1] * size1[2]; int ng2 = bc->ndouble * size2[0] * size2[1] * size2[2]; const double* in = DOUBLEP(input); double* out = DOUBLEP(output); bool real = (PyArray_DESCR(input)->type_num == NPY_DOUBLE); const double_complex* ph = (real ? 0 : COMPLEXP(phases)); int nthds = 1; #ifdef GPAW_OMP if (getenv("OMP_NUM_THREADS") != NULL) nthds = atoi(getenv("OMP_NUM_THREADS")); #endif struct transapply_args *wargs = GPAW_MALLOC(struct transapply_args, nthds); pthread_t *thds = GPAW_MALLOC(pthread_t, nthds); for(int i=0; i < nthds; i++) { (wargs+i)->thread_id = i; (wargs+i)->nthds = nthds; (wargs+i)->self = self; (wargs+i)->ng = ng; (wargs+i)->ng2 = ng2; (wargs+i)->nin = nin; (wargs+i)->in = in; (wargs+i)->out = out; (wargs+i)->real = real; (wargs+i)->ph = ph; } #ifdef GPAW_OMP for(int i=1; i < nthds; i++) pthread_create(thds + i, NULL, transapply_worker, (void*) (wargs+i)); #endif transapply_worker(wargs); #ifdef GPAW_OMP for(int i=1; i < nthds; i++) pthread_join(*(thds+i), NULL); #endif free(wargs); free(thds); Py_RETURN_NONE; } static PyObject * Transformer_get_async_sizes(TransformerObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; #ifdef GPAW_ASYNC return Py_BuildValue("(ii)", 1, GPAW_ASYNC_D); #else return Py_BuildValue("(ii)", 0, GPAW_ASYNC_D); #endif } static PyMethodDef Transformer_Methods[] = { {"apply", (PyCFunction)Transformer_apply, METH_VARARGS, NULL}, {"get_async_sizes", (PyCFunction)Transformer_get_async_sizes, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL} }; PyTypeObject TransformerType = { PyVarObject_HEAD_INIT(NULL, 0) "Transformer", sizeof(TransformerObject), 0, (destructor)Transformer_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, "Transformer object", 0, 0, 0, 0, 0, 0, Transformer_Methods }; PyObject * NewTransformerObject(PyObject *obj, PyObject *args) { PyArrayObject* size_in; PyArrayObject* size_out; int k; PyArrayObject* paddings; PyArrayObject* npaddings; PyArrayObject* skip; PyArrayObject* neighbors; int real; PyObject* comm_obj; int interpolate; if (!PyArg_ParseTuple(args, "OOiOOOOiOi", &size_in, &size_out, &k, &paddings, &npaddings, &skip, &neighbors, &real, &comm_obj, &interpolate)) return NULL; TransformerObject* self = PyObject_NEW(TransformerObject, &TransformerType); if (self == NULL) return NULL; self->k = k; self->interpolate = interpolate; MPI_Comm comm = MPI_COMM_NULL; if (comm_obj != Py_None) comm = ((MPIObject*)comm_obj)->comm; const long (*nb)[2] = (const long (*)[2])LONGP(neighbors); const long (*pad)[2] = (const long (*)[2])LONGP(paddings); const long (*npad)[2] = (const long (*)[2])LONGP(npaddings); const long (*skp)[2] = (const long (*)[2])LONGP(skip); self->bc = bc_init(LONGP(size_in), pad, npad, nb, comm, real, 0); for (int c = 0; c < 3; c++) self->size_out[c] = LONGP(size_out)[c]; for (int c = 0; c < 3; c++) for (int d = 0; d < 2; d++) self->skip[c][d] = (int)skp[c][d]; return (PyObject*)self; } gpaw-0.11.0.13004/c/wigner_seitz.c0000664000175000017500000000306312553643466016562 0ustar jensjjensj00000000000000#include "extensions.h" #include double distance(double *a, double *b); // returns the squared distance between a 3d double vector // and a 3d int vector double distance3d2_di(double *a, int *b) { double sum = 0; double diff; for (int c = 0; c < 3; c++) { diff = a[c] - (double)b[c]; sum += diff*diff; } return sum; } PyObject *exterior_electron_density_region(PyObject *self, PyObject *args) { PyArrayObject* ai; PyArrayObject* aatom_c; PyArrayObject* beg_c; PyArrayObject* end_c; PyArrayObject* hh_c; PyArrayObject* vdWrad; if (!PyArg_ParseTuple(args, "OOOOOO", &ai, &aatom_c, &beg_c, &end_c, &hh_c, &vdWrad)) return NULL; long *aindex = LONGP(ai); int natoms = PyArray_DIM(aatom_c, 0); double *atom_c = DOUBLEP(aatom_c); long *beg = LONGP(beg_c); long *end = LONGP(end_c); double *h_c = DOUBLEP(hh_c); double *vdWradius = DOUBLEP(vdWrad); int n[3], ij; double pos[3]; for (int c = 0; c < 3; c++) { n[c] = end[c] - beg[c]; } // loop over all points for (int i = 0; i < n[0]; i++) { pos[0] = (beg[0] + i) * h_c[0]; for (int j = 0; j < n[1]; j++) { pos[1] = (beg[1] + j) * h_c[1]; ij = (i*n[1] + j)*n[2]; for (int k = 0; k < n[2]; k++) { pos[2] = (beg[2] + k) * h_c[2]; aindex[ij + k] = (long) 1; /* assume outside the structure */ // loop over all atoms for (int a=0; a < natoms; a++) { double d = distance(atom_c + a*3, pos); if (d < vdWradius[a]) { aindex[ij + k] = (long) 0; /* this is inside */ a = natoms; } } } } } Py_RETURN_NONE; } gpaw-0.11.0.13004/c/point_charges.c0000664000175000017500000000426712553643466016705 0ustar jensjjensj00000000000000#include "extensions.h" #include double distance(double *a, double *b); double pc_pot_value(double *pos, // position [Bohr] double *pc_pos, // PC positions [Bohr] double *pc_q, // PC charges [atomic units] int npc, // # of PCs double v_max) // max. potential // loop over all point charges and add their potentials { double V = 0.0; for (int a=0; a < npc; a++) { double d = distance(pc_pos + a*3, pos); double v = v_max; if(d != 0.0) { v = MIN(v_max, 1. / d); } V -= pc_q[a] * v; } return V; } PyObject *pc_potential_value(PyObject *self, PyObject *args) { PyArrayObject* posi_c; PyArrayObject* pci_nc; PyArrayObject* qi_n; if (!PyArg_ParseTuple(args, "OOO", &posi_c, &pci_nc, &qi_n)) return NULL; double *pos_c = DOUBLEP(posi_c); int npc = PyArray_DIMS(pci_nc)[0]; double *pc_nc = DOUBLEP(pci_nc); double *q_n = DOUBLEP(qi_n); return Py_BuildValue("d", pc_pot_value(pos_c, pc_nc, q_n, npc, 1.e+99)); } PyObject *pc_potential(PyObject *self, PyObject *args) { PyArrayObject* poti; PyArrayObject* pci_nc; PyArrayObject* beg_c; PyArrayObject* end_c; PyArrayObject* hh_c; PyArrayObject* qi_n; if (!PyArg_ParseTuple(args, "OOOOOO", &poti, &pci_nc, &qi_n, &beg_c, &end_c, &hh_c)) return NULL; double *pot = DOUBLEP(poti); int npc = PyArray_DIMS(pci_nc)[0]; double *pc_nc = DOUBLEP(pci_nc); long *beg = LONGP(beg_c); long *end = LONGP(end_c); double *h_c = DOUBLEP(hh_c); double *q_n = DOUBLEP(qi_n); // cutoff to avoid singularities // = Coulomb integral over a ball of the same volume // as the volume element of the grid double dV = h_c[0] * h_c[1] * h_c[2]; double v_max = 2.417988 / cbrt(dV); // double v_max = .5; int n[3], ij; double pos[3]; for (int c = 0; c < 3; c++) { n[c] = end[c] - beg[c]; } // loop over all points for (int i = 0; i < n[0]; i++) { pos[0] = (beg[0] + i) * h_c[0]; for (int j = 0; j < n[1]; j++) { pos[1] = (beg[1] + j) * h_c[1]; ij = (i*n[1] + j)*n[2]; for (int k = 0; k < n[2]; k++) { pos[2] = (beg[2] + k) * h_c[2]; pot[ij + k] = pc_pot_value(pos, pc_nc, q_n, npc, v_max); } } } Py_RETURN_NONE; } gpaw-0.11.0.13004/c/lfc.h0000664000175000017500000001061012553643466014616 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2009 CAMd * Please see the accompanying LICENSE file for further information. */ #ifndef LFC_H #define LFC_H #include typedef struct { const double* A_gm; // function values int nm; // number of functions (2*l+1) int M; // global number of first function int W; // volume number } LFVolume; typedef struct { PyObject_HEAD double dv; // volume per grid point int nW; // number of volumes int nB; // number of boundary points double* work_gm; // work space LFVolume* volume_W; // pointers to volumes LFVolume* volume_i; // pointers to volumes at current grid point int* G_B; // boundary grid points int* W_B; // volume numbers int* i_W; // mapping from all volumes to current volumes int* ngm_W; // number of grid points per volume bool bloch_boundary_conditions; // Gamma-point calculation? complex double* phase_kW; // phase factors: exp(ik.R) complex double* phase_i; // phase factors for current volumes } LFCObject; #define GRID_LOOP_START(lfc, k) \ { \ int* G_B = lfc->G_B; \ int* W_B = lfc->W_B; \ int* i_W = lfc->i_W; \ complex double* phase_i = lfc->phase_i; \ LFVolume* volume_i = lfc->volume_i; \ LFVolume* volume_W = lfc->volume_W; \ double complex* phase_W = lfc->phase_kW + k * lfc->nW; \ int Ga = 0; \ int ni = 0; \ for (int B = 0; B < lfc->nB; B++) \ { \ int Gb = G_B[B]; \ int nG = Gb - Ga; \ if (nG > 0) \ { #define GRID_LOOP_STOP(lfc, k) \ for (int i = 0; i < ni; i++) \ volume_i[i].A_gm += nG * volume_i[i].nm; \ } \ int Wnew = W_B[B]; \ if (Wnew >= 0) \ { \ /* Entering new sphere: */ \ volume_i[ni] = volume_W[Wnew]; \ if (k >= 0) \ phase_i[ni] = phase_W[Wnew]; \ i_W[Wnew] = ni; \ ni++; \ } \ else \ { \ /* Leaving sphere: */ \ int Wold = -1 - Wnew; \ int iold = i_W[Wold]; \ volume_W[Wold].A_gm = volume_i[iold].A_gm; \ ni--; \ volume_i[iold] = volume_i[ni]; \ if (k >= 0) \ phase_i[iold] = phase_i[ni]; \ int Wlast = volume_i[iold].W; \ i_W[Wlast] = iold; \ } \ Ga = Gb; \ } \ for (int W = 0; W < lfc->nW; W++) \ volume_W[W].A_gm -= lfc->ngm_W[W]; \ } #endif gpaw-0.11.0.13004/c/woperators.c0000664000175000017500000004453612553643466016270 0ustar jensjjensj00000000000000/* This file (woperators.c) is a modified copy of operators.c * with added support for nonlocal operator weights. * The original copyright note of operators.c follows: * Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2008 CAMd * Copyright (C) 2005 CSC - IT Center for Science Ltd. * Please see the accompanying LICENSE file for further information. */ //*** The apply operator and some associate structors are imple- ***// //*** mented in two version: a original version and a speciel ***// //*** OpenMP version. By default the original version will ***// //*** be used, but it's possible to use the OpenMP version ***// //*** by compiling gpaw with the macro GPAW_OMP defined and ***// //*** and the compile/link option "-fopenmp". ***// //*** Author of the optimized OpenMP code: ***// //*** Mads R. B. Kristensen - madsbk@diku.dk ***// #include #define PY_ARRAY_UNIQUE_SYMBOL GPAW_ARRAY_API #define NO_IMPORT_ARRAY #include #include #include #include "extensions.h" #include "bc.h" #include "mympi.h" #ifdef GPAW_ASYNC #define GPAW_ASYNC3 3 #define GPAW_ASYNC2 2 #else #define GPAW_ASYNC3 1 #define GPAW_ASYNC2 1 #endif typedef struct { PyObject_HEAD int nweights; const double** weights; bmgsstencil* stencils; boundary_conditions* bc; MPI_Request recvreq[2]; MPI_Request sendreq[2]; } WOperatorObject; static void WOperator_dealloc(WOperatorObject *self) { free(self->bc); for (int i = 0; i < self->nweights; i++) { free(self->stencils[i].coefs); free(self->stencils[i].offsets); } free(self->stencils); free(self->weights); PyObject_DEL(self); } static PyObject * WOperator_relax(WOperatorObject *self, PyObject *args) { int relax_method; PyArrayObject* func; PyArrayObject* source; int nrelax; double w = 1.0; if (!PyArg_ParseTuple(args, "iOOi|d", &relax_method, &func, &source, &nrelax, &w)) return NULL; const boundary_conditions* bc = self->bc; double* fun = DOUBLEP(func); const double* src = DOUBLEP(source); const double_complex* ph; const int* size2 = bc->size2; double* buf = (double*) GPAW_MALLOC(double, size2[0] * size2[1] * size2[2] * bc->ndouble); double* sendbuf = (double*) GPAW_MALLOC(double, bc->maxsend); double* recvbuf = (double*) GPAW_MALLOC(double, bc->maxrecv); const double** weights = (const double**) GPAW_MALLOC(double*, self->nweights); ph = 0; for (int n = 0; n < nrelax; n++ ) { for (int i = 0; i < 3; i++) { bc_unpack1(bc, fun, buf, i, self->recvreq, self->sendreq, recvbuf, sendbuf, ph + 2 * i, 0, 1); bc_unpack2(bc, buf, i, self->recvreq, self->sendreq, recvbuf, 1); } for (int iw = 0; iw < self->nweights; iw++) weights[iw] = self->weights[iw]; bmgs_wrelax(relax_method, self->nweights, self->stencils, weights, buf, fun, src, w); } free(weights); free(recvbuf); free(sendbuf); free(buf); Py_RETURN_NONE; } struct wapply_args{ int thread_id; WOperatorObject *self; int ng; int ng2; int nin; int nthds; int chunksize; int chunkinc; const double* in; double* out; int real; const double_complex* ph; }; //Plain worker void *wapply_worker(void *threadarg) { struct wapply_args *args = (struct wapply_args *) threadarg; boundary_conditions* bc = args->self->bc; MPI_Request recvreq[2]; MPI_Request sendreq[2]; int chunksize = args->nin / args->nthds; if (!chunksize) chunksize = 1; int nstart = args->thread_id * chunksize; if (nstart >= args->nin) return NULL; int nend = nstart + chunksize; if (nend > args->nin) nend = args->nin; if (chunksize > args->chunksize) chunksize = args->chunksize; double* sendbuf = (double*) GPAW_MALLOC(double, bc->maxsend * args->chunksize); double* recvbuf = (double*) GPAW_MALLOC(double, bc->maxrecv * args->chunksize); double* buf = (double*) GPAW_MALLOC(double, args->ng2 * args->chunksize); const double** weights = (const double**) GPAW_MALLOC(double*, args->self->nweights); for (int n = nstart; n < nend; n += chunksize) { if (n + chunksize >= nend && chunksize > 1) chunksize = nend - n; const double* in = args->in + n * args->ng; double* out = args->out + n * args->ng; for (int i = 0; i < 3; i++) { bc_unpack1(bc, in, buf, i, recvreq, sendreq, recvbuf, sendbuf, args->ph + 2 * i, args->thread_id, chunksize); bc_unpack2(bc, buf, i, recvreq, sendreq, recvbuf, chunksize); } for (int m = 0; m < chunksize; m++) { for (int iw = 0; iw < args->self->nweights; iw++) weights[iw] = args->self->weights[iw] + m * args->ng2; if (args->real) bmgs_wfd(args->self->nweights, args->self->stencils, weights, buf + m * args->ng2, out + m * args->ng); else bmgs_wfdz(args->self->nweights, args->self->stencils, weights, (const double_complex*) (buf + m * args->ng2), (double_complex*) (out + m * args->ng)); } } free(weights); free(buf); free(recvbuf); free(sendbuf); return NULL; } //Async worker void *wapply_worker_cfd_async(void *threadarg) { struct wapply_args *args = (struct wapply_args *) threadarg; boundary_conditions* bc = args->self->bc; MPI_Request recvreq[2 * GPAW_ASYNC3]; MPI_Request sendreq[2 * GPAW_ASYNC3]; int chunksize = args->nin / args->nthds; if (!chunksize) chunksize = 1; int nstart = args->thread_id * chunksize; if (nstart >= args->nin) return NULL; int nend = nstart + chunksize; if (nend > args->nin) nend = args->nin; if (chunksize > args->chunksize) chunksize = args->chunksize; double* sendbuf = (double*) GPAW_MALLOC(double, bc->maxsend * GPAW_ASYNC3 * args->chunksize); double* recvbuf = (double*) GPAW_MALLOC(double, bc->maxrecv * GPAW_ASYNC3 * args->chunksize); double* buf = (double*) GPAW_MALLOC(double, args->ng2 * args->chunksize); const double** weights = (const double**) GPAW_MALLOC(double*, args->self->nweights); for (int n = nstart; n < nend; n += chunksize) { if (n + chunksize >= nend && chunksize > 1) chunksize = nend - n; const double* in = args->in + n * args->ng; double* out = args->out + n * args->ng; for (int i = 0; i < 3; i++) { bc_unpack1(bc, in, buf, i, recvreq + i * 2, sendreq + i * 2, recvbuf + i * bc->maxrecv * chunksize, sendbuf + i * bc->maxsend * chunksize, args->ph + 2 * i, args->thread_id, chunksize); } for (int i = 0; i < 3; i++) { bc_unpack2(bc, buf, i, recvreq + i * 2, sendreq + i * 2, recvbuf + i * bc->maxrecv * chunksize, chunksize); } for (int m = 0; m < chunksize; m++) { for (int iw = 0; iw < args->self->nweights; iw++) weights[iw] = args->self->weights[iw] + m * args->ng2; if (args->real) bmgs_wfd(args->self->nweights, args->self->stencils, weights, buf + m * args->ng2, out + m * args->ng); else bmgs_wfdz(args->self->nweights, args->self->stencils, weights, (const double_complex*) (buf + m * args->ng2), (double_complex*) (out + m * args->ng)); } } free(weights); free(buf); free(recvbuf); free(sendbuf); return NULL; } //Double buffering async worker void *wapply_worker_cfd(void *threadarg) { struct wapply_args *args = (struct wapply_args *) threadarg; boundary_conditions* bc = args->self->bc; MPI_Request recvreq[2 * GPAW_ASYNC3 * GPAW_ASYNC2]; MPI_Request sendreq[2 * GPAW_ASYNC3 * GPAW_ASYNC2]; int chunksize = args->nin / args->nthds; if (!chunksize) chunksize = 1; int nstart = args->thread_id * chunksize; if (nstart >= args->nin) return NULL; int nend = nstart + chunksize; if (nend > args->nin) nend = args->nin; if (chunksize > args->chunksize) chunksize = args->chunksize; int chunk = args->chunkinc; if (chunk > chunksize); chunk = chunksize; double* sendbuf = (double*) GPAW_MALLOC(double, bc->maxsend * args->chunksize * GPAW_ASYNC3 * GPAW_ASYNC2); double* recvbuf = (double*) GPAW_MALLOC(double, bc->maxrecv * args->chunksize * GPAW_ASYNC3 * GPAW_ASYNC2); double* buf = (double*) GPAW_MALLOC(double, args->ng2 * args->chunksize * GPAW_ASYNC2); const double** weights = (const double**) GPAW_MALLOC(double*, args->self->nweights); int odd = 0; const double* in = args->in + nstart * args->ng; double* out; for (int i = 0; i < 3; i++) bc_unpack1(bc, in, buf + odd * args->ng2 * chunksize, i, recvreq + odd * 2 + i * 4, sendreq + odd * 2 + i * 4, recvbuf + odd * bc->maxrecv * chunksize + i * bc->maxrecv * chunksize * GPAW_ASYNC2, sendbuf + odd * bc->maxsend * chunksize + i * bc->maxsend * chunksize * GPAW_ASYNC2, args->ph + 2 * i, args->thread_id, chunk); odd = odd ^ 1; int last_chunk = chunk; for (int n = nstart+chunk; n < nend; n += chunk) { last_chunk += args->chunkinc; if (last_chunk > chunksize); last_chunk = chunksize; if (n + last_chunk >= nend && last_chunk > 1) last_chunk = nend - n; in = args->in + n * args->ng; out = args->out + (n-chunk) * args->ng; for (int i = 0; i < 3; i++) { bc_unpack1(bc, in, buf + odd * args->ng2 * chunksize, i, recvreq + odd * 2 + i * 4, sendreq + odd * 2 + i * 4, recvbuf + odd * bc->maxrecv * chunksize + i * bc->maxrecv * chunksize * GPAW_ASYNC2, sendbuf + odd * bc->maxsend * chunksize + i * bc->maxsend * chunksize * GPAW_ASYNC2, args->ph + 2 * i, args->thread_id, last_chunk); } odd = odd ^ 1; for (int i = 0; i < 3; i++) { bc_unpack2(bc, buf + odd * args->ng2 * chunksize, i, recvreq + odd * 2 + i * 4, sendreq + odd * 2 + i * 4, recvbuf + odd * bc->maxrecv * chunksize + i * bc->maxrecv * chunksize * GPAW_ASYNC2, chunk); } for (int m = 0; m < chunk; m++) { for (int iw = 0; iw < args->self->nweights; iw++) weights[iw] = args->self->weights[iw] + m * args->ng2 + odd * args->ng2 * chunksize; if (args->real) bmgs_wfd(args->self->nweights, args->self->stencils, weights, buf + m * args->ng2 + odd * args->ng2 * chunksize, out + m * args->ng); else bmgs_wfdz(args->self->nweights, args->self->stencils, weights, (const double_complex*) (buf + m * args->ng2 + odd * args->ng2 * chunksize), (double_complex*) (out + m * args->ng)); } chunk = last_chunk; } odd = odd ^ 1; out = args->out + (nend-last_chunk) * args->ng; for (int i = 0; i < 3; i++) { bc_unpack2(bc, buf + odd * args->ng2 * chunksize, i, recvreq + odd * 2 + i * 4, sendreq + odd * 2 + i * 4, recvbuf + odd * bc->maxrecv * chunksize + i * bc->maxrecv * chunksize * GPAW_ASYNC2, last_chunk); } for (int m = 0; m < last_chunk; m++) { for (int iw = 0; iw < args->self->nweights; iw++) weights[iw] = args->self->weights[iw] + m * args->ng2 + odd * args->ng2 * chunksize; if (args->real) bmgs_wfd(args->self->nweights, args->self->stencils, weights, buf + m * args->ng2 + odd * args->ng2 * chunksize, out + m * args->ng); else bmgs_wfdz(args->self->nweights, args->self->stencils, weights, (const double_complex*) (buf + m * args->ng2 + odd * args->ng2 * chunksize), (double_complex*) (out + m * args->ng)); } free(weights); free(buf); free(recvbuf); free(sendbuf); return NULL; } static PyObject * WOperator_apply(WOperatorObject *self, PyObject *args) { PyArrayObject* input; PyArrayObject* output; PyArrayObject* phases = 0; if (!PyArg_ParseTuple(args, "OO|O", &input, &output, &phases)) return NULL; int nin = 1; if (PyArray_NDIM(input) == 4) nin = PyArray_DIMS(input)[0]; boundary_conditions* bc = self->bc; const int* size1 = bc->size1; const int* size2 = bc->size2; int ng = bc->ndouble * size1[0] * size1[1] * size1[2]; int ng2 = bc->ndouble * size2[0] * size2[1] * size2[2]; const double* in = DOUBLEP(input); double* out = DOUBLEP(output); const double_complex* ph; bool real = (PyArray_DESCR(input)->type_num == NPY_DOUBLE); if (real) ph = 0; else ph = COMPLEXP(phases); int chunksize = 1; if (getenv("GPAW_CHUNK_SIZE") != NULL) chunksize = atoi(getenv("GPAW_CHUNK_SIZE")); int chunkinc = chunksize; if (getenv("GPAW_CHUNK_INC") != NULL) chunkinc = atoi(getenv("GPAW_CHUNK_INC")); int nthds = 1; #ifdef GPAW_OMP if (getenv("OMP_NUM_THREADS") != NULL) nthds = atoi(getenv("OMP_NUM_THREADS")); #endif struct wapply_args *wargs = GPAW_MALLOC(struct wapply_args, nthds); pthread_t *thds = GPAW_MALLOC(pthread_t, nthds); for(int i=0; i < nthds; i++) { (wargs+i)->thread_id = i; (wargs+i)->nthds = nthds; (wargs+i)->chunksize = chunksize; (wargs+i)->chunkinc = chunkinc; (wargs+i)->self = self; (wargs+i)->ng = ng; (wargs+i)->ng2 = ng2; (wargs+i)->nin = nin; (wargs+i)->in = in; (wargs+i)->out = out; (wargs+i)->real = real; (wargs+i)->ph = ph; } #ifndef GPAW_ASYNC if (1) #else if (bc->cfd == 0) #endif { #ifdef GPAW_OMP for(int i=1; i < nthds; i++) pthread_create(thds + i, NULL, wapply_worker, (void*) (wargs+i)); #endif wapply_worker(wargs); } else { #ifdef GPAW_OMP for(int i=1; i < nthds; i++) pthread_create(thds + i, NULL, wapply_worker_cfd, (void*) (wargs+i)); #endif wapply_worker_cfd(wargs); } #ifdef GPAW_OMP for(int i=1; i < nthds; i++) pthread_join(*(thds+i), NULL); #endif free(wargs); free(thds); Py_RETURN_NONE; } static PyObject * WOperator_get_diagonal_element(WOperatorObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; const double** weights = (const double**) GPAW_MALLOC(double*, self->nweights); for (int iw = 0; iw < self->nweights; iw++) weights[iw] = self->weights[iw]; const int n0 = self->stencils[0].n[0]; const int n1 = self->stencils[0].n[1]; const int n2 = self->stencils[0].n[2]; double d = 0.0; for (int i0 = 0; i0 < n0; i0++) { for (int i1 = 0; i1 < n1; i1++) { for (int i2 = 0; i2 < n2; i2++) { double coef = 0.0; for (int iw = 0; iw < self->nweights; iw++) { coef += weights[iw][0] * self->stencils[iw].coefs[0]; weights[iw]++; } if (coef < 0) coef = -coef; if (coef > d) d = coef; } } } free(weights); return Py_BuildValue("d", d); } static PyObject * WOperator_get_async_sizes(WOperatorObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; #ifdef GPAW_ASYNC return Py_BuildValue("(iii)", 1, GPAW_ASYNC2, GPAW_ASYNC3); #else return Py_BuildValue("(iii)", 0, GPAW_ASYNC2, GPAW_ASYNC3); #endif } static PyMethodDef WOperator_Methods[] = { {"apply", (PyCFunction)WOperator_apply, METH_VARARGS, NULL}, {"relax", (PyCFunction)WOperator_relax, METH_VARARGS, NULL}, {"get_diagonal_element", (PyCFunction)WOperator_get_diagonal_element, METH_VARARGS, NULL}, {"get_async_sizes", (PyCFunction)WOperator_get_async_sizes, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL} }; PyTypeObject WOperatorType = { PyVarObject_HEAD_INIT(NULL, 0) "WOperator", sizeof(WOperatorObject), 0, (destructor)WOperator_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, "FDW-operator object", 0, 0, 0, 0, 0, 0, WOperator_Methods }; PyObject* NewWOperatorObject(PyObject *obj, PyObject *args) { PyObject* coefs_list; PyArrayObject* coefs; PyObject* offsets_list; PyArrayObject* offsets; PyObject* weights_list; PyArrayObject* weights; PyArrayObject* size; PyArrayObject* neighbors; int real; PyObject* comm_obj; int cfd; int range; int nweights; if (!PyArg_ParseTuple(args, "iO!O!O!OiOiOi", &nweights, &PyList_Type, &weights_list, &PyList_Type, &coefs_list, &PyList_Type, &offsets_list, &size, &range, &neighbors, &real, &comm_obj, &cfd)) return NULL; WOperatorObject *self = PyObject_NEW(WOperatorObject, &WOperatorType); if (self == NULL) return NULL; self->stencils = (bmgsstencil*) GPAW_MALLOC(bmgsstencil, nweights); self->weights = (const double**) GPAW_MALLOC(double*, nweights); self->nweights = nweights; for (int iw = 0; iw < nweights; iw++) { coefs = (PyArrayObject*) PyList_GetItem(coefs_list, iw); offsets = (PyArrayObject*) PyList_GetItem(offsets_list, iw); weights = (PyArrayObject*) PyList_GetItem(weights_list, iw); self->stencils[iw] = bmgs_stencil(PyArray_DIMS(coefs)[0], DOUBLEP(coefs), LONGP(offsets), range, LONGP(size)); self->weights[iw] = DOUBLEP(weights); } const long (*nb)[2] = (const long (*)[2])LONGP(neighbors); const long padding[3][2] = {{range, range}, {range, range}, {range, range}}; MPI_Comm comm = MPI_COMM_NULL; if (comm_obj != Py_None) comm = ((MPIObject*)comm_obj)->comm; self->bc = bc_init(LONGP(size), padding, padding, nb, comm, real, cfd); return (PyObject*) self; } gpaw-0.11.0.13004/c/operators.c0000664000175000017500000003552312553643466016075 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2008 CAMd * Copyright (C) 2005 CSC - IT Center for Science Ltd. * Please see the accompanying LICENSE file for further information. */ //*** The apply operator and some associate structors are imple- ***// //*** mented in two version: a original version and a speciel ***// //*** OpenMP version. By default the original version will ***// //*** be used, but it's possible to use the OpenMP version ***// //*** by compiling gpaw with the macro GPAW_OMP defined and ***// //*** and the compile/link option "-fopenmp". ***// //*** Author of the optimized OpenMP code: ***// //*** Mads R. B. Kristensen - madsbk@diku.dk ***// #include #define PY_ARRAY_UNIQUE_SYMBOL GPAW_ARRAY_API #define NO_IMPORT_ARRAY #include #include #include #include "extensions.h" #include "bc.h" #include "mympi.h" #ifdef GPAW_ASYNC #define GPAW_ASYNC3 3 #define GPAW_ASYNC2 2 #else #define GPAW_ASYNC3 1 #define GPAW_ASYNC2 1 #endif typedef struct { PyObject_HEAD bmgsstencil stencil; boundary_conditions* bc; MPI_Request recvreq[2]; MPI_Request sendreq[2]; } OperatorObject; static void Operator_dealloc(OperatorObject *self) { free(self->bc); PyObject_DEL(self); } static PyObject * Operator_relax(OperatorObject *self, PyObject *args) { int relax_method; PyArrayObject* func; PyArrayObject* source; int nrelax; double w = 1.0; if (!PyArg_ParseTuple(args, "iOOi|d", &relax_method, &func, &source, &nrelax, &w)) return NULL; const boundary_conditions* bc = self->bc; double* fun = DOUBLEP(func); const double* src = DOUBLEP(source); const double_complex* ph; const int* size2 = bc->size2; double* buf = GPAW_MALLOC(double, size2[0] * size2[1] * size2[2] * bc->ndouble); double* sendbuf = GPAW_MALLOC(double, bc->maxsend); double* recvbuf = GPAW_MALLOC(double, bc->maxrecv); ph = 0; for (int n = 0; n < nrelax; n++ ) { for (int i = 0; i < 3; i++) { bc_unpack1(bc, fun, buf, i, self->recvreq, self->sendreq, recvbuf, sendbuf, ph + 2 * i, 0, 1); bc_unpack2(bc, buf, i, self->recvreq, self->sendreq, recvbuf, 1); } bmgs_relax(relax_method, &self->stencil, buf, fun, src, w); } free(recvbuf); free(sendbuf); free(buf); Py_RETURN_NONE; } struct apply_args{ int thread_id; OperatorObject *self; int ng; int ng2; int nin; int nthds; int chunksize; int chunkinc; const double* in; double* out; int real; const double_complex* ph; }; //Plain worker void *apply_worker(void *threadarg) { struct apply_args *args = (struct apply_args *) threadarg; boundary_conditions* bc = args->self->bc; MPI_Request recvreq[2]; MPI_Request sendreq[2]; int chunksize = args->nin / args->nthds; if (!chunksize) chunksize = 1; int nstart = args->thread_id * chunksize; if (nstart >= args->nin) return NULL; int nend = nstart + chunksize; if (nend > args->nin) nend = args->nin; if (chunksize > args->chunksize) chunksize = args->chunksize; double* sendbuf = GPAW_MALLOC(double, bc->maxsend * args->chunksize); double* recvbuf = GPAW_MALLOC(double, bc->maxrecv * args->chunksize); double* buf = GPAW_MALLOC(double, args->ng2 * args->chunksize); for (int n = nstart; n < nend; n += chunksize) { if (n + chunksize >= nend && chunksize > 1) chunksize = nend - n; const double* in = args->in + n * args->ng; double* out = args->out + n * args->ng; for (int i = 0; i < 3; i++) { bc_unpack1(bc, in, buf, i, recvreq, sendreq, recvbuf, sendbuf, args->ph + 2 * i, args->thread_id, chunksize); bc_unpack2(bc, buf, i, recvreq, sendreq, recvbuf, chunksize); } for (int m = 0; m < chunksize; m++) if (args->real) bmgs_fd(&args->self->stencil, buf + m * args->ng2, out + m * args->ng); else bmgs_fdz(&args->self->stencil, (const double_complex*) (buf + m * args->ng2), (double_complex*) (out + m * args->ng)); } free(buf); free(recvbuf); free(sendbuf); return NULL; } //Async worker void *apply_worker_cfd_async(void *threadarg) { struct apply_args *args = (struct apply_args *) threadarg; boundary_conditions* bc = args->self->bc; MPI_Request recvreq[2 * GPAW_ASYNC3]; MPI_Request sendreq[2 * GPAW_ASYNC3]; int chunksize = args->nin / args->nthds; if (!chunksize) chunksize = 1; int nstart = args->thread_id * chunksize; if (nstart >= args->nin) return NULL; int nend = nstart + chunksize; if (nend > args->nin) nend = args->nin; if (chunksize > args->chunksize) chunksize = args->chunksize; double* sendbuf = GPAW_MALLOC(double, bc->maxsend * GPAW_ASYNC3 * args->chunksize); double* recvbuf = GPAW_MALLOC(double, bc->maxrecv * GPAW_ASYNC3 * args->chunksize); double* buf = GPAW_MALLOC(double, args->ng2 * args->chunksize); for (int n = nstart; n < nend; n += chunksize) { if (n + chunksize >= nend && chunksize > 1) chunksize = nend - n; const double* in = args->in + n * args->ng; double* out = args->out + n * args->ng; for (int i = 0; i < 3; i++) { bc_unpack1(bc, in, buf, i, recvreq + i * 2, sendreq + i * 2, recvbuf + i * bc->maxrecv * chunksize, sendbuf + i * bc->maxsend * chunksize, args->ph + 2 * i, args->thread_id, chunksize); } for (int i = 0; i < 3; i++) { bc_unpack2(bc, buf, i, recvreq + i * 2, sendreq + i * 2, recvbuf + i * bc->maxrecv * chunksize, chunksize); } for (int m = 0; m < chunksize; m++) if (args->real) bmgs_fd(&args->self->stencil, buf + m * args->ng2, out + m * args->ng); else bmgs_fdz(&args->self->stencil, (const double_complex*) (buf + m * args->ng2), (double_complex*) (out + m * args->ng)); } free(buf); free(recvbuf); free(sendbuf); return NULL; } //Double buffering async worker void *apply_worker_cfd(void *threadarg) { struct apply_args *args = (struct apply_args *) threadarg; boundary_conditions* bc = args->self->bc; MPI_Request recvreq[2 * GPAW_ASYNC3 * GPAW_ASYNC2]; MPI_Request sendreq[2 * GPAW_ASYNC3 * GPAW_ASYNC2]; int chunksize = args->nin / args->nthds; if (!chunksize) chunksize = 1; int nstart = args->thread_id * chunksize; if (nstart >= args->nin) return NULL; int nend = nstart + chunksize; if (nend > args->nin) nend = args->nin; if (chunksize > args->chunksize) chunksize = args->chunksize; int chunk = args->chunkinc; if (chunk > chunksize); chunk = chunksize; double* sendbuf = GPAW_MALLOC(double, bc->maxsend * args->chunksize * GPAW_ASYNC3 * GPAW_ASYNC2); double* recvbuf = GPAW_MALLOC(double, bc->maxrecv * args->chunksize * GPAW_ASYNC3 * GPAW_ASYNC2); double* buf = GPAW_MALLOC(double, args->ng2 * args->chunksize * GPAW_ASYNC2); int odd = 0; const double* in = args->in + nstart * args->ng; double* out; for (int i = 0; i < 3; i++) bc_unpack1(bc, in, buf + odd * args->ng2 * chunksize, i, recvreq + odd * 2 + i * 4, sendreq + odd * 2 + i * 4, recvbuf + odd * bc->maxrecv * chunksize + i * bc->maxrecv * chunksize * GPAW_ASYNC2, sendbuf + odd * bc->maxsend * chunksize + i * bc->maxsend * chunksize * GPAW_ASYNC2, args->ph + 2 * i, args->thread_id, chunk); odd = odd ^ 1; int last_chunk = chunk; for (int n = nstart+chunk; n < nend; n += chunk) { last_chunk += args->chunkinc; if (last_chunk > chunksize); last_chunk = chunksize; if (n + last_chunk >= nend && last_chunk > 1) last_chunk = nend - n; in = args->in + n * args->ng; out = args->out + (n-chunk) * args->ng; for (int i = 0; i < 3; i++) { bc_unpack1(bc, in, buf + odd * args->ng2 * chunksize, i, recvreq + odd * 2 + i * 4, sendreq + odd * 2 + i * 4, recvbuf + odd * bc->maxrecv * chunksize + i * bc->maxrecv * chunksize * GPAW_ASYNC2, sendbuf + odd * bc->maxsend * chunksize + i * bc->maxsend * chunksize * GPAW_ASYNC2, args->ph + 2 * i, args->thread_id, last_chunk); } odd = odd ^ 1; for (int i = 0; i < 3; i++) { bc_unpack2(bc, buf + odd * args->ng2 * chunksize, i, recvreq + odd * 2 + i * 4, sendreq + odd * 2 + i * 4, recvbuf + odd * bc->maxrecv * chunksize + i * bc->maxrecv * chunksize * GPAW_ASYNC2, chunk); } for (int m = 0; m < chunk; m++) if (args->real) bmgs_fd(&args->self->stencil, buf + m * args->ng2 + odd * args->ng2 * chunksize, out + m * args->ng); else bmgs_fdz(&args->self->stencil, (const double_complex*) (buf + m * args->ng2 + odd * args->ng2 * chunksize), (double_complex*) (out + m * args->ng)); chunk = last_chunk; } odd = odd ^ 1; out = args->out + (nend-last_chunk) * args->ng; for (int i = 0; i < 3; i++) { bc_unpack2(bc, buf + odd * args->ng2 * chunksize, i, recvreq + odd * 2 + i * 4, sendreq + odd * 2 + i * 4, recvbuf + odd * bc->maxrecv * chunksize + i * bc->maxrecv * chunksize * GPAW_ASYNC2, last_chunk); } for (int m = 0; m < last_chunk; m++) if (args->real) bmgs_fd(&args->self->stencil, buf + m * args->ng2 + odd * args->ng2 * chunksize, out + m * args->ng); else bmgs_fdz(&args->self->stencil, (const double_complex*) (buf + m * args->ng2 + odd * args->ng2 * chunksize), (double_complex*) (out + m * args->ng)); free(buf); free(recvbuf); free(sendbuf); return NULL; } static PyObject * Operator_apply(OperatorObject *self, PyObject *args) { PyArrayObject* input; PyArrayObject* output; PyArrayObject* phases = 0; if (!PyArg_ParseTuple(args, "OO|O", &input, &output, &phases)) return NULL; int nin = 1; if (PyArray_NDIM(input) == 4) nin = PyArray_DIMS(input)[0]; boundary_conditions* bc = self->bc; const int* size1 = bc->size1; const int* size2 = bc->size2; int ng = bc->ndouble * size1[0] * size1[1] * size1[2]; int ng2 = bc->ndouble * size2[0] * size2[1] * size2[2]; const double* in = DOUBLEP(input); double* out = DOUBLEP(output); const double_complex* ph; bool real = (PyArray_DESCR(input)->type_num == NPY_DOUBLE); if (real) ph = 0; else ph = COMPLEXP(phases); int chunksize = 1; if (getenv("GPAW_CHUNK_SIZE") != NULL) chunksize = atoi(getenv("GPAW_CHUNK_SIZE")); int chunkinc = chunksize; if (getenv("GPAW_CHUNK_INC") != NULL) chunkinc = atoi(getenv("GPAW_CHUNK_INC")); int nthds = 1; #ifdef GPAW_OMP if (getenv("OMP_NUM_THREADS") != NULL) nthds = atoi(getenv("OMP_NUM_THREADS")); #endif struct apply_args *wargs = GPAW_MALLOC(struct apply_args, nthds); pthread_t *thds = GPAW_MALLOC(pthread_t, nthds); for(int i=0; i < nthds; i++) { (wargs+i)->thread_id = i; (wargs+i)->nthds = nthds; (wargs+i)->chunksize = chunksize; (wargs+i)->chunkinc = chunkinc; (wargs+i)->self = self; (wargs+i)->ng = ng; (wargs+i)->ng2 = ng2; (wargs+i)->nin = nin; (wargs+i)->in = in; (wargs+i)->out = out; (wargs+i)->real = real; (wargs+i)->ph = ph; } #ifndef GPAW_ASYNC if (1) #else if (bc->cfd == 0) #endif { #ifdef GPAW_OMP for(int i=1; i < nthds; i++) pthread_create(thds + i, NULL, apply_worker, (void*) (wargs+i)); #endif apply_worker(wargs); } else { #ifdef GPAW_OMP for(int i=1; i < nthds; i++) pthread_create(thds + i, NULL, apply_worker_cfd, (void*) (wargs+i)); #endif apply_worker_cfd(wargs); } #ifdef GPAW_OMP for(int i=1; i < nthds; i++) pthread_join(*(thds+i), NULL); #endif free(wargs); free(thds); Py_RETURN_NONE; } static PyObject * Operator_get_diagonal_element(OperatorObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; const bmgsstencil* s = &self->stencil; double d = 0.0; for (int n = 0; n < s->ncoefs; n++) if (s->offsets[n] == 0) d = s->coefs[n]; return Py_BuildValue("d", d); } static PyObject * Operator_get_async_sizes(OperatorObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; #ifdef GPAW_ASYNC return Py_BuildValue("(iii)", 1, GPAW_ASYNC2, GPAW_ASYNC3); #else return Py_BuildValue("(iii)", 0, GPAW_ASYNC2, GPAW_ASYNC3); #endif } static PyMethodDef Operator_Methods[] = { {"apply", (PyCFunction)Operator_apply, METH_VARARGS, NULL}, {"relax", (PyCFunction)Operator_relax, METH_VARARGS, NULL}, {"get_diagonal_element", (PyCFunction)Operator_get_diagonal_element, METH_VARARGS, NULL}, {"get_async_sizes", (PyCFunction)Operator_get_async_sizes, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL} }; PyTypeObject OperatorType = { PyVarObject_HEAD_INIT(NULL, 0) "Operator", sizeof(OperatorObject), 0, (destructor)Operator_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, "FD-operator object", 0, 0, 0, 0, 0, 0, Operator_Methods }; PyObject * NewOperatorObject(PyObject *obj, PyObject *args) { PyArrayObject* coefs; PyArrayObject* offsets; PyArrayObject* size; int range; PyArrayObject* neighbors; int real; PyObject* comm_obj; int cfd; if (!PyArg_ParseTuple(args, "OOOiOiOi", &coefs, &offsets, &size, &range, &neighbors, &real, &comm_obj, &cfd)) return NULL; OperatorObject *self = PyObject_NEW(OperatorObject, &OperatorType); if (self == NULL) return NULL; self->stencil = bmgs_stencil(PyArray_DIMS(coefs)[0], DOUBLEP(coefs), LONGP(offsets), range, LONGP(size)); const long (*nb)[2] = (const long (*)[2])LONGP(neighbors); const long padding[3][2] = {{range, range}, {range, range}, {range, range}}; MPI_Comm comm = MPI_COMM_NULL; if (comm_obj != Py_None) comm = ((MPIObject*)comm_obj)->comm; self->bc = bc_init(LONGP(size), padding, padding, nb, comm, real, cfd); return (PyObject*)self; } gpaw-0.11.0.13004/c/xc/0000775000175000017500000000000012553644063014307 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/c/xc/xc_mgga.c0000664000175000017500000000742412553643466016075 0ustar jensjjensj00000000000000 #include #include #include #include "xc_mgga.h" #include "xc_gpaw.h" extern const mgga_func_info m06l_info; extern const mgga_func_info tpss_info; extern const mgga_func_info revtpss_info; static void init_common(common_params* params, int code, int nspin, const mgga_func_info *finfo) { params->code = code; params->nspin = nspin; params->funcinfo = finfo; } void init_mgga(void** params, int code, int nspin) { const mgga_func_info *finfo; if (code==20) { finfo = &tpss_info; } else if (code==21) { finfo = &m06l_info; } else if (code==22) { finfo = &revtpss_info; } else { // this should never happen. forces a crash. assert(code>=20 && code <=22); finfo = NULL; } *params = malloc(finfo->size); init_common(*params, code, nspin, finfo); finfo->init(*params); } void end_mgga(common_params *common) { common->funcinfo->end(common); free(common); } void calc_mgga(void** params, int nspin, int ng, const double* n_g, const double* sigma_g, const double* tau_g, double *e_g, double *v_g, double *dedsigma_g, double *dedtau_g) { common_params *common = (common_params*)*params; // check for a changed spin (similar to a line in gpaw/libxc.py) if (nspin!=common->nspin) { int code = common->code; // save this, since we're about to destroy common end_mgga(common); init_mgga(params, code, nspin); common = (common_params*)*params; // init_mgga changes this } if (nspin == 1) { for (int g = 0; g < ng; g++) { // kludge n[1] because of the way TPSS was written (requires n[1]=0.0 even for unpolarized) double n[2]; n[0] = n_g[g]; n[1] = 0.0; if (n[0] < NMIN) n[0] = NMIN; // m06l is assuming that there is space for spinpolarized calculation output // even for non-spin-polarized. double etmp, vtmp[2], dedsigmatmp[3], dedtautmp[2]; common->funcinfo->exch(*params, n, sigma_g+g, tau_g+g, &etmp, vtmp, dedsigmatmp, dedtautmp); e_g[g] = etmp; v_g[g] += vtmp[0]; dedsigma_g[g] = dedsigmatmp[0]; dedtau_g[g] = dedtautmp[0]; common->funcinfo->corr(*params, n, sigma_g+g, tau_g+g, &etmp, vtmp, dedsigmatmp, dedtautmp); e_g[g] += etmp; e_g[g] *= n[0]; v_g[g] += vtmp[0]; dedsigma_g[g] += dedsigmatmp[0]; dedtau_g[g] += dedtautmp[0]; } } else { double etmp, ntmp[2], vtmp[2], sigmatmp[3], dedsigmatmp[3], tautmp[2], dedtautmp[2]; for (int g = 0; g < ng; g++) { ntmp[0] = n_g[g]; if (ntmp[0] < NMIN) ntmp[0] = NMIN; ntmp[1] = n_g[g+ng]; if (ntmp[1] < NMIN) ntmp[1] = NMIN; sigmatmp[0] = sigma_g[g]; sigmatmp[1] = sigma_g[g+ng]; sigmatmp[2] = sigma_g[g+ng+ng]; tautmp[0] = tau_g[g]; tautmp[1] = tau_g[g+ng]; // kludge: mgga_x_tpss requires dedsigma[1] set to 0, since it doesn't calculate it. dedsigmatmp[1]=0.0; common->funcinfo->exch(*params, ntmp, sigmatmp, tautmp, &etmp, vtmp, dedsigmatmp, dedtautmp); e_g[g] = etmp; v_g[g] += vtmp[0]; v_g[g+ng] += vtmp[1]; dedsigma_g[g] = dedsigmatmp[0]; dedsigma_g[g+ng] = dedsigmatmp[1]; dedsigma_g[g+ng+ng] = dedsigmatmp[2]; dedtau_g[g] = dedtautmp[0]; dedtau_g[g+ng] = dedtautmp[1]; common->funcinfo->corr(*params, ntmp, sigmatmp, tautmp, &etmp, vtmp, dedsigmatmp, dedtautmp); e_g[g] += etmp; e_g[g] *= ntmp[0]+ntmp[1]; v_g[g] += vtmp[0]; v_g[g+ng] += vtmp[1]; dedsigma_g[g] += dedsigmatmp[0]; dedsigma_g[g+ng] += dedsigmatmp[1]; dedsigma_g[g+ng+ng] += dedsigmatmp[2]; dedtau_g[g] += dedtautmp[0]; dedtau_g[g+ng] += dedtautmp[1]; } } } gpaw-0.11.0.13004/c/xc/pw91.c0000664000175000017500000001224512553643466015265 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Please see the accompanying LICENSE file for further information. */ #include #include "xc_gpaw.h" double G(double rtrs, double A, double alpha1, double beta1, double beta2, double beta3, double beta4, double* dGdrs); double pw91_exchange(const xc_parameters* par, double n, double rs, double a2, double* dedrs, double* deda2) { double e = C1 / rs; *dedrs = -e / rs; if (par->gga) { double c = C2 * rs / n; c *= c; double s2 = a2 * c; double s = sqrt(s2); double f1 = 7.7956 * s; double f2 = 0.19645 * asinh(f1); double f3 = 0.1508 * exp(-100.0 * s2); double f4 = 0.004 * s2 * s2; double f5 = 1.0 + s * f2; double f6 = f5 + f4; double f7 = 0.2743 - f3; double f8 = f5 + f7 * s2; double Fx = f8 / f6; double f9 = 0.5 * 7.7956 * 0.19645 / sqrt(1.0 + f1 * f1); if (s < 0.00001) f9 += 0.5 * 7.7956 * 0.19645; else f9 += 0.5 * f2 / s; double dFxds2 = ((f9 + f7 + 100.0 * f3 * s2) * f6 - f8 * (f9 + 0.008 * s2)) / (f6 * f6); double ds2drs = 8.0 * s2 / rs; *dedrs = *dedrs * Fx + e * dFxds2 * ds2drs; *deda2 = e * dFxds2 * c; e *= Fx; } return e; } double pw91_correlation(double n, double rs, double zeta, double a2, bool gga, bool spinpol, double* dedrs, double* dedzeta, double* deda2) { double rtrs = sqrt(rs); double de0drs; double e0 = G(rtrs, GAMMA, 0.21370, 7.5957, 3.5876, 1.6382, 0.49294, &de0drs); double e; double xp = 117.0; double xm = 117.0; if (spinpol) { double de1drs; double e1 = G(rtrs, 0.015545, 0.20548, 14.1189, 6.1977, 3.3662, 0.62517, &de1drs); double dalphadrs; double alpha = -G(rtrs, 0.016887, 0.11125, 10.357, 3.6231, 0.88026, 0.49671, &dalphadrs); dalphadrs = -dalphadrs; double zp = 1.0 + zeta; double zm = 1.0 - zeta; xp = pow(zp, THIRD); xm = pow(zm, THIRD); double f = CC1 * (zp * xp + zm * xm - 2.0); double f1 = CC2 * (xp - xm); double zeta2 = zeta * zeta; double zeta3 = zeta2 * zeta; double zeta4 = zeta2 * zeta2; double x = 1.0 - zeta4; *dedrs = (de0drs * (1.0 - f * zeta4) + de1drs * f * zeta4 + dalphadrs * f * x * IF2); *dedzeta = (4.0 * zeta3 * f * (e1 - e0 - alpha * IF2) + f1 * (zeta4 * e1 - zeta4 * e0 + x * alpha * IF2)); e = e0 + alpha * IF2 * f * x + (e1 - e0) * f * zeta4; } else { *dedrs = de0drs; e = e0; } if (gga) { double n2 = n * n; double t2; double y; double phi; double phi2; double phi3; double phi4; double GAMMAPW91 = BETA * BETA / 0.18; if (spinpol) { phi = 0.5 * (xp * xp + xm * xm); phi2 = phi * phi; phi3 = phi * phi2; phi4 = phi * phi3; } else { phi = 1.0; phi2 = 1.0; phi3 = 1.0; phi4 = 1.0; } t2 = C3 * a2 * rs / (n2 * phi2); y = -e / (GAMMAPW91 * phi3); double x = exp(y); double A = BETA / (GAMMAPW91 * (x - 1.0)); double At2 = A * t2; double nom = 1.0 + At2; double denom = nom + At2 * At2; double H0 = (phi3 * GAMMAPW91 * log(1.0 + BETA * t2 * nom / (denom * GAMMAPW91))); double tmp = (phi3 * GAMMAPW91 * BETA / (denom * (BETA * t2 * nom + GAMMAPW91 * denom))); double tmp2 = A * A * x / BETA; double dAdrs = tmp2 * *dedrs / phi3; const double KK = 66.343643960645011; // 100*4/pi*(4/pi/9)**(1/3.) const double XNU = 15.75592; const double Cc0 = 0.004235; const double Cx = -0.001667212; const double K1 = 0.002568; const double K2 = 0.023266; const double K3 = 7.389e-6; const double K4 = 8.723; const double K5 = 0.472; const double K6 = 7.389e-2; double f0 = XNU * exp(-KK * rs * phi4 * t2); double rs2 = rs * rs; double f1 = K1 + K2 * rs + K3 * rs2; double f2 = 1.0 + K4 * rs + K5 * rs2 + K6 * rs2 * rs; double f3 = -10.0 * Cx / 7.0 - Cc0 + f1 / f2; double H1 = f0 * phi3 * f3 * t2; double dH1drs = (-KK * phi4 * t2 * H1 + f0 * phi3 * t2 * ((K2 + 2.0 * K3 * rs) * f2 - (K4 + 2.0 * K5 * rs + 3.0 * K6 * rs2) * f1) / (f2 * f2)); double dH1dt2 = -KK * rs * phi4 * H1 + f0 * phi3 * f3; double dH1dphi = (-4.0 * KK * rs * phi3 * H1 + 3.0 * f0 * phi2 * f3) * t2; double dH0dt2 = (1.0 + 2.0 * At2) * tmp; double dH0dA = -At2 * t2 * t2 * (2.0 + At2) * tmp; *dedrs += (dH0dt2 + dH1dt2) * 7 * t2 / rs + dH0dA * dAdrs + dH1drs; *deda2 = (dH0dt2 + dH1dt2) * C3 * rs / n2; if (spinpol) { double dphidzeta = (1.0 / xp - 1.0 / xm) / 3.0; double dAdzeta = tmp2 * (*dedzeta - 3.0 * e * dphidzeta / phi) / phi3; *dedzeta += ((3.0 * H0 / phi - dH0dt2 * 2.0 * t2 / phi ) * dphidzeta + dH0dA * dAdzeta); *dedzeta += (dH1dphi - dH1dt2 * 2.0 * t2 / phi ) * dphidzeta; *deda2 /= phi2; } e += H0 + H1; } return e; } gpaw-0.11.0.13004/c/xc/ensemble_gga.c0000664000175000017500000000304112553643466017067 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2009 CAMd * Please see the accompanying LICENSE file for further information. */ #include #include "xc_gpaw.h" double beefvdw_exchange(const xc_parameters* par, double n, double rs, double a2, double* dedrs, double* deda2) { double e = C1 / rs; *dedrs = -e / rs; double c = C2 * rs / n; c *= c; double s2 = a2 * c; /* Legendre polynomial basis expansion */ int parlen = par->nparameters-1; double p = par->parameters[0]; double tmp = p + s2; double x = 2.0 * s2 / tmp - 1.0; double dxds2 = 2.0 * p / pow(tmp,2); double Fx = 0.0; double dFxds2 = 0.0; int max_order = par->parameters[parlen+1]; double L[max_order+1]; double dL[max_order+1]; double coef; int m; int order; /* initializing */ L[0] = 1.0; L[1] = x; dL[0] = 0.0; dL[1] = 1.0; /* recursively building polynomia and their derivatives */ for(int i = 2; i < max_order+1; i++) { L[i] = 2.0 * x * L[i-1] - L[i-2] - (x * L[i-1] - L[i-2])/i; dL[i] = i * L[i-1] + x * dL[i-1]; } /* building enhancement factor Fx and derivative dFxds2 */ m = 0; for(int i = 0; i < max_order+1; i++) { order = par->parameters[2+m]; if(order == i) { coef = par->parameters[2+parlen+m]; Fx += coef * L[i]; dFxds2 += coef * dL[i] * dxds2; m += 1; } } double ds2drs = 8.0 * c * a2 / rs; *dedrs = *dedrs * Fx + e * dFxds2 * ds2drs; *deda2 = e * dFxds2 * c; e *= Fx; return e; } gpaw-0.11.0.13004/c/xc/tpss.c0000664000175000017500000003746612553643466015472 0ustar jensjjensj00000000000000/************************************************************************ Implements Perdew, Tao, Staroverov & Scuseria meta-Generalized Gradient Approximation. Exchange part ************************************************************************/ #include #include #include #include "xc_mgga.h" typedef struct tpss_params { common_params common; // needs to be at the beginning of every functional_params XC(func_type) *x_aux; XC(func_type) *c_aux1; XC(func_type) *c_aux2; } tpss_params; /* some parameters */ static double b=0.40, c=1.59096, e=1.537, kappa=0.804, mu=0.21951; /* This is Equation (7) from the paper and its derivatives */ static void x_tpss_7(double p, double alpha, double *qb, double *dqbdp, double *dqbdalpha) { /* Eq. (7) */ double a = sqrt(1.0 + b*alpha*(alpha-1.0)), h = 9.0/20.0; *qb = h*(alpha - 1.0)/a + 2.0*p/3.0; *dqbdp = 2.0/3.0; *dqbdalpha = h*(1.0 + 0.5*b*(alpha-1.0))/pow(a, 3); } /* Equation (10) in all it's glory */ static void x_tpss_10(double p, double alpha, double *x, double *dxdp, double *dxdalpha) { double x1, dxdp1, dxdalpha1; double aux1, ap, apsr, p2; double qb, dqbdp, dqbdalpha; /* Equation 7 */ x_tpss_7(p, alpha, &qb, &dqbdp, &dqbdalpha); p2 = p*p; aux1 = 10.0/81.0; ap = (3*alpha + 5*p)*(3*alpha + 5*p); apsr = (3*alpha + 5*p); /* first we handle the numerator */ x1 = 0.0; dxdp1 = 0.0; dxdalpha1 = 0.0; { /* first term */ double a = (9*alpha*alpha+30*alpha*p+50*p2), a2 = a*a; x1 += aux1*p + 25*c*p2*p*ap/a2; dxdp1 += aux1 + ((3*225*c*p2*alpha*alpha+ 4*750*c*p*p2*alpha + 5*625*c*p2*p2)*a2 - 25*c*p2*p*ap*2*a*(30*alpha+50*2*p))/(a2*a2); dxdalpha1 += ((225*c*p*p2*2*alpha + 750*c*p2*p2)*a2 - 25*c*p2*p*ap*2*a*(9*2*alpha+30*p))/(a2*a2); } { /* second term */ double a = 146.0/2025.0*qb; x1 += a*qb; dxdp1 += 2.0*a*dqbdp; dxdalpha1 += 2.0*a*dqbdalpha; } { /* third term */ double h = 73.0/(405*sqrt(2.0)); x1 += -h*qb*p/apsr * sqrt(ap+9); dxdp1 += -h * qb *((3*alpha)/ap * sqrt(ap+9) + p/apsr * 1./2. * pow(ap+9,-1./2.)* 2*apsr*5) - h*p/apsr*sqrt(ap+9)*dqbdp; dxdalpha1 += -h*qb*( (-1)*p*3/ap * sqrt(ap+9) + p/apsr * 1./2. * pow(ap+9,-1./2.)* 2*apsr*3) - h*p/apsr*sqrt(ap+9)*dqbdalpha; } { /* forth term */ double a = aux1*aux1/kappa; x1 += a*p2; dxdp1 += a*2.0*p; dxdalpha1 += 0.0; } { /* fifth term */ x1 += 20*sqrt(e)*p2/(9*ap); dxdp1 += 20*sqrt(e)/9*(2*p*ap-p2*2*(3*alpha + 5*p)*5)/(ap*ap); dxdalpha1 +=-20*2*sqrt(e)/3*p2/(ap*(3*alpha + 5*p)); } { /* sixth term */ double a = e*mu; x1 += a*p*p2; dxdp1 += a*3.0*p2; dxdalpha1 += 0.0; } /* and now the denominator */ { double a = 1.0+sqrt(e)*p, a2 = a*a; *x = x1/a2; *dxdp = (dxdp1*a - 2.0*sqrt(e)*x1)/(a2*a); *dxdalpha = dxdalpha1/a2; } } static void x_tpss_para(XC(func_type) *lda_aux, const double *rho, const double sigma, const double tau_, double *energy, double *dedd, double *vsigma, double *dedtau) { double gdms, p, tau, tauw; double x, dxdp, dxdalpha, Fx, dFxdx; double tau_lsda, exunif, vxunif, dtau_lsdadd; double dpdd, dpdsigma; double alpha, dalphadd, dalphadsigma, dalphadtau; double aux = (3./10.) * pow((3*M_PI*M_PI),2./3.); /* get the uniform gas energy and potential */ const int np = 1; XC(lda_exc_vxc)(lda_aux, np, rho, &exunif, &vxunif); /* calculate |nabla rho|^2 */ gdms = max(MIN_GRAD*MIN_GRAD, sigma); /* Eq. (4) */ p = gdms/(4.0*pow(3*M_PI*M_PI, 2.0/3.0)*pow(rho[0], 8.0/3.0)); dpdd = -(8.0/3.0)*p/rho[0]; dpdsigma= 1/(4.0*pow(3*M_PI*M_PI, 2.0/3.0)*pow(rho[0], 8.0/3.0)); /* von Weisaecker kinetic energy density */ tauw = max(gdms/(8.0*rho[0]), 1.0e-12); tau = max(tau_, tauw); tau_lsda = aux * pow(rho[0],5./3.); dtau_lsdadd = aux * 5./3.* pow(rho[0],2./3.); alpha = (tau - tauw)/tau_lsda; if(fabs(tauw-tau_)< 1.0e-10){ dalphadsigma = 0.0; dalphadtau = 0.0; dalphadd = 0.0; }else{ dalphadtau = 1./tau_lsda; dalphadsigma = -1./(tau_lsda*8.0*rho[0]); dalphadd = (tauw/rho[0]* tau_lsda - (tau - tauw) * dtau_lsdadd)/ pow(tau_lsda,2.); } /* get Eq. (10) */ x_tpss_10(p, alpha, &x, &dxdp, &dxdalpha); { /* Eq. (5) */ double a = kappa/(kappa + x); Fx = 1.0 + kappa*(1.0 - a); dFxdx = a*a; } { /* Eq. (3) */ *energy = exunif*Fx*rho[0]; /* exunif is en per particle already so we multiply by n the terms with exunif*/ *dedd = vxunif*Fx + exunif*dFxdx*rho[0]*(dxdp*dpdd + dxdalpha*dalphadd); *vsigma = exunif*dFxdx*rho[0]*(dxdp*dpdsigma + dxdalpha*dalphadsigma); *dedtau = exunif*dFxdx*rho[0]*(dxdalpha*dalphadtau); } } static void XC(mgga_x_tpss)(void *p, const double *rho, const double *sigma, const double *tau, double *e, double *dedd, double *vsigma, double *dedtau) { tpss_params *par = (tpss_params*)p; if(par->common.nspin == XC_UNPOLARIZED){ double en; x_tpss_para(par->x_aux, rho, sigma[0], tau[0], &en, dedd, vsigma, dedtau); *e = en/(rho[0]+rho[1]); }else{ /* The spin polarized version is handle using the exact spin scaling Ex[n1, n2] = (Ex[2*n1] + Ex[2*n2])/2 */ *e = 0.0; double e2na, e2nb, rhoa[2], rhob[2]; double vsigmapart[3]; rhoa[0]=2*rho[0]; rhoa[1]=0.0; rhob[0]=2*rho[1]; rhob[1]=0.0; x_tpss_para(par->x_aux, rhoa, 4*sigma[0], 2.0*tau[0], &e2na, &(dedd[0]), &(vsigmapart[0]), &(dedtau[0])); x_tpss_para(par->x_aux, rhob, 4*sigma[2], 2.0*tau[1], &e2nb, &(dedd[1]), &(vsigmapart[2]), &(dedtau[1])); *e = (e2na + e2nb )/(2.*(rho[0]+rho[1])); vsigma[0] = 2*vsigmapart[0]; vsigma[2] = 2*vsigmapart[2]; } } /************************************************************************ Implements Perdew, Tao, Staroverov & Scuseria meta-Generalized Gradient Approximation. J. Chem. Phys. 120, 6898 (2004) http://dx.doi.org/10.1063/1.1665298 Correlation part ************************************************************************/ /* some parameters */ static double d = 2.8; /* Equation (14) */ static void c_tpss_14(double csi, double zeta, double *C, double *dCdcsi, double *dCdzeta) { double fz, C0, dC0dz, dfzdz; double z2 = zeta*zeta; /* Equation (13) */ C0 = 0.53 + z2*(0.87 + z2*(0.50 + z2*2.26)); dC0dz = zeta*(2.0*0.87 + z2*(4.0*0.5 + z2*6.0*2.26)); /*OK*/ fz = 0.5*(pow(1.0 + zeta, -4.0/3.0) + pow(1.0 - zeta, -4.0/3.0)); dfzdz = 0.5*(-4.0/3.0)*(pow(1.0 + zeta, -7.0/3.0) - pow(1.0 - zeta, -7.0/3.0)); /*OK*/ { /* Equation (14) */ double csi2 = csi*csi; double a = 1.0 + csi2*fz, a4 = pow(a, 4); *C = C0 / a4; *dCdcsi = -8.0*C0*csi*fz/(a*a4); /*added C OK*/ *dCdzeta = (dC0dz*a - C0*4.0*csi2*dfzdz)/(a*a4); /*OK*/ } } /* Equation (12) */ static void c_tpss_12(XC(func_type) *aux1, XC(func_type) *aux2, int nspin, const double *rho, const double *sigma, double dens, double zeta, double z, double *e_PKZB, double *de_PKZBdd, double *de_PKZBdsigma, double *de_PKZBdz) { /*some incoming variables: dens = rho[0] + rho[1] z = tau_w/tau zeta = (rho[0] - rho[1])/dens*/ double e_PBE, e_PBEup, e_PBEdn; double de_PBEdd[2], de_PBEdsigma[3], de_PBEddup[2], de_PBEdsigmaup[3], de_PBEdddn[2], de_PBEdsigmadn[3] ; double aux, zsq; double dzetadd[2], dcsidd[2], dcsidsigma[3]; double C, dCdcsi, dCdzeta; double densp[2], densp2[2], sigmatot[3], sigmaup[3], sigmadn[3]; int i; /*initialize dCdcsi and dCdzeta and the energy*/ dCdcsi = dCdzeta = 0.0; e_PBE = 0.0; e_PBEup = 0.0; e_PBEdn = 0.0; /* get the PBE stuff */ if(nspin== XC_UNPOLARIZED) { densp[0]=rho[0]/2.; densp[1]=rho[0]/2.; sigmatot[0] = sigma[0]/4.; sigmatot[1] = sigma[0]/4.; sigmatot[2] = sigma[0]/4.; }else{ densp[0] = rho[0]; densp[1] = rho[1]; sigmatot[0] = sigma[0]; sigmatot[1] = sigma[1]; sigmatot[2] = sigma[2]; } /* e_PBE */ XC(func_type) *auxfunc = (nspin == XC_UNPOLARIZED) ? aux2 : aux1; const int np = 1; XC(gga_exc_vxc)(auxfunc, np, densp, sigmatot, &e_PBE, de_PBEdd, de_PBEdsigma); densp2[0]=densp[0]; densp2[1]=0.0; if(nspin== XC_UNPOLARIZED) { sigmaup[0] = sigma[0]/4.; sigmaup[1] = 0.; sigmaup[2] = 0.; }else{ sigmaup[0] = sigma[0]; sigmaup[1] = 0.; sigmaup[2] = 0.; } /* e_PBE spin up */ XC(gga_exc_vxc)(auxfunc, np, densp2, sigmaup, &e_PBEup, de_PBEddup, de_PBEdsigmaup); densp2[0]=densp[1]; densp2[1]=0.0; if(nspin== XC_UNPOLARIZED) { sigmadn[0] = sigma[0]/4.; sigmadn[1] = 0.; sigmadn[2] = 0.; }else{ sigmadn[0] = sigma[2]; sigmadn[1] = 0.; sigmadn[2] = 0.; } /* e_PBE spin down */ XC(gga_exc_vxc)(auxfunc, np, densp2, sigmadn, &e_PBEdn, de_PBEdddn, de_PBEdsigmadn); /*get Eq. (13) and (14) for the polarized case*/ if(nspin == XC_UNPOLARIZED){ C = 0.53; dzetadd[0] = 0.0; dcsidd [0] = 0.0; dzetadd[1] = 0.0; dcsidd [1] = 0.0; for(i=0; i<3; i++) dcsidsigma[i] = 0.0; }else{ // initialize derivatives for(i=0; i<2; i++){ dzetadd[i] = 0.0; dcsidd [i] = 0.0;} for(i=0; i<3; i++) dcsidsigma[i] = 0.0; double num, gzeta, csi, a; /*numerator of csi: derive as grho all components and then square the 3 parts [2 (grho_a[0]n_b - grho_b[0]n_a) +2 (grho_a[1]n_b - grho_b[1]n_a) + 2 (grho_a[2]n_b - grho_b[2]n_a)]/(n_a+n_b)^2 -> 4 (sigma_aa n_b^2 - 2 sigma_ab n_a n_b + sigma_bb n_b^2)/(n_a+n_b)^2 */ num = sigma[0] * pow(rho[1],2) - 2.* sigma[1]*rho[0]*rho[1]+ sigma[2]*pow(rho[0],2); num = max(num, 1e-20); gzeta = sqrt(4*(num))/(dens*dens); gzeta = max(gzeta, MIN_GRAD); /*denominator of csi*/ a = 2*pow(3.0*M_PI*M_PI*dens, 1.0/3.0); csi = gzeta/a; c_tpss_14(csi, zeta, &C, &dCdcsi, &dCdzeta); dzetadd[0] = (1.0 - zeta)/dens; /*OK*/ dzetadd[1] = -(1.0 + zeta)/dens; /*OK*/ dcsidd [0] = 0.5*csi*(-2*sigma[1]*rho[1]+2*sigma[2]*rho[0])/num - 7./3.*csi/dens; /*OK*/ dcsidd [1] = 0.5*csi*(-2*sigma[1]*rho[0]+2*sigma[0]*rho[1])/num - 7./3.*csi/dens; /*OK*/ dcsidsigma[0]= csi*pow(rho[1],2)/(2*num); /*OK*/ dcsidsigma[1]= -csi*rho[0]*rho[1]/num; /*OK*/ dcsidsigma[2]= csi*pow(rho[0],2)/(2*num); /*OK*/ } aux = (densp[0] * max(e_PBEup, e_PBE) + densp[1] * max(e_PBEdn, e_PBE)) / dens; double dauxdd[2], dauxdsigma[3]; if(e_PBEup > e_PBE) { //case densp[0] * e_PBEup dauxdd[0] = de_PBEddup[0]; dauxdd[1] = 0.0; dauxdsigma[0] = de_PBEdsigmaup[0]; dauxdsigma[1] = 0.0; dauxdsigma[2] = 0.0; }else{ //case densp[0] * e_PBE dauxdd[0] = densp[0] / dens * (de_PBEdd[0] - e_PBE) + e_PBE; dauxdd[1] = densp[0] / dens * (de_PBEdd[1] - e_PBE); dauxdsigma[0] = densp[0] / dens * de_PBEdsigma[0]; dauxdsigma[1] = densp[0] / dens * de_PBEdsigma[1]; dauxdsigma[2] = densp[0] / dens * de_PBEdsigma[2]; } if(e_PBEdn > e_PBE) {//case densp[1] * e_PBEdn dauxdd[0] += 0.0; dauxdd[1] += de_PBEdddn[0]; dauxdsigma[0] += 0.0; dauxdsigma[1] += 0.0; dauxdsigma[2] += de_PBEdsigmadn[0]; }else{//case densp[1] * e_PBE dauxdd[0] += densp[1] / dens * (de_PBEdd[0] - e_PBE); dauxdd[1] += densp[1] / dens * (de_PBEdd[1] - e_PBE) + e_PBE; dauxdsigma[0] += densp[1] / dens * de_PBEdsigma[0]; dauxdsigma[1] += densp[1] / dens * de_PBEdsigma[1]; dauxdsigma[2] += densp[1] / dens * de_PBEdsigma[2]; } zsq=z*z; *e_PKZB = (e_PBE*(1.0 + C * zsq) - (1.0 + C) * zsq * aux); *de_PKZBdz = dens * e_PBE * C * 2*z - dens * (1.0 + C) * 2*z * aux; /*? think ok*/ double dCdd[2]; dCdd[0] = dCdzeta*dzetadd[0] + dCdcsi*dcsidd[0]; /*OK*/ dCdd[1] = dCdzeta*dzetadd[1] + dCdcsi*dcsidd[1]; /*OK*/ /* partial derivatives*/ de_PKZBdd[0] = de_PBEdd[0] * (1.0 + C*zsq) + dens * e_PBE * dCdd[0] * zsq - zsq * (dens*dCdd[0] * aux + (1.0 + C) * dauxdd[0]); de_PKZBdd[1] = de_PBEdd[1] * (1.0 + C*zsq) + dens * e_PBE * dCdd[1] * zsq - zsq * (dens*dCdd[1] * aux + (1.0 + C) * dauxdd[1]); int nder = (nspin==XC_UNPOLARIZED) ? 1 : 3; for(i=0; icommon.nspin; zeta = (rho[0]-rho[1])/(rho[0]+rho[1]); dens = rho[0]; tautr = tau[0]; grad = sigma[0]; if(nspin == XC_POLARIZED) { dens += rho[1]; tautr += tau[1]; grad += (2*sigma[1] + sigma[2]); } grad = max(MIN_GRAD*MIN_GRAD, grad); tauw = max(grad/(8.0*dens), 1.0e-12); taut = max(tautr, tauw); z = tauw/taut; double sigmatmp[3]; sigmatmp[0] = max(MIN_GRAD*MIN_GRAD, sigma[0]); sigmatmp[1] = 0.0; sigmatmp[2] = 0.0; if(nspin == XC_POLARIZED) { //sigma[1] = max(MIN_GRAD*MIN_GRAD, sigma[1]); sigmatmp[1] = sigma[1]; sigmatmp[2] = max(MIN_GRAD*MIN_GRAD, sigma[2]); } /* Equation (12) */ c_tpss_12(par->c_aux1, par->c_aux2, nspin, rho, sigmatmp, dens, zeta, z, &e_PKZB, de_PKZBdd, de_PKZBdsigma, &de_PKZBdz); /* Equation (11) */ { double z2 = z*z, z3 = z2*z; double dedz; double dzdd[2], dzdsigma[3], dzdtau; if(tauw >= tautr || fabs(tauw- tautr)< 1.0e-10){ dzdtau = 0.0; dzdd[0] = 0.0; dzdd[1] = 0.0; dzdsigma[0] = 0.0; dzdsigma[1] = 0.0; dzdsigma[2] = 0.0; }else{ dzdtau = -z/taut; dzdd[0] = - z/dens; dzdd[1] = 0.0; if (nspin == XC_POLARIZED) dzdd[1] = - z/dens; dzdsigma[0] = 1.0/(8*dens*taut); dzdsigma[1] = 0.0; dzdsigma[2] = 0.0; if (nspin == XC_POLARIZED) { dzdsigma[1] = 2.0/(8*dens*taut); dzdsigma[2] = 1.0/(8*dens*taut); } } *energy = e_PKZB * (1.0 + d*e_PKZB*z3); /* due to the definition of na and nb in libxc.c we need to divide by (na+nb) to recover the * same energy for polarized and unpolarized calculation with the same total density */ if(nspin == XC_UNPOLARIZED) *energy *= dens/(rho[0]+rho[1]); dedz = de_PKZBdz*(1.0 + 2.0*d*e_PKZB*z3) + dens*e_PKZB * e_PKZB * d * 3.0*z2; for(is=0; isx_aux = (XC(func_type) *) malloc(sizeof(XC(func_type))); XC(func_init)(par->x_aux, XC_LDA_X, XC_UNPOLARIZED); par->c_aux1 = (XC(func_type) *) malloc(sizeof(XC(func_type))); par->c_aux2 = (XC(func_type) *) malloc(sizeof(XC(func_type))); XC(func_init)(par->c_aux1, XC_GGA_C_PBE, par->common.nspin); XC(func_init)(par->c_aux2, XC_GGA_C_PBE, XC_POLARIZED); } static void tpss_end(void *p) { tpss_params *par = (tpss_params*)p; XC(func_end)(par->x_aux); free(par->x_aux); XC(func_end)(par->c_aux1); XC(func_end)(par->c_aux2); free(par->c_aux1); free(par->c_aux2); } const mgga_func_info tpss_info = { sizeof(tpss_params), &tpss_init, &tpss_end, &XC(mgga_x_tpss), &XC(mgga_c_tpss) }; gpaw-0.11.0.13004/c/xc/xc_gpaw.h0000664000175000017500000000176012553643466016122 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2009 CAMd * Please see the accompanying LICENSE file for further information. */ #ifndef _XC_GPAW_H #define _XC_GPAW_H /* BETA = 0.066725 MU = BETA * pi * pi / 3 C2 = (1 / (18 * pi)**(1 / 3)) C0I = 3 / (4 * pi) C1 = -9 / (8 * pi) * (2 * pi / 3)**(1 / 3) CC1 = 1 / (2**(4 / 3) - 2) CC2 = 4 * CC1 / 3 IF2 = 3 / (2 * CC2); C3 = pi * (4 / (9 * pi))**(1 / 3) / 16 C0 = 4 * pi / 3 */ #define BETA 0.066725 #define GAMMA 0.031091 #define MU 0.2195164512208958 #define C2 0.26053088059892404 #define C0I 0.238732414637843 #define C1 -0.45816529328314287 #define CC1 1.9236610509315362 #define CC2 2.5648814012420482 #define IF2 0.58482236226346462 #define C3 0.10231023756535741 #define C0 4.1887902047863905 #define THIRD 0.33333333333333333 #define NMIN 1.0E-10 typedef int bool; typedef struct { bool gga; double kappa; int nparameters; double parameters[110]; } xc_parameters; #endif /* _XC_GPAW_H */ gpaw-0.11.0.13004/c/xc/m06l.c0000664000175000017500000005636312553643466015254 0ustar jensjjensj00000000000000/************************************************************************ Implements Zhao, Truhlar Meta-gga M06-Local Correlation part ************************************************************************/ #include #include #include #include "xc_mgga.h" typedef struct m06l_params { common_params common; // needs to be at the beginning of every functional_params XC(func_type) *c_aux; XC(func_type) *x_aux; } m06l_params; /* derivatives of x and z with respect to rho, grho and tau*/ static void c_m06l_zx(double x, double z, double rho, double tau, double *dxdd, double *dxdgd, double *dzdd, double *dzdtau) { *dxdd = -8./3. * x * 1/rho; *dxdgd = 1./pow(rho,8./3.); *dzdd = -5./3. * 2 * tau/pow(rho, 8./3.); *dzdtau = 2./pow(rho, 5./3.); } /* Get g for Eq. (13)*/ static void c_m06_13(double *x, double *rho, double *g_ab, double *dg_abdd, double *dg_abdgd) { /*define the C_ab,i */ static double c_ab0= 0.6042374, c_ab1= 177.6783, c_ab2= -251.3252, c_ab3=76.35173, c_ab4=-12.55699; double gammaCab = 0.0031 ; double x_ab, a; double dg_abdx, dxdd_a, dxdgd_a, dzdd_a, dzdtau_a; double dxdd_b, dxdgd_b, dzdd_b, dzdtau_b; /*x = x_ba^2 = x_a^2+x_b^2*/ x_ab = x[0] + x[1]; a= (gammaCab*x_ab/(1+gammaCab*x_ab)); *g_ab = c_ab0*pow(a,0)+ c_ab1*pow(a,1)+ c_ab2*pow(a,2)+c_ab3*pow(a,3)+c_ab4*pow(a,4); double dadx = gammaCab/pow(1+gammaCab*x_ab, 2.); dg_abdx = (0.0*c_ab0*pow(a,-1)+ 1.*c_ab1*pow(a,0)+ 2.*c_ab2*pow(a,1)+3.*c_ab3*pow(a,2)+4.*c_ab4*pow(a,3))*dadx; c_m06l_zx(x[0], 0.0, rho[0], 0.0, &dxdd_a, &dxdgd_a, &dzdd_a, &dzdtau_a); c_m06l_zx(x[1], 0.0, rho[1], 0.0, &dxdd_b, &dxdgd_b, &dzdd_b, &dzdtau_b); dg_abdd[0] = dg_abdx*dxdd_a; dg_abdd[1] = dg_abdx*dxdd_b; dg_abdgd[0] = dg_abdx*dxdgd_a; dg_abdgd[1] = 0.0; dg_abdgd[2] = dg_abdx*dxdgd_b; } /* Get g for Eq. (15)*/ static void c_m06_15(double x, double rho, double *g_ss, double *dg_ssdd, double *dg_ssdgd) { /*define the C_ss,i */ static double c_ss0=0.5349466, c_ss1=0.5396620, c_ss2=-31.61217, c_ss3= 51.49592, c_ss4=-29.19613; double gammaCss = 0.06 ; double a; double dg_ssdx, dxdd, dxdgd, dzdd, dzdtau; /*x = x_a^2 */ a= (gammaCss*x/(1+gammaCss*x)); *g_ss = c_ss0*pow(a,0)+ c_ss1*pow(a,1)+ c_ss2*pow(a,2)+c_ss3*pow(a,3)+c_ss4*pow(a,4); double dadx = gammaCss/pow(1+gammaCss*x, 2.); dg_ssdx = (0.0*c_ss0*pow(a,-1)+ 1.*c_ss1*pow(a,0)+ 2.*c_ss2*pow(a,1)+3.*c_ss3*pow(a,2)+4.*c_ss4*pow(a,3))*dadx; c_m06l_zx(x, 0.0, rho, 0.0, &dxdd, &dxdgd, &dzdd, &dzdtau); *dg_ssdd = dg_ssdx*dxdd; *dg_ssdgd = dg_ssdx*dxdgd; /*printf("g_ss %19.12f\n", *g_ss);*/ } /* Get h_ab for Eq. (12)*/ static void c_m06l_hab(double *x, double *z, double *rho, double *tau, double *h_ab, double *dh_abdd, double *dh_abdgd, double *dh_abdtau) { /* define the d_ab,i for Eq. (12)*/ static double d_ab0= 0.3957626, d_ab1= -0.5614546, d_ab2= 0.01403963, d_ab3= 0.0009831442, d_ab4= -0.003577176; double alpha_ab = 0.00304966; double hab1, dhabdd1[2], dhabdgd1[3], dhabdtau1[2]; double x_ab, z_ab, gamma, xgamma, zgamma; double dgammadx, dgammadz; double dgammadd_a, dgammadgd_a, dgammadtau_a; double dgammadd_b, dgammadgd_b, dgammadtau_b; double dxdd_a, dxdgd_a, dzdd_a, dzdtau_a; double dxdd_b, dxdgd_b, dzdd_b, dzdtau_b; x_ab = x[0] + x[1]; z_ab = z[0] + z[1]; gamma = 1 + alpha_ab*(x_ab + z_ab); { /* derivatives of gamma with respect to x and z*/ dgammadx = alpha_ab; dgammadz = alpha_ab; } c_m06l_zx(x[0], z[0], rho[0], tau[0], &dxdd_a, &dxdgd_a, &dzdd_a, &dzdtau_a); c_m06l_zx(x[1], z[1], rho[1], tau[1], &dxdd_b, &dxdgd_b, &dzdd_b, &dzdtau_b); { /*derivatives of gamma with respect to density, gradient and kietic energy*/ dgammadd_a = dgammadx * dxdd_a + dgammadz * dzdd_a; dgammadd_b = dgammadx * dxdd_b + dgammadz * dzdd_b; dgammadgd_a = dgammadx * dxdgd_a; dgammadgd_b = dgammadx * dxdgd_b; dgammadtau_a = dgammadz * dzdtau_a; dgammadtau_b = dgammadz * dzdtau_b; } xgamma = x_ab/gamma; zgamma = z_ab/gamma; /* we initialize h and collect the terms*/ hab1 = 0.0; dhabdd1[0] = dhabdd1[1] = 0.0; dhabdgd1[0] = dhabdgd1[1] = dhabdgd1[2] = 0.0; dhabdtau1[0] = dhabdtau1[1] = 0.0; { /* first term */ double g2=pow(gamma,2.); hab1 += d_ab0/gamma; dhabdd1[0] += -d_ab0*dgammadd_a/g2; dhabdd1[1] += -d_ab0*dgammadd_b/g2; dhabdgd1[0] += -d_ab0*dgammadgd_a/g2; dhabdgd1[1] += 0.0; dhabdgd1[2] += -d_ab0*dgammadgd_b/g2; dhabdtau1[0] += -d_ab0*dgammadtau_a/g2 ; dhabdtau1[1] += -d_ab0*dgammadtau_b/g2 ; } { /* second term */ double g3=pow(gamma,3.); hab1 += (d_ab1*xgamma + d_ab2*zgamma)/gamma; dhabdd1[0] += (gamma*(d_ab1*dxdd_a+d_ab2*dzdd_a)-2*dgammadd_a*(d_ab1*x_ab+d_ab2*z_ab))/g3; dhabdd1[1] += (gamma*(d_ab1*dxdd_b+d_ab2*dzdd_b)-2*dgammadd_b*(d_ab1*x_ab+d_ab2*z_ab))/g3; dhabdgd1[0] += (d_ab1*dxdgd_a*gamma -2*(d_ab1*x_ab+d_ab2*z_ab)*dgammadgd_a)/g3; dhabdgd1[1] += 0.0; dhabdgd1[2] += (d_ab1*dxdgd_b*gamma -2*(d_ab1*x_ab+d_ab2*z_ab)*dgammadgd_b)/g3; dhabdtau1[0] += (d_ab2*dzdtau_a*gamma -2*(d_ab1*x_ab+d_ab2*z_ab)*dgammadtau_a)/g3; dhabdtau1[1] += (d_ab2*dzdtau_b*gamma -2*(d_ab1*x_ab+d_ab2*z_ab)*dgammadtau_b)/g3; } { /* third term */ double g4= pow(gamma,4); hab1 += (d_ab3*xgamma*xgamma+d_ab4*xgamma*zgamma)/gamma; dhabdd1[0] += (-3*dgammadd_a*(d_ab3*pow(x_ab,2.)+d_ab4*x_ab*z_ab)+dxdd_a*gamma*(2*d_ab3*x_ab+d_ab4*z_ab)+d_ab4*x_ab*dzdd_a*gamma)/g4; dhabdd1[1] += (-3*dgammadd_b*(d_ab3*pow(x_ab,2.)+d_ab4*x_ab*z_ab)+dxdd_b*gamma*(2*d_ab3*x_ab+d_ab4*z_ab)+d_ab4*x_ab*dzdd_b*gamma)/g4; dhabdgd1[0] += (-3*x_ab*(d_ab3*x_ab+d_ab4*z_ab)*dgammadgd_a+gamma*(2*d_ab3*x_ab+d_ab4*z_ab)*dxdgd_a)/g4; dhabdgd1[1] += 0.0; dhabdgd1[2] += (-3*x_ab*(d_ab3*x_ab+d_ab4*z_ab)*dgammadgd_b+gamma*(2*d_ab3*x_ab+d_ab4*z_ab)*dxdgd_b)/g4; dhabdtau1[0] += (d_ab4*x_ab*dzdtau_a*gamma-3*x_ab*(d_ab3*x_ab+d_ab4*z_ab)*dgammadtau_a)/g4; dhabdtau1[1] += (d_ab4*x_ab*dzdtau_b*gamma-3*x_ab*(d_ab3*x_ab+d_ab4*z_ab)*dgammadtau_b)/g4; } *h_ab = hab1; //derivatives dh_abdd[0] = dhabdd1[0]; dh_abdd[1] = dhabdd1[1]; dh_abdgd[0] = dhabdgd1[0]; dh_abdgd[1] = dhabdgd1[1]; dh_abdgd[2] = dhabdgd1[2]; dh_abdtau[0] = dhabdtau1[0]; dh_abdtau[1] = dhabdtau1[1]; } /* Get h_ss for Eq. (14)*/ static void c_m06l_hss(double x, double z, double rho, double tau, double *h_ss, double *dh_ssdd, double *dh_ssdgd, double *dh_ssdtau) { /* define the d_ab,i for Eq. (12)*/ static double d_ss0= 0.4650534, d_ss1= 0.1617589, d_ss2= 0.1833657, d_ss3= 0.0004692100, d_ss4= -0.004990573; double alpha_ss = 0.00515088; double hss1, dhssdd1, dhssdgd1, dhssdtau1; double gamma, xgamma, zgamma; double dgammadx, dgammadz; double dgammadd, dgammadgd, dgammadtau; double dxdd, dxdgd, dzdd, dzdtau; gamma = 1 + alpha_ss*(x + z); { /* derivatives of gamma with respect to x and z*/ dgammadx = alpha_ss; dgammadz = alpha_ss; } c_m06l_zx(x, z, rho, tau, &dxdd, &dxdgd, &dzdd, &dzdtau); { /* derivatives of gamma with respect to density, gradient and kinetic energy */ dgammadd = dgammadx * dxdd + dgammadz * dzdd; dgammadgd = dgammadx * dxdgd; dgammadtau = dgammadz * dzdtau; } xgamma = x/gamma; zgamma = z/gamma; /* we initialize h and collect the terms*/ hss1 = 0.0; dhssdd1 = 0.0; dhssdgd1 = 0.0; dhssdtau1 = 0.0; { /* first term */ double g2=pow(gamma,2.); hss1 += d_ss0/gamma; dhssdd1 += -d_ss0*dgammadd/g2; dhssdgd1 += -d_ss0*dgammadgd/g2; dhssdtau1 += -d_ss0*dgammadtau/g2 ; } { /* second term */ double g3=pow(gamma,3.); hss1 += (d_ss1*xgamma + d_ss2*zgamma)/gamma; dhssdd1 += (gamma*(d_ss1*dxdd+d_ss2*dzdd)-2*dgammadd*(d_ss1*x+d_ss2*z))/g3; dhssdgd1 += (d_ss1*dxdgd*gamma -2*(d_ss1*x+d_ss2*z)*dgammadgd)/g3; dhssdtau1 += (d_ss2*dzdtau*gamma -2*(d_ss1*x+d_ss2*z)*dgammadtau)/g3; } { /* third term */ double g4= pow(gamma,4); hss1 += (d_ss3*xgamma*xgamma+d_ss4*xgamma*zgamma)/gamma; dhssdd1 += (-3*dgammadd*(d_ss3*pow(x,2.)+d_ss4*x*z)+dxdd*gamma*(2*d_ss3*x+d_ss4*z)+d_ss4*x*dzdd*gamma)/g4; dhssdgd1 += (-3*x*(d_ss3*x+d_ss4*z)*dgammadgd+gamma*(2*d_ss3*x+d_ss4*z)*dxdgd)/g4; dhssdtau1 += (d_ss4*x*dzdtau*gamma-3*x*(d_ss3*x+d_ss4*z)*dgammadtau)/g4; } *h_ss = hss1; //derivatives *dh_ssdd = dhssdd1; *dh_ssdgd = dhssdgd1; *dh_ssdtau = dhssdtau1; } static void c_m06l_para(m06l_params *p, const double *rho, const double *sigmatmp, const double *tautmp, double *energy, double *dedd, double *vsigma, double *dedtau) { double rho2[2], rho2s[2], x[2], z[2], zc_ss[2]; double tau2[2], tauw[2], dens, dens1, sigma[3]; double g_ss[2], h_ss[2], Ec_ss[2], D_ss[2]; double g_ab=0.0, h_ab=0.0, Ec_ab=0.0; double exunif_ss[2], vxunif_up[2], vxunif_dn[2], vxunif_ss[2]; double exunif =0.0, exunif_ab=0.0, vxunif[2]; //derivatives double dh_ssdd[2], dh_ssdgd[3], dh_ssdtau[2]; double dg_ssdd[2], dg_ssdgd[3] ; double dh_abdd[2], dh_abdgd[3], dh_abdtau[2]; double dg_abdd[2], dg_abdgd[3]; double dEc_ssdd[2], dEc_ssdgd[3], dEc_ssdtau[2]; double dEc_abdd[2], dEc_abdgd[3], dEc_abdtau[2]; double dD_ssdd[2], dD_ssdgd[3], dD_ssdtau[2], dD_ssdx[2], dD_ssdz[2]; double dxdd[2], dxdgd[2], dzdd[2], dzdtau[2]; const double Cfermi= (3./5.)*pow(6*M_PI*M_PI,2./3.); /* put in by cpo for const reasons */ double sigma_[3],tau[2]; sigma_[0] = sigmatmp[0]; sigma_[1] = sigmatmp[1]; sigma_[2] = sigmatmp[2]; tau[0] = tautmp[0]; tau[1] = tautmp[1]; /*calculate |nabla rho|^2 */ sigma_[0] = max(MIN_GRAD*MIN_GRAD, sigma_[0]); tauw[0] = max(sigma_[0]/(8.0*rho[0]), 1.0e-12); tau[0] = max(tauw[0], tau[0]); dens1 = rho[0]+rho[1]; if(p->common.nspin== XC_UNPOLARIZED) { tau[1] = 0.0; rho2[0] = rho[0]/2.; rho2[1] = rho[0]/2.; sigma[0] = sigma_[0]/4.; sigma[1] = sigma_[0]/4.; sigma[2] = sigma_[0]/4.; dens = rho[0]; tau2[0] = tau[0]/2.; tau2[1] = tau[0]/2.; }else{ sigma_[2] = max(MIN_GRAD*MIN_GRAD, sigma_[2]); tauw[1] = max(sigma_[2]/(8.0*rho[1]), 1.0e-12); tau[1] = max(tauw[1], tau[1]); rho2[0]=rho[0]; rho2[1]=rho[1]; sigma[0] = sigma_[0]; sigma[1] = sigma_[1]; sigma[2] = sigma_[2]; dens = rho[0]+rho[1]; tau2[0] =tau[0]; tau2[1] =tau[1]; } //get the e_LDA(rho_a,b) const int np = 1; XC(lda_exc_vxc)(p->c_aux, np, rho2, &exunif, vxunif); exunif = exunif*dens; /*==============get the E_sigma part================*/ /*============ spin up =============*/ rho2s[0]=rho2[0]; rho2s[1]=0.; //get the e_LDA(rho_up,0) XC(lda_exc_vxc)(p->c_aux, np, rho2s, &(exunif_ss[0]), vxunif_up); exunif_ss[0] = exunif_ss[0] * rho2s[0]; vxunif_ss[0] = vxunif_up[0]; /*define variables for rho_up and zc in order to avoid x/0 -> D_ss = -inf */ x[0] = sigma[0]/(pow(rho2s[0], 8./3.)); z[0] = 2*tau2[0]/pow(rho2s[0],5./3.) - Cfermi; zc_ss[0] = 2*tau2[0]/pow(rho2s[0],5./3.); /*D_ss = 1 -x/4*(z + Cf), z+Cf = 2*tau2/pow(rho2s[0],5./3.) = zc */ D_ss[0] = 1 - x[0]/(4. * zc_ss[0]); //derivatives for D_up dD_ssdx[0] = -1/(4 * zc_ss[0]); dD_ssdz[0] = 4 * x[0]/pow(4.*zc_ss[0],2.); c_m06l_zx(x[0], z[0], rho2s[0], tau2[0], &(dxdd[0]), &(dxdgd[0]), &(dzdd[0]), &(dzdtau[0])); dD_ssdd[0] = dD_ssdx[0] * dxdd[0] + dD_ssdz[0] * dzdd[0]; dD_ssdgd[0] = dD_ssdx[0] * dxdgd[0]; dD_ssdtau[0] = dD_ssdz[0] * dzdtau[0]; /*build up Eq. (14): Ec_sigmasigma*/ c_m06_15(x[0], rho2s[0], &(g_ss[0]), &(dg_ssdd[0]), &(dg_ssdgd[0])); c_m06l_hss(x[0], z[0], rho2s[0], tau2[0], &(h_ss[0]), &(dh_ssdd[0]), &(dh_ssdgd[0]), &(dh_ssdtau[0])); Ec_ss[0] = (exunif_ss[0] * (g_ss[0]+h_ss[0]) * D_ss[0]); //printf("Ec_up %.9e\n", Ec_ss[0]); /*============== spin down =============*/ rho2s[0]=rho2[1]; rho2s[1]=0.; //get the e_LDA(0,rho_dn) XC(lda_exc_vxc)(p->c_aux, np, rho2s, &(exunif_ss[1]), vxunif_dn); exunif_ss[1] = exunif_ss[1] * rho2s[0]; vxunif_ss[1] = vxunif_dn[0]; /*define variables for rho_beta*/ x[1] = sigma[2]/(pow(rho2s[0], 8./3.)); z[1] = 2*tau2[1]/pow(rho2s[0],5./3.) - Cfermi; zc_ss[1] = 2*tau2[1]/pow(rho2s[0],5./3.); //printf("x1 %.9e, zc_ss%.9e\n", x[1], zc_ss[1]); D_ss[1] = 1 - x[1]/(4.*zc_ss[1]); //derivatives for D_dn dD_ssdx[1] = - 1/(4*zc_ss[1]); dD_ssdz[1] = 4*x[1]/pow(4.*zc_ss[1],2.); c_m06l_zx(x[1], z[1], rho2s[0], tau2[1], &(dxdd[1]), &(dxdgd[1]), &(dzdd[1]), &(dzdtau[1])); dD_ssdd[1] = dD_ssdx[1] * dxdd[1] + dD_ssdz[1] * dzdd[1]; dD_ssdgd[2] = dD_ssdx[1] * dxdgd[1]; dD_ssdtau[1] = dD_ssdz[1] * dzdtau[1]; c_m06_15(x[1], rho2s[0], &(g_ss[1]), &(dg_ssdd[1]), &(dg_ssdgd[2])); c_m06l_hss(x[1], z[1], rho2s[0], tau2[1], &(h_ss[1]), &(dh_ssdd[1]), &(dh_ssdgd[2]), &(dh_ssdtau[1])); //printf("exunif_ss %.9e, (g_ss[1]+h_ss[1])%.9e, D_ss %.9e\n", exunif_ss[1],(g_ss[1]+h_ss[1]),D_ss[1]); Ec_ss[1] = (exunif_ss[1] * (g_ss[1]+h_ss[1]) * D_ss[1]); //printf("Ec_dn %.9e\n", Ec_ss[1]); // Derivatives for Ec_up and Ec_dn with respect to density and kinetic energy int i; for(i=0; i<2; i++){ dEc_ssdd[i] = exunif_ss[i] * dh_ssdd[i] * D_ss[i] + vxunif_ss[i] * h_ss[i] * D_ss[i] + exunif_ss[i] * h_ss[i] * dD_ssdd[i] + exunif_ss[i] * dg_ssdd[i] * D_ss[i] + vxunif_ss[i] * g_ss[i] * D_ss[i] + exunif_ss[i] * g_ss[i] * dD_ssdd[i]; dEc_ssdtau[i] = exunif_ss[i] * dh_ssdtau[i] * D_ss[i] + exunif_ss[i] * h_ss[i] * dD_ssdtau[i] + exunif_ss[i] * g_ss[i] * dD_ssdtau[i]; } // Derivatives for Ec_up and Ec_dn with respect to gradient dEc_ssdgd[0] = exunif_ss[0] * dh_ssdgd[0] * D_ss[0] + exunif_ss[0] * h_ss[0] * dD_ssdgd[0] + exunif_ss[0] * dg_ssdgd[0] * D_ss[0] + exunif_ss[0] * g_ss[0] * dD_ssdgd[0]; dEc_ssdgd[2] = exunif_ss[1] * dh_ssdgd[2] * D_ss[1] + exunif_ss[1] * h_ss[1] * dD_ssdgd[2] + exunif_ss[1] * dg_ssdgd[2] * D_ss[1] + exunif_ss[1] * g_ss[1] * dD_ssdgd[2]; /*==============get the E_ab part========================*/ exunif_ab = exunif - exunif_ss[0] - exunif_ss[1]; //x_ab = sigmatot[0] /(pow(rho2[0], 8./3.)) + sigmatot[2] /(pow(rho2[1], 8./3.)); //z_ab = 2*tau2[0]/pow(rho2[0],5./3.) + 2*tau2[1]/pow(rho2[1],5./3.) - 2*Cfermi; /*build up Eq. (12): Ec_alphabeta*/ c_m06_13(x, rho2, &g_ab, dg_abdd, dg_abdgd); c_m06l_hab(x, z, rho2, tau2, &h_ab, dh_abdd, dh_abdgd, dh_abdtau); Ec_ab = exunif_ab * (g_ab+h_ab); // Derivatives for Ec_ab with respect to density and kinetic energy for(i=0; i<2; i++){ dEc_abdd[i] = exunif_ab * (dh_abdd[i]+ dg_abdd[i]) + (vxunif[i]- vxunif_ss[i]) * (g_ab+h_ab); dEc_abdtau[i] = exunif_ab * dh_abdtau[i]; } // Derivatives for Ec_ab with respect to gradient for(i=0; i<3; i++){ dEc_abdgd[i] = exunif_ab * (dh_abdgd[i] + dg_abdgd[i]); } /*==============get the total energy E_c= E_up + E_dn + E_ab========================*/ /*==============================and derivatives=====================================*/ *energy = (Ec_ss[0] + Ec_ss[1] + Ec_ab)/dens1; //printf("Ec_ss %.9e, Ec_ss %.9e, Ec_ab %.9e\n", Ec_ss[0], Ec_ss[1], Ec_ab); //derivative for the total correlation energy if(p->common.nspin== XC_UNPOLARIZED) { dedd[0]=dEc_ssdd[0] + dEc_abdd[0]; dedd[1]=0.0; vsigma[0]= (dEc_ssdgd[0] + dEc_abdgd[0])/2.; vsigma[1]= 0.0; vsigma[2]= 0.0; dedtau[0]= dEc_ssdtau[0] + dEc_abdtau[0]; dedtau[1]= 0.0; }else{ dedd[0]=dEc_ssdd[0] + dEc_abdd[0]; dedd[1]=dEc_ssdd[1] + dEc_abdd[1]; vsigma[0]= dEc_ssdgd[0] + dEc_abdgd[0]; vsigma[1]= 0.0; vsigma[2]= dEc_ssdgd[2] + dEc_abdgd[2]; dedtau[0]= dEc_ssdtau[0] + dEc_abdtau[0]; dedtau[1]= dEc_ssdtau[1] + dEc_abdtau[1]; } } static void XC(mgga_c_m06l)(void *p, const double *rho, const double *sigma, const double *tau, double *e, double *dedd, double *vsigma, double *dedtau) { c_m06l_para(p, rho, sigma, tau, e, dedd, vsigma, dedtau); } /* derivatives of x and z with respect to rho, grho and tau: Eq.(1) and Eq.(3)*/ static void x_m06l_zx(double x, double z, double rho, double tau, double *dxdd, double *dxdgd, double *dzdd, double *dzdtau) { *dxdd = -8./3. * x * 1/rho; *dxdgd = 1./pow(rho,8./3.); *dzdd = -5./3. * 2* tau/pow(rho, 8./3.); *dzdtau = 2./pow(rho, 5./3.); } /* Build gamma and its derivatives with respect to rho, grho and tau: Eq. (4)*/ static void x_m06l_gamma(double x, double z, double rho, double tau, double *gamma, double *dgammadd, double *dgammadgd, double *dgammadtau) { static double alpha = 0.00186726; /*set alpha of Eq. (4)*/ double dgammadx, dgammadz; double dxdd, dxdgd, dzdd, dzdtau; *gamma = 1 + alpha*(x + z); /*printf("gamma %19.12f\n", *gamma);*/ { /* derivatives */ dgammadx = alpha; dgammadz = alpha; } x_m06l_zx(x, z, rho, tau, &dxdd, &dxdgd, &dzdd, &dzdtau); { *dgammadd = dgammadx*dxdd + dgammadz*dzdd; *dgammadgd = dgammadx*dxdgd; *dgammadtau = dgammadz*dzdtau; } } /************************************************************************ Implements Zhao, Truhlar Meta-gga M06-Local Correlation part ************************************************************************/ /* calculate h and h derivatives with respect to rho, grho and tau: Equation (5) */ static void x_m06l_h(double x, double z, double rho, double tau, double *h, double *dhdd, double *dhdgd, double *dhdtau) { /* parameters for h(x_sigma,z_sigma) of Eq. (5)*/ static double d0=0.6012244, d1=0.004748822, d2=-0.008635108, d3=-0.000009308062, d4=0.00004482811; double h1, dhdd1, dhdgd1, dhdtau1; double gamma, dgammadd, dgammadgd, dgammadtau; double xgamma, zgamma; double dxdd, dxdgd, dzdd, dzdtau; x_m06l_gamma(x, z, rho, tau, &gamma, &dgammadd, &dgammadgd, &dgammadtau); xgamma = x/gamma; zgamma = z/gamma; /* we initialize h and its derivatives and collect the terms*/ h1 = 0.0; dhdd1 = 0.0; dhdgd1 = 0.0; dhdtau1 = 0.0; { /* first term */ double g2=pow(gamma,2.); h1 += d0/gamma; dhdd1 += -d0*dgammadd/g2; dhdgd1 += -d0*dgammadgd/g2; dhdtau1 += -d0*dgammadtau/g2 ; } x_m06l_zx(x, z, rho, tau, &dxdd, &dxdgd, &dzdd, &dzdtau); { /* second term */ double g3=pow(gamma,3.); h1 += (d1*xgamma + d2*zgamma)/gamma; dhdd1 += (gamma*(d1*dxdd+d2*dzdd)-2*dgammadd*(d1*x+d2*z))/g3; dhdgd1 += (d1*dxdgd*gamma -2*(d1*x+d2*z)*dgammadgd)/g3; dhdtau1 += (d2*dzdtau*gamma -2*(d1*x+d2*z)*dgammadtau)/g3; } { /* third term */ double g4= pow(gamma,4); h1 += (d3*xgamma*xgamma+d4*xgamma*zgamma)/gamma; dhdd1 += (-3*dgammadd*(d3*pow(x,2.)+d4*x*z)+dxdd*gamma*(2*d3*x+d4*z)+d4*x*dzdd*gamma)/g4; dhdgd1 += (-3*x*(d3*x+d4*z)*dgammadgd+gamma*(2*d3*x+d4*z)*dxdgd)/g4; dhdtau1 += (d4*x*dzdtau*gamma-3*x*(d3*x+d4*z)*dgammadtau)/g4; } *h = h1; /*printf(" h %19.12f\n", *h);*/ *dhdd = dhdd1; *dhdgd =dhdgd1; *dhdtau = dhdtau1; } /* f(w) and its derivatives with respect to rho and tau*/ static void x_m06l_fw(double rho, double tau, double *fw, double *dfwdd, double *dfwdtau) { /*define the parameters for fw of Eq. (8) as in the reference paper*/ static double a0= 0.3987756, a1= 0.2548219, a2= 0.3923994, a3= -2.103655, a4= -6.302147, a5= 10.97615, a6= 30.97273, a7=-23.18489, a8=-56.73480, a9=21.60364, a10= 34.21814, a11= -9.049762; double tau_lsda, t, w; double dtdd, dtdtau; double dfwdw, dwdt, dtau_lsdadd; double aux = (3./10.) * pow((6*M_PI*M_PI),2./3.); /*3->6 for nspin=2 */ tau_lsda = aux * pow(rho,5./3.); t = tau_lsda/tau; dtdtau = -t/tau; w = (t - 1)/(t + 1); *fw = a0*pow(w,0.)+a1*pow(w,1.)+a2*pow(w,2.)+a3*pow(w,3.)+a4*pow(w,4.)+ + a5*pow(w,5.)+a6*pow(w,6.)+a7*pow(w,7.)+a8*pow(w,8.)+a9*pow(w,9.)+a10*pow(w,10.)+a11*pow(w,11.); dfwdw = 0.0*a0*pow(w,-1)+1.0*a1*pow(w,0.)+2.0*a2*pow(w,1.)+3.0*a3*pow(w,2.)+4.0*a4*pow(w,3.)+ + 5.0*a5*pow(w,4.)+6.0*a6*pow(w,5.)+7.0*a7*pow(w,6.)+8.0*a8*pow(w,7.)+9.0*a9*pow(w,8.)+ + 10*a10*pow(w,9.)+11*a11*pow(w,10.); dwdt = 2/pow((t + 1),2.); dtau_lsdadd = aux * 5./3.* pow(rho,2./3.); dtdd = dtau_lsdadd/tau; *dfwdd = dfwdw * dwdt * dtdd; *dfwdtau = dfwdw * dwdt * dtdtau; } static void x_m06l_para(m06l_params *pt, double rho, double sigma, double tau, double *energy, double *dedd, double *vsigma, double *dedtau) { /*Build Eq. (6) collecting the terms Fx_PBE, fw, e_lsda and h*/ double grad, tauw, tau2, x, z; double rho2[2],sigmatot[3]; double F_PBE, de_PBEdd[2], de_PBEdgd[3]; double h, dhdd, dhdgd, dhdtau; double fw, dfwdd, dfwdtau; double epsx_lsda, depsx_lsdadd; const double Cfermi = (3./5.) * pow(6*M_PI*M_PI,2./3.); /* calculate |nabla rho|^2 */ grad = sigma; grad = max(MIN_GRAD*MIN_GRAD, grad); tauw = max(grad/(8.0*rho),1.0e-12); /* tau^W = |nabla rho|^2/ 8rho */ tau = max(tau, tauw); rho2[0]=rho/2.; rho2[1]=0.0; sigmatot[0] = grad/4.; sigmatot[1] = 0.0; sigmatot[2] = 0.0; tau2 =tau/2.; /* get the uniform gas energy and potential a MINUS was missing in the paper*/ epsx_lsda = -(3./2.)*pow(3./(4*M_PI),1./3.)*pow(rho2[0],4./3.); depsx_lsdadd = -2*pow(3./(4*M_PI),1./3.)*pow(rho2[0],1./3.); /*get Fx for PBE*/ const int np = 1; XC(gga_exc_vxc)(pt->x_aux, np, rho2, sigmatot, &F_PBE, de_PBEdd, de_PBEdgd); /* define x and z from Eq. (1) and Eq. (3) NOTE: we build directly x^2 */ x = grad/(4*pow(rho2[0], 8./3.)); z = 2*tau2/pow(rho2[0],5./3.) - Cfermi; /*THERE IS A 2 IN FRONT AS IN THEOR. CHEM. ACCOUNT 120 215 (2008)*/ /*get h and fw*/ x_m06l_h(x, z, rho2[0], tau2, &h, &dhdd, &dhdgd, &dhdtau); x_m06l_fw(rho2[0], tau2, &fw, &dfwdd, &dfwdtau); { /* Eq. (6) E_x = Int F_PBE*fw + exunif*h, the factor 2 accounts for spin. */ *energy = 2*(F_PBE*rho2[0] *fw + epsx_lsda *h); *dedd = (de_PBEdd[0] *fw + F_PBE*rho2[0] * dfwdd+ depsx_lsdadd *h + epsx_lsda * dhdd); *dedtau = (F_PBE * dfwdtau *rho2[0] + epsx_lsda * dhdtau); *vsigma = (de_PBEdgd[0] *fw + epsx_lsda*dhdgd)/2.; } } void XC(mgga_x_m06l)(void *p, const double *rho, const double *sigma, const double *tau, double *e, double *dedd, double *vsigma, double *dedtau) { m06l_params *par = (m06l_params*)p; if(par->common.nspin == XC_UNPOLARIZED){ double en; x_m06l_para(p, rho[0], sigma[0], tau[0], &en, dedd, vsigma, dedtau); *e = en/(rho[0]+rho[1]); }else{ *e = 0.0; double e2na, e2nb, rhoa[2], rhob[2]; double vsigmapart[3]; rhoa[0]=2*rho[0]; rhoa[1]=0.0; rhob[0]=2*rho[1]; rhob[1]=0.0; x_m06l_para(p, rhoa[0], 4*sigma[0], 2.0*tau[0], &e2na, &(dedd[0]), &(vsigmapart[0]), &(dedtau[0])); x_m06l_para(p, rhob[0], 4*sigma[2], 2.0*tau[1], &e2nb, &(dedd[1]), &(vsigmapart[2]), &(dedtau[1])); *e = (e2na + e2nb )/(2.*(rho[0]+rho[1])); vsigma[0] = 2*vsigmapart[0]; vsigma[2] = 2*vsigmapart[2]; } } static void m06l_init(void *p) { m06l_params *par = (m06l_params*)p; par->c_aux = (XC(func_type) *) malloc(sizeof(XC(func_type))); XC(func_init)(par->c_aux, XC_LDA_C_PW, XC_POLARIZED); par->x_aux = (XC(func_type) *) malloc(sizeof(XC(func_type))); XC(func_init)(par->x_aux, XC_GGA_X_PBE, XC_POLARIZED); } static void m06l_end(void *p) { m06l_params *par = (m06l_params*)p; XC(func_end)(par->c_aux); free(par->c_aux); XC(func_end)(par->x_aux); free(par->x_aux); } const mgga_func_info m06l_info = { sizeof(m06l_params), &m06l_init, &m06l_end, &XC(mgga_x_m06l), &XC(mgga_c_m06l), }; gpaw-0.11.0.13004/c/xc/libxc.c0000664000175000017500000007333512553643466015575 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2008 CAMd * Please see the accompanying LICENSE file for further information. */ #include #define PY_ARRAY_UNIQUE_SYMBOL GPAW_ARRAY_API #define NO_IMPORT_ARRAY #include #include #include #include "xc_gpaw.h" #include "../extensions.h" typedef struct { PyObject_HEAD /* exchange-correlation energy second derivatives */ void (*get_fxc)(XC(func_type) *func, double point[7], double der[5][5]); XC(func_type) xc_functional; XC(func_type) x_functional; XC(func_type) c_functional; XC(func_type) *functional[2]; /* store either x&c, or just xc */ int nspin; /* must be common to x and c, so declared redundantly here */ } lxcXCFunctionalObject; void XC(lda_fxc_fd)(const XC(func_type) *p, const double *rho, double *fxc); /* a general call for an LDA functional - finite difference */ void get_fxc_fd_lda(XC(func_type) *func, double point[7], double der[5][5]) { double v2rho2[3], v2rhosigma[6], v2sigma2[6]; for(int i=0; i<3; i++) v2rho2[i] = 0.0; for(int i=0; i<6; i++){ v2rhosigma[i] = 0.0; v2sigma2[i] = 0.0; } XC(lda_fxc_fd)(func, point, v2rho2); der[0][0] = v2rho2[0]; der[0][1] = der[1][0] = v2rho2[1]; der[1][1] = v2rho2[2]; der[0][2] = der[2][0] = v2rhosigma[0]; der[0][3] = der[3][0] = v2rhosigma[1]; der[0][4] = der[4][0] = v2rhosigma[2]; der[1][2] = der[2][1] = v2rhosigma[3]; der[1][3] = der[3][1] = v2rhosigma[4]; der[1][4] = der[4][1] = v2rhosigma[5]; der[2][2] = v2sigma2[0]; der[2][3] = der[3][2] = v2sigma2[1]; der[2][4] = der[4][2] = v2sigma2[2]; der[3][3] = v2sigma2[3]; der[3][4] = der[4][3] = v2sigma2[4]; der[4][4] = v2sigma2[5]; } // finite difference calculation of second functional derivative // stolen from libxc/testsuite/xc-consistency.c double get_point(XC(func_type) *func, double point[7], double *e, double der[5], int which) { const int np = 1; switch(func->info->family) { case XC_FAMILY_LDA: XC(lda_exc_vxc)(func, np, &(point[0]), e, &(der[0])); break; case XC_FAMILY_GGA: case XC_FAMILY_HYB_GGA: XC(gga_exc_vxc)(func, np, &(point[0]), &(point[2]), e, &(der[0]), &(der[2])); break; } if(which == 0) return (*e)*(point[0] + point[1]); else return der[which-1]; } void first_derivative(XC(func_type) *func, double point[7], double der[5], int which, int nspin) { int i; for(i=0; i<5; i++){ const double delta = 5e-10; double dd, p[5], v[5]; int j; if(nspin==1 && (i!=0 && i!=2)){ der[i] = 0.0; continue; } dd = point[i]*delta; if(dd < delta) dd = delta; for(j=0; j<5; j++) p[j] = point[j]; if(point[i]>=3.0*dd){ /* centered difference */ double e, em1, em2, ep1, ep2; p[i] = point[i] + dd; ep1 = get_point(func, p, &e, v, which); p[i] = point[i] + 2*dd; ep2 = get_point(func, p, &e, v, which); p[i] = point[i] - dd; /* backward point */ em1 = get_point(func, p, &e, v, which); p[i] = point[i] - 2*dd; /* backward point */ em2 = get_point(func, p, &e, v, which); der[i] = 1.0/2.0*(ep1 - em1); der[i] += 1.0/12.0*(em2 - 2*em1 + 2*ep1 - ep2); der[i] /= dd; }else{ /* we use a 5 point forward difference */ double e, e1, e2, e3, e4, e5; p[i] = point[i]; e1 = get_point(func, p, &e, v, which); p[i] = point[i] + dd; e2 = get_point(func, p, &e, v, which); p[i] = point[i] + 2.0*dd; e3 = get_point(func, p, &e, v, which); p[i] = point[i] + 3.0*dd; e4 = get_point(func, p, &e, v, which); p[i] = point[i] + 4.0*dd; e5 = get_point(func, p, &e, v, which); der[i] = (-e1 + e2); der[i] -= 1.0/2.0*( e1 - 2*e2 + e3); der[i] += 1.0/3.0*(-e1 + 3*e2 - 3*e3 + e4); der[i] -= 1.0/4.0*( e1 - 4*e2 + 6*e3 - 4*e4 + e5); der[i] /= dd; } } } void first_derivative_spinpaired(XC(func_type) *func, double point[7], double der[5], int which) { first_derivative(func, point, der, which, XC_UNPOLARIZED); } void first_derivative_spinpolarized(XC(func_type) *func, double point[7], double der[5], int which) { first_derivative(func, point, der, which, XC_POLARIZED); } void second_derivatives_spinpaired(XC(func_type) *func, double point[7], double der[5][5]) { int i; for(i=0; i<5; i++){ first_derivative_spinpaired(func, point, der[i], i+1); } } void second_derivatives_spinpolarized(XC(func_type) *func, double point[7], double der[5][5]) { int i; for(i=0; i<5; i++){ first_derivative_spinpolarized(func, point, der[i], i+1); } } /* a general call for a functional - finite difference */ void get_fxc_fd_spinpaired(XC(func_type) *func, double point[7], double der[5][5]) { second_derivatives_spinpaired(func, point, der); } /* a general call for a functional - finite difference */ void get_fxc_fd_spinpolarized(XC(func_type) *func, double point[7], double der[5][5]) { second_derivatives_spinpolarized(func, point, der); } static void lxcXCFunctional_dealloc(lxcXCFunctionalObject *self) { for (int i=0; i<2; i++) if (self->functional[i] != NULL) xc_func_end(self->functional[i]); PyObject_DEL(self); } static PyObject* lxcXCFunctional_is_gga(lxcXCFunctionalObject *self, PyObject *args) { int success = 0; /* assume functional is not GGA */ // check family of most-complex functional if (self->functional[0]->info->family == XC_FAMILY_GGA || self->functional[0]->info->family == XC_FAMILY_HYB_GGA) success = XC_FAMILY_GGA; return Py_BuildValue("i", success); } static PyObject* lxcXCFunctional_is_mgga(lxcXCFunctionalObject *self, PyObject *args) { int success = 0; /* assume functional is not MGGA */ // check family of most-complex functional if (self->functional[0]->info->family == XC_FAMILY_MGGA) success = XC_FAMILY_MGGA; return Py_BuildValue("i", success); } static PyObject* lxcXCFunctional_CalculateFXC_FD_SpinPaired(lxcXCFunctionalObject *self, PyObject *args) { PyArrayObject* n_array; /* rho */ PyArrayObject* v2rho2_array; /* d2E/drho2 */ PyArrayObject* a2_array = 0; /* |nabla rho|^2*/ PyArrayObject* v2rhosigma_array = 0; /* d2E/drhod|nabla rho|^2 */ PyArrayObject* v2sigma2_array = 0; /* d2E/drhod|nabla rho|^2 */ if (!PyArg_ParseTuple(args, "OO|OOO", &n_array, &v2rho2_array, /* object | optional objects*/ &a2_array, &v2rhosigma_array, &v2sigma2_array)) return NULL; /* find nspin */ int nspin = self->nspin; assert(nspin == XC_UNPOLARIZED); /* we are spinpaired */ assert (self->functional[0]->info->family != XC_FAMILY_MGGA); int ng = PyArray_DIMS(n_array)[0]; /* number of grid points */ const double* n_g = DOUBLEP(n_array); /* density on the grid */ double* v2rho2_g = DOUBLEP(v2rho2_array); /* v on the grid */ const double* a2_g = 0; /* a2 on the grid */ double* v2rhosigma_g = 0; /* d2Ednda2 on the grid */ double* v2sigma2_g = 0; /* d2Eda2da2 on the grid */ if ((self->functional[0]->info->family == XC_FAMILY_GGA) || (self->functional[0]->info->family == XC_FAMILY_HYB_GGA)) { a2_g = DOUBLEP(a2_array); v2rhosigma_g = DOUBLEP(v2rhosigma_array); v2sigma2_g = DOUBLEP(v2sigma2_array); } self->get_fxc = get_fxc_fd_spinpaired; /* ################################################################ */ for (int g = 0; g < ng; g++) { double n = n_g[g]; if (n < NMIN) n = NMIN; double a2 = 0.0; /* initialize for lda */ if ((self->functional[0]->info->family == XC_FAMILY_GGA) || (self->functional[0]->info->family == XC_FAMILY_HYB_GGA)) { a2 = a2_g[g]; } double point[7]; /* generalized point */ // from http://www.tddft.org/programs/octopus/wiki/index.php/Libxc:manual // rhoa rhob sigmaaa sigmaab sigmabb taua taub // \sigma[0] = \nabla n_\uparrow \cdot \nabla n_\uparrow \qquad // \sigma[1] = \nabla n_\uparrow \cdot \nabla n_\downarrow \qquad // \sigma[2] = \nabla n_\downarrow \cdot \nabla n_\downarrow \qquad double derivative[5][5]; /* generalized derivative */ double v2rho2[3]; double v2rhosigma[6]; double v2sigma2[6]; // one that uses this: please add description of spin derivative order notation // (see c/libxc/src/gga_perdew.c) MDTMP for(int i=0; i<3; i++) v2rho2[i] = 0.0; for(int i=0; i<6; i++){ v2rhosigma[i] = 0.0; v2sigma2[i] = 0.0; } for(int j=0; j<7; j++) { point[j] = 0.0; } for(int i=0; i<5; i++) { for(int j=0; j<5; j++) { derivative[i][j] = 0.0; } } point[0] = n; /* -> rho */ point[2] = a2; /* -> sigma */ for (int i=0; i<2; i++) { XC(func_type) *func = self->functional[i]; if (func == NULL) continue; self->get_fxc(func, point, derivative); v2rho2[0] = derivative[0][0]; v2rho2[1] = derivative[0][1]; // XC_POLARIZED v2rho2[2] = derivative[1][1]; // XC_POLARIZED v2rhosigma[0] = derivative[0][2]; v2rhosigma[1] = derivative[0][3]; // XC_POLARIZED v2rhosigma[2] = derivative[0][4]; // XC_POLARIZED v2rhosigma[3] = derivative[1][2]; // XC_POLARIZED v2rhosigma[4] = derivative[1][3]; // XC_POLARIZED v2rhosigma[5] = derivative[1][4]; // XC_POLARIZED v2sigma2[0] = derivative[2][2]; /* aa_aa */ v2sigma2[1] = derivative[2][3]; // XC_POLARIZED /* aa_ab */ v2sigma2[2] = derivative[2][4]; // XC_POLARIZED /* aa_bb */ v2sigma2[3] = derivative[3][3]; // XC_POLARIZED /* ab_ab */ v2sigma2[4] = derivative[3][4]; // XC_POLARIZED /* ab_bb */ v2sigma2[5] = derivative[4][4]; // XC_POLARIZED /* bb_bb */ switch(func->info->family) { case XC_FAMILY_HYB_GGA: case XC_FAMILY_GGA: v2rhosigma_g[g] += v2rhosigma[0]; v2sigma2_g[g] += v2sigma2[0]; // don't break here since we need LDA values as well case XC_FAMILY_LDA: v2rho2_g[g] += v2rho2[0]; } } } Py_RETURN_NONE; } // Below are changes made by cpo@slac.stanford.edu for libxc 1.2.0 // which allows passing of arrays of points to libxc routines. // The fundamental design idea (to try to minimize code-duplication) is that // all libxc routines have input/output arrays that get processed in // common ways with three special exceptions: n_sg, e_g, dedn_sg. The // struct "xcptrlist" is used to keep track of these pointers. // Two libxc features prevent us from using a straightforward // interface: // 1) libxc calls memset(0) on output arrays, preventing us // from adding x/c contributions "in place" without scratch arrays // 2) for spin-polarized calculations libxc wants spin indices to be // dense in memory, whereas GPAW probably loops over grid indices // more often, so we want to keep those dense in memory. // I asked Miguel Marques to remove the memset, and to add a "stride" // argument to libxc routines to address the above. He says he will // consider it in the future. In the meantime we have to "block" // over gridpoints using some scratch memory. // What is supported: // - combined xc-functional mode // - separate x,c functionals. // - separate x,c can have differing complexities (e.g. one GGA, one LDA) // - "exc_vxc" style routines for LDA/GGA/MGGA both unpolarized/polarized // - "fxc" style routines for LDA/GGA both unpolarized/polarized // To support a libxc routine other than exc_vxc/fxc one needs to // copy a "Calculate" routine and change the pointer list setup, and // associated libxc function calls. // number of gridpoints we will "block" over when doing xc calculation #define BLOCKSIZE 1024 // this is the maximum number of BLOCKSIZE arrays that will be put // into scratch (depends on the "spinsize" values for the various // arrays. currently determined by fxc, which has input spinsizes // of 2+3 and output spinsizes of 3+6+6 (totalling 20). #define MAXARRAYS 20 #define LIBXCSCRATCHSIZE (BLOCKSIZE*MAXARRAYS) static double *scratch=NULL; // we don't use lapl, but libxc needs space for them. static double *scratch_lapl=NULL; static double *scratch_vlapl=NULL; // special cases for array behaviors: // flag to indicate we need to add to existing values for dedn_sg #define DEDN_SG 1 // flag to indicate we need to apply NMIN cutoff to n_sg #define N_SG 2 // flag to indicate we need to multiply by density for e_g #define E_G 4 typedef struct xcptr { double *p; int special; int spinsize; } xcptr; #define MAXPTR 10 typedef struct xcptrlist { int num; xcptr p[MAXPTR]; } xcptrlist; typedef struct xcinfo { int nspin; bool spinpolarized; int ng; } xcinfo; // these 3 functions make the spin index closest in memory ("gather") or the // farthest apart in memory ("scatter"). "scatteradd" adds to previous results. static void gather(const double* src, double* dst, int np, int stride, int nspins) { const double *dstend = dst+np*nspins; const double *srcend = src+nspins*stride; do { const double *s = src; do { *dst++ = *s; s+=stride; } while (snum; i++) { inblocklist[i] = next; next+=blocksize*inlist->p[i].spinsize; } for (int i=0; inum; i++) { outblocklist[i] = next; next+=blocksize*outlist->p[i].spinsize; } // check that we fit in the scratch space // if we don't, then we need to increase MAXARRAY assert((next - scratch) <= LIBXCSCRATCHSIZE); } // copy a piece of the full data into the block for processing by libxc static void data2block(const xcinfo *info, const xcptrlist *inlist, double *inblocklist[], int blocksize) { // copy data into the block, taking into account special cases for (int i=0; inum; i++) { double *ptr = inlist->p[i].p; double* block = inblocklist[i]; if (info->spinpolarized) { gather(ptr,block,blocksize,info->ng,inlist->p[i].spinsize); if (inlist->p[i].special&N_SG) for (int i=0; ip[i].special&N_SG) for (int i=0; inum; i++) { double *ptr = outlist->p[i].p; double* block = outblocklist[i]; if (outlist->p[i].special&E_G) { if (info->spinpolarized) { for (int i=0; ip[i].special&DEDN_SG) { if (info->spinpolarized) { scatteradd(block,ptr,blocksize,info->ng,outlist->p[i].spinsize); // need to add to pre-existing values } else { for (int i=0; ispinpolarized) { scatter(block,ptr,blocksize,info->ng,outlist->p[i].spinsize); } else { memcpy(ptr,block,blocksize*sizeof(double)); } } } } // copy the data from the block back into its final resting place, but add to previous results static void block2dataadd(const xcinfo *info, double *outblocklist[], const xcptrlist *outlist, const double *n_sg, int blocksize, int noutcopy) { for (int i=0; ip[i].p; double* block = outblocklist[i]; if (outlist->p[i].special&E_G) { if (info->spinpolarized) { for (int i=0; ispinpolarized) { scatteradd(block,ptr,blocksize,info->ng,outlist->p[i].spinsize); } else { for (int i=0; inspin; info.spinpolarized = (info.nspin==2); info.ng = PyArray_DIMS(py_e_g)[0]; xcptrlist inlist,outlist; inlist.num=0; outlist.num=0; int blocksize = BLOCKSIZE; int remaining = info.ng; // setup pointers using most complex functional switch(self->functional[0]->info->family) { case XC_FAMILY_MGGA: inlist.p[2].p = DOUBLEP(py_tau_sg); inlist.p[2].special = 0; inlist.p[2].spinsize = 2; inlist.num++; outlist.p[3].p = DOUBLEP(py_dedtau_sg); outlist.p[3].special = 0; outlist.p[3].spinsize = 2; outlist.num++; // don't break here since MGGA also needs GGA ptrs case XC_FAMILY_HYB_GGA: case XC_FAMILY_GGA: inlist.p[1].p = DOUBLEP(py_sigma_xg); inlist.p[1].special = 0; inlist.p[1].spinsize = 3; inlist.num++; outlist.p[2].p = DOUBLEP(py_dedsigma_xg); outlist.p[2].special = 0; outlist.p[2].spinsize = 3; outlist.num++; // don't break here since GGA also needs LDA ptrs case XC_FAMILY_LDA: inlist.p[0].p = DOUBLEP(py_n_sg); inlist.p[0].special = N_SG; inlist.p[0].spinsize = 2; inlist.num += 1; outlist.p[0].p = DOUBLEP(py_e_g); outlist.p[0].special = E_G; outlist.p[0].spinsize = 1; outlist.p[1].p = DOUBLEP(py_dedn_sg); outlist.p[1].special = DEDN_SG; outlist.p[1].spinsize = 2; outlist.num += 2; } assert(inlist.num < MAXPTR); assert(outlist.num < MAXPTR); double *inblock[MAXPTR]; double *outblock[MAXPTR]; setupblockptrs(&info, &inlist, &outlist, &inblock[0], &outblock[0], blocksize); do { blocksize = blocksizefunctional[i] == NULL) continue; XC(func_type) *func = self->functional[i]; int noutcopy=0; switch(func->info->family) { case XC_FAMILY_LDA: xc_lda_exc_vxc(func, blocksize, n_sg, e_g, dedn_sg); noutcopy = 2; // potentially decrease the size for block2dataadd if second functional less complex. break; case XC_FAMILY_HYB_GGA: case XC_FAMILY_GGA: xc_gga_exc_vxc(func, blocksize, n_sg, sigma_xg, e_g, dedn_sg, dedsigma_xg); noutcopy = 3; // potentially decrease the size for block2dataadd if second functional less complex. break; case XC_FAMILY_MGGA: xc_mgga_exc_vxc(func, blocksize, n_sg, sigma_xg, scratch_lapl, tau_sg, e_g, dedn_sg, dedsigma_xg, scratch_vlapl, dedtau_sg); noutcopy = 4; // potentially decrease the size for block2dataadd if second functional less complex. break; } // if we have more than 1 functional, add results // canonical example: adding "x" results to "c" if (i==0) block2data(&info, &outblock[0], &outlist, n_sg, blocksize); else block2dataadd(&info, &outblock[0], &outlist, n_sg, blocksize, noutcopy); } for (int i=0; i0); Py_RETURN_NONE; } static PyObject* lxcXCFunctional_CalculateFXC(lxcXCFunctionalObject *self, PyObject *args) { PyArrayObject* py_n_sg=NULL; PyArrayObject* py_v2rho2_xg=NULL; PyArrayObject* py_sigma_xg=NULL; PyArrayObject* py_v2rhosigma_yg=NULL; PyArrayObject* py_v2sigma2_yg=NULL; if (!PyArg_ParseTuple(args, "OO|OOO", &py_n_sg, &py_v2rho2_xg, &py_sigma_xg, &py_v2rhosigma_yg, &py_v2sigma2_yg)) return NULL; xcinfo info; info.nspin = self->nspin; info.spinpolarized = (info.nspin==2); info.ng = (info.spinpolarized) ? PyArray_DIMS(py_n_sg)[0]/2 : PyArray_DIMS(py_n_sg)[0]; xcptrlist inlist,outlist; inlist.num=0; outlist.num=0; int blocksize = BLOCKSIZE; int remaining = info.ng; // setup pointers using most complex functional switch(self->functional[0]->info->family) { case XC_FAMILY_MGGA: // not supported assert(self->functional[0]->info->family != XC_FAMILY_MGGA); // don't break here since MGGA also needs GGA ptrs case XC_FAMILY_HYB_GGA: case XC_FAMILY_GGA: inlist.p[1].p = DOUBLEP(py_sigma_xg); inlist.p[1].special = 0; inlist.p[1].spinsize = 3; inlist.num++; outlist.p[1].p = DOUBLEP(py_v2rhosigma_yg); outlist.p[1].special = 0; outlist.p[1].spinsize = 6; outlist.p[2].p = DOUBLEP(py_v2sigma2_yg); outlist.p[2].special = 0; outlist.p[2].spinsize = 6; outlist.num+=2; // don't break here since GGA also needs LDA ptrs case XC_FAMILY_LDA: inlist.p[0].p = DOUBLEP(py_n_sg); inlist.p[0].special = N_SG; inlist.p[0].spinsize = 2; inlist.num += 1; outlist.p[0].p = DOUBLEP(py_v2rho2_xg); outlist.p[0].special = 0; outlist.p[0].spinsize = 3; outlist.num++; } assert(inlist.num < MAXPTR); assert(outlist.num < MAXPTR); double *inblock[MAXPTR]; double *outblock[MAXPTR]; setupblockptrs(&info, &inlist, &outlist, &inblock[0], &outblock[0], blocksize); do { blocksize = blocksizefunctional[i] == NULL) continue; XC(func_type) *func = self->functional[i]; int noutcopy=0; switch(func->info->family) { case XC_FAMILY_LDA: xc_lda_fxc(func, blocksize, n_sg, v2rho2); noutcopy = 1; // potentially decrease the size for block2dataadd if second functional less complex. break; case XC_FAMILY_HYB_GGA: case XC_FAMILY_GGA: xc_gga_fxc(func, blocksize, n_sg, sigma_xg, v2rho2, v2rhosigma, v2sigma2); noutcopy = 3; // potentially decrease the size for block2dataadd if second functional less complex. break; case XC_FAMILY_MGGA: // not supported by GPAW yet, so crash assert (func->info->family!=XC_FAMILY_MGGA); break; } // if we have more than 1 functional, add results // canonical example: adding "x" results to "c" if (i==0) block2data(&info, &outblock[0], &outlist, n_sg, blocksize); else block2dataadd(&info, &outblock[0], &outlist, n_sg, blocksize, noutcopy); } for (int i=0; i0); Py_RETURN_NONE; } static PyObject* lxcXCFunctional_tb09(lxcXCFunctionalObject *self, PyObject *args) { double c; PyArrayObject* n_g; PyArrayObject* sigma_g; PyArrayObject* lapl_g; PyArrayObject* tau_g; PyArrayObject* v_g; PyArrayObject* vx_g; // for vsigma, vtau, vlapl if (!PyArg_ParseTuple(args, "dOOOOOO", &c, &n_g, &sigma_g, &lapl_g, &tau_g, &v_g, &vx_g)) return NULL; xc_mgga_x_tb09_set_params(self->functional[0], c); xc_mgga_vxc(self->functional[0], PyArray_DIM(n_g, 0), PyArray_DATA(n_g), PyArray_DATA(sigma_g), PyArray_DATA(lapl_g), PyArray_DATA(tau_g), PyArray_DATA(v_g), PyArray_DATA(vx_g), PyArray_DATA(vx_g), PyArray_DATA(vx_g)); Py_RETURN_NONE; } static PyMethodDef lxcXCFunctional_Methods[] = { {"is_gga", (PyCFunction)lxcXCFunctional_is_gga, METH_VARARGS, 0}, {"is_mgga", (PyCFunction)lxcXCFunctional_is_mgga, METH_VARARGS, 0}, {"calculate_fxc_fd_spinpaired", (PyCFunction)lxcXCFunctional_CalculateFXC_FD_SpinPaired, METH_VARARGS, 0}, {"calculate", (PyCFunction)lxcXCFunctional_Calculate, METH_VARARGS, 0}, {"calculate_fxc_spinpaired", (PyCFunction)lxcXCFunctional_CalculateFXC, METH_VARARGS, 0}, {"tb09", (PyCFunction)lxcXCFunctional_tb09, METH_VARARGS, 0}, {NULL, NULL, 0, NULL} }; PyTypeObject lxcXCFunctionalType = { PyVarObject_HEAD_INIT(NULL, 0) "lxcXCFunctional", sizeof(lxcXCFunctionalObject), 0, (destructor)lxcXCFunctional_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, "LibXCFunctional object", 0, 0, 0, 0, 0, 0, lxcXCFunctional_Methods }; PyObject * NewlxcXCFunctionalObject(PyObject *obj, PyObject *args) { int xc, x, c; /* functionals identifier number */ int nspin; /* XC_UNPOLARIZED or XC_POLARIZED */ if (!scratch) { scratch = (double*)malloc(LIBXCSCRATCHSIZE*sizeof(double)); const int laplsize = BLOCKSIZE*sizeof(double)*2; scratch_lapl = (double*)malloc(laplsize); memset(scratch_lapl,0,laplsize); scratch_vlapl = (double*)malloc(laplsize); } if (!PyArg_ParseTuple(args, "iiii", &xc, &x, &c, &nspin)) { return NULL; } /* checking if the numbers xc x c are valid is done at python level */ lxcXCFunctionalObject *self = PyObject_NEW(lxcXCFunctionalObject, &lxcXCFunctionalType); if (self == NULL){ return NULL; } assert(nspin==XC_UNPOLARIZED || nspin==XC_POLARIZED); self->nspin = nspin; /* must be common to x and c, so declared redundantly */ int number,family,familyx,familyc; if (xc != -1) { xc_family_from_id(xc,&family,&number); assert (family != XC_FAMILY_UNKNOWN); XC(func_init)(&self->xc_functional, xc, nspin); self->functional[0]=&self->xc_functional; self->functional[1]=NULL; } else { assert (x!=-1 || c!=-1); if (x!=-1) { xc_family_from_id(x,&familyx,&number); assert (familyx != XC_FAMILY_UNKNOWN); XC(func_init)(&self->x_functional, x, nspin); } if (c!=-1) { xc_family_from_id(c,&familyc,&number); assert (familyc != XC_FAMILY_UNKNOWN); XC(func_init)(&self->c_functional, c, nspin); } if (x!=-1 && c!=-1) { /* put most complex functional first */ /* important for later loops over functionals */ if (familyx == XC_FAMILY_MGGA) { self->functional[0]=&self->x_functional; self->functional[1]=&self->c_functional; } else if (familyc == XC_FAMILY_MGGA) { self->functional[0]=&self->c_functional; self->functional[1]=&self->x_functional; } else if (familyx == XC_FAMILY_GGA || familyx == XC_FAMILY_HYB_GGA) { self->functional[0]=&self->x_functional; self->functional[1]=&self->c_functional; } else { // either c is GGA, or both are LDA (so don't care) self->functional[0]=&self->c_functional; self->functional[1]=&self->x_functional; } } else if (x!=-1) { self->functional[0]=&self->x_functional; self->functional[1]=NULL; } else if (c!=-1) { self->functional[0]=&self->c_functional; self->functional[1]=NULL; } } return (PyObject*)self; } PyObject * lxcXCFuncNum(PyObject *obj, PyObject *args) { char *funcname; if (!PyArg_ParseTuple(args, "s", &funcname)) { return NULL; } int num = XC(functional_get_number)(funcname); if (num != -1) return Py_BuildValue("i",num); else Py_RETURN_NONE; } gpaw-0.11.0.13004/c/xc/revtpss.c0000664000175000017500000004015512553643466016174 0ustar jensjjensj00000000000000 #include #include #include #include #include "xc_mgga.h" typedef struct revtpss_params { common_params common; // needs to be at the beginning of every functional_params XC(func_type) *x_aux; XC(func_type) c_aux1; XC(func_type) c_aux2; } revtpss_params; void gga_c_pbe_revtpss(XC(func_type) *p, const double *rho, const double *sigma, double *e, double *vrho, double *vsigma, double *v2rho2, double *v2rhosigma, double *v2sigma2); /************************************************************************ Implements John P. Perdew, Adrienn Ruzsinszky, Gabor I. Csonka, Lucian A. Constantin, and Jianwei Sun meta-Generalized Gradient Approximation. Correlation part ************************************************************************/ /* some parameters */ static double d = 2.8; /* Equation (14) */ static void c_revtpss_14(double csi, double zeta, double *C, double *dCdcsi, double *dCdzeta) { double fz, C0, dC0dz, dfzdz; double z2 = zeta*zeta; /* Equation (13) */ C0 = 0.59 + z2*(0.9269 + z2*(0.6225 + z2*2.1540)); dC0dz = zeta*(2.0*0.9269 + z2*(4.0*0.6225 + z2*6.0*2.1540)); /*OK*/ fz = 0.5*(pow(1.0 + zeta, -4.0/3.0) + pow(1.0 - zeta, -4.0/3.0)); dfzdz = 0.5*(-4.0/3.0)*(pow(1.0 + zeta, -7.0/3.0) - pow(1.0 - zeta, -7.0/3.0)); /*OK*/ { /* Equation (14) */ double csi2 = csi*csi; double a = 1.0 + csi2*fz, a4 = pow(a, 4); *C = C0 / a4; *dCdcsi = -8.0*C0*csi*fz/(a*a4); /*added C OK*/ *dCdzeta = (dC0dz*a - C0*4.0*csi2*dfzdz)/(a*a4); /*OK*/ } } /* Equation (12) */ static void c_revtpss_12(revtpss_params *p, const double *rho, const double *sigma, double dens, double zeta, double z, double *e_PKZB, double *de_PKZBdd, double *de_PKZBdsigma, double *de_PKZBdz) { /*some incoming variables: dens = rho[0] + rho[1] z = tau_w/tau zeta = (rho[0] - rho[1])/dens*/ double e_PBE, e_PBEup, e_PBEdn; double de_PBEdd[2], de_PBEdsigma[3], de_PBEddup[2], de_PBEdsigmaup[3], de_PBEdddn[2], de_PBEdsigmadn[3] ; double aux, zsq; double dzetadd[2], dcsidd[2], dcsidsigma[3]; double C, dCdcsi, dCdzeta; double densp[2], densp2[2], sigmatot[3], sigmaup[3], sigmadn[3]; int i; /*initialize dCdcsi and dCdzeta and the energy*/ dCdcsi = dCdzeta = 0.0; e_PBE = 0.0; e_PBEup = 0.0; e_PBEdn = 0.0; /* get the PBE stuff */ if(p->common.nspin== XC_UNPOLARIZED) { densp[0]=rho[0]/2.; densp[1]=rho[0]/2.; sigmatot[0] = sigma[0]/4.; sigmatot[1] = sigma[0]/4.; sigmatot[2] = sigma[0]/4.; }else{ densp[0] = rho[0]; densp[1] = rho[1]; sigmatot[0] = sigma[0]; sigmatot[1] = sigma[1]; sigmatot[2] = sigma[2]; } /* e_PBE */ XC(func_type) *aux2 = (p->common.nspin == XC_UNPOLARIZED) ? &p->c_aux2 : &p->c_aux1; gga_c_pbe_revtpss(aux2, densp, sigmatot, &e_PBE, de_PBEdd, de_PBEdsigma, NULL, NULL, NULL); densp2[0]=densp[0]; densp2[1]=0.0; if(p->common.nspin== XC_UNPOLARIZED) { sigmaup[0] = sigma[0]/4.; sigmaup[1] = 0.; sigmaup[2] = 0.; }else{ sigmaup[0] = sigma[0]; sigmaup[1] = 0.; sigmaup[2] = 0.; } /* e_PBE spin up */ gga_c_pbe_revtpss(aux2, densp2, sigmaup, &e_PBEup, de_PBEddup, de_PBEdsigmaup, NULL, NULL, NULL); densp2[0]=densp[1]; densp2[1]=0.0; if(p->common.nspin== XC_UNPOLARIZED) { sigmadn[0] = sigma[0]/4.; sigmadn[1] = 0.; sigmadn[2] = 0.; }else{ sigmadn[0] = sigma[2]; sigmadn[1] = 0.; sigmadn[2] = 0.; } /* e_PBE spin down */ gga_c_pbe_revtpss(aux2, densp2, sigmadn, &e_PBEdn, de_PBEdddn, de_PBEdsigmadn, NULL, NULL, NULL); /*get Eq. (13) and (14) for the polarized case*/ if(p->common.nspin == XC_UNPOLARIZED){ C = 0.59; dzetadd[0] = 0.0; dcsidd [0] = 0.0; dzetadd[1] = 0.0; dcsidd [1] = 0.0; for(i=0; i<3; i++) dcsidsigma[i] = 0.0; }else{ // initialize derivatives for(i=0; i<2; i++){ dzetadd[i] = 0.0; dcsidd [i] = 0.0;} for(i=0; i<3; i++) dcsidsigma[i] = 0.0; double num, gzeta, csi, a; /*numerator of csi: derive as grho all components and then square the 3 parts [2 (grho_a[0]n_b - grho_b[0]n_a) +2 (grho_a[1]n_b - grho_b[1]n_a) + 2 (grho_a[2]n_b - grho_b[2]n_a)]/(n_a+n_b)^2 -> 4 (sigma_aa n_b^2 - 2 sigma_ab n_a n_b + sigma_bb n_b^2)/(n_a+n_b)^2 */ num = sigma[0] * pow(rho[1],2) - 2.* sigma[1]*rho[0]*rho[1]+ sigma[2]*pow(rho[0],2); num = max(num, 1e-20); gzeta = sqrt(4*(num))/(dens*dens); gzeta = max(gzeta, MIN_GRAD); /*denominator of csi*/ a = 2*pow(3.0*M_PI*M_PI*dens, 1.0/3.0); csi = gzeta/a; c_revtpss_14(csi, zeta, &C, &dCdcsi, &dCdzeta); dzetadd[0] = (1.0 - zeta)/dens; /*OK*/ dzetadd[1] = -(1.0 + zeta)/dens; /*OK*/ dcsidd [0] = 0.5*csi*(-2*sigma[1]*rho[1]+2*sigma[2]*rho[0])/num - 7./3.*csi/dens; /*OK*/ dcsidd [1] = 0.5*csi*(-2*sigma[1]*rho[0]+2*sigma[0]*rho[1])/num - 7./3.*csi/dens; /*OK*/ dcsidsigma[0]= csi*pow(rho[1],2)/(2*num); /*OK*/ dcsidsigma[1]= -csi*rho[0]*rho[1]/num; /*OK*/ dcsidsigma[2]= csi*pow(rho[0],2)/(2*num); /*OK*/ } aux = (densp[0] * max(e_PBEup, e_PBE) + densp[1] * max(e_PBEdn, e_PBE)) / dens; double dauxdd[2], dauxdsigma[3]; if(e_PBEup > e_PBE) { //case densp[0] * e_PBEup dauxdd[0] = de_PBEddup[0]; dauxdd[1] = 0.0; dauxdsigma[0] = de_PBEdsigmaup[0]; dauxdsigma[1] = 0.0; dauxdsigma[2] = 0.0; }else{ //case densp[0] * e_PBE dauxdd[0] = densp[0] / dens * (de_PBEdd[0] - e_PBE) + e_PBE; dauxdd[1] = densp[0] / dens * (de_PBEdd[1] - e_PBE); dauxdsigma[0] = densp[0] / dens * de_PBEdsigma[0]; dauxdsigma[1] = densp[0] / dens * de_PBEdsigma[1]; dauxdsigma[2] = densp[0] / dens * de_PBEdsigma[2]; } if(e_PBEdn > e_PBE) {//case densp[1] * e_PBEdn dauxdd[0] += 0.0; dauxdd[1] += de_PBEdddn[0]; dauxdsigma[0] += 0.0; dauxdsigma[1] += 0.0; dauxdsigma[2] += de_PBEdsigmadn[0]; }else{//case densp[1] * e_PBE dauxdd[0] += densp[1] / dens * (de_PBEdd[0] - e_PBE); dauxdd[1] += densp[1] / dens * (de_PBEdd[1] - e_PBE) + e_PBE; dauxdsigma[0] += densp[1] / dens * de_PBEdsigma[0]; dauxdsigma[1] += densp[1] / dens * de_PBEdsigma[1]; dauxdsigma[2] += densp[1] / dens * de_PBEdsigma[2]; } zsq=z*z; *e_PKZB = (e_PBE*(1.0 + C * zsq) - (1.0 + C) * zsq * aux); *de_PKZBdz = dens * e_PBE * C * 2*z - dens * (1.0 + C) * 2*z * aux; /*? think ok*/ double dCdd[2]; dCdd[0] = dCdzeta*dzetadd[0] + dCdcsi*dcsidd[0]; /*OK*/ dCdd[1] = dCdzeta*dzetadd[1] + dCdcsi*dcsidd[1]; /*OK*/ /* partial derivatives*/ de_PKZBdd[0] = de_PBEdd[0] * (1.0 + C*zsq) + dens * e_PBE * dCdd[0] * zsq - zsq * (dens*dCdd[0] * aux + (1.0 + C) * dauxdd[0]); de_PKZBdd[1] = de_PBEdd[1] * (1.0 + C*zsq) + dens * e_PBE * dCdd[1] * zsq - zsq * (dens*dCdd[1] * aux + (1.0 + C) * dauxdd[1]); int nder = (p->common.nspin==XC_UNPOLARIZED) ? 1 : 3; for(i=0; icommon.nspin==XC_UNPOLARIZED) dauxdsigma[i] /= 2.; double dCdsigma[i]; dCdsigma[i]= dCdcsi*dcsidsigma[i]; /* partial derivatives*/ de_PKZBdsigma[i] = de_PBEdsigma[i] * (1.0 + C * zsq) + dens * e_PBE * dCdsigma[i] * zsq - zsq * (dens * dCdsigma[i] * aux + (1.0 + C) * dauxdsigma[i]); } } static void XC(mgga_c_revtpss)(void *par, const double *rho, const double *sigmatmp, const double *tau, double *energy, double *dedd, double *vsigma, double *dedtau) { double sigma[3]; revtpss_params *p = (revtpss_params*)par; double dens, zeta, grad; double tautr, taut, tauw, z; double e_PKZB, de_PKZBdd[2], de_PKZBdsigma[3], de_PKZBdz; int i, is; sigma[0] = sigmatmp[0]; sigma[1] = sigmatmp[1]; sigma[2] = sigmatmp[2]; zeta = (rho[0]-rho[1])/(rho[0]+rho[1]); dens = rho[0]; tautr = tau[0]; grad = sigma[0]; if(p->common.nspin == XC_POLARIZED) { dens += rho[1]; tautr += tau[1]; grad += (2*sigma[1] + sigma[2]); } grad = max(MIN_GRAD*MIN_GRAD, grad); tauw = max(grad/(8.0*dens), 1.0e-12); taut = max(tautr, tauw); z = tauw/taut; sigma[0] = max(MIN_GRAD*MIN_GRAD, sigma[0]); if(p->common.nspin == XC_POLARIZED) { //sigma[1] = max(MIN_GRAD*MIN_GRAD, sigma[1]); sigma[2] = max(MIN_GRAD*MIN_GRAD, sigma[2]); } /* Equation (12) */ c_revtpss_12(p, rho, sigma, dens, zeta, z, &e_PKZB, de_PKZBdd, de_PKZBdsigma, &de_PKZBdz); /* Equation (11) */ { double z2 = z*z, z3 = z2*z; double dedz; double dzdd[2], dzdsigma[3], dzdtau; if(tauw >= tautr || fabs(tauw- tautr)< 1.0e-10){ dzdtau = 0.0; dzdd[0] = 0.0; dzdd[1] = 0.0; dzdsigma[0] = 0.0; dzdsigma[1] = 0.0; dzdsigma[2] = 0.0; }else{ dzdtau = -z/taut; dzdd[0] = - z/dens; dzdd[1] = 0.0; if (p->common.nspin == XC_POLARIZED) dzdd[1] = - z/dens; dzdsigma[0] = 1.0/(8*dens*taut); dzdsigma[1] = 0.0; dzdsigma[2] = 0.0; if (p->common.nspin == XC_POLARIZED) { dzdsigma[1] = 2.0/(8*dens*taut); dzdsigma[2] = 1.0/(8*dens*taut); } } *energy = e_PKZB * (1.0 + d*e_PKZB*z3); /* due to the definition of na and nb in libxc.c we need to divide by (na+nb) to recover the * same energy for polarized and unpolarized calculation with the same total density */ if(p->common.nspin == XC_UNPOLARIZED) *energy *= dens/(rho[0]+rho[1]); dedz = de_PKZBdz*(1.0 + 2.0*d*e_PKZB*z3) + dens*e_PKZB * e_PKZB * d * 3.0*z2; for(is=0; iscommon.nspin; is++){ dedd[is] = de_PKZBdd[is] * (1.0 + 2.0*d*e_PKZB*z3) + dedz*dzdd[is] - e_PKZB*e_PKZB * d * z3; /*OK*/ dedtau[is] = dedz * dzdtau; /*OK*/ } int nder = (p->common.nspin==XC_UNPOLARIZED) ? 1 : 3; for(i=0; ix_aux, np, rho, &exunif, &vxunif); /* calculate |nabla rho|^2 */ gdms = max(MIN_GRAD*MIN_GRAD, sigma); /* Eq. (4) */ p = gdms/(4.0*pow(3*M_PI*M_PI, 2.0/3.0)*pow(rho[0], 8.0/3.0)); dpdd = -(8.0/3.0)*p/rho[0]; dpdsigma= 1/(4.0*pow(3*M_PI*M_PI, 2.0/3.0)*pow(rho[0], 8.0/3.0)); /* von Weisaecker kinetic energy density */ tauw = max(gdms/(8.0*rho[0]), 1.0e-12); tau = max(tau_, tauw); tau_lsda = aux * pow(rho[0],5./3.); dtau_lsdadd = aux * 5./3.* pow(rho[0],2./3.); alpha = (tau - tauw)/tau_lsda; if(fabs(tauw-tau_)< 1.0e-10){ dalphadsigma = 0.0; dalphadtau = 0.0; dalphadd = 0.0; }else{ dalphadtau = 1./tau_lsda; dalphadsigma = -1./(tau_lsda*8.0*rho[0]); dalphadd = (tauw/rho[0]* tau_lsda - (tau - tauw) * dtau_lsdadd)/ pow(tau_lsda,2.); } /* get Eq. (10) */ x_revtpss_10(p, alpha, &x, &dxdp, &dxdalpha); { /* Eq. (5) */ double a = kappa/(kappa + x); Fx = 1.0 + kappa*(1.0 - a); dFxdx = a*a; } { /* Eq. (3) */ *energy = exunif*Fx*rho[0]; //printf("Ex %.9e\n", *energy); /* exunif is en per particle already so we multiply by n the terms with exunif*/ *dedd = vxunif*Fx + exunif*dFxdx*rho[0]*(dxdp*dpdd + dxdalpha*dalphadd); *vsigma = exunif*dFxdx*rho[0]*(dxdp*dpdsigma + dxdalpha*dalphadsigma); *dedtau = exunif*dFxdx*rho[0]*(dxdalpha*dalphadtau); } } void XC(mgga_x_revtpss)(void *par, const double *rho, const double *sigma, const double *tau, double *e, double *dedd, double *vsigma, double *dedtau) { revtpss_params *p = (revtpss_params*)par; if(p->common.nspin == XC_UNPOLARIZED){ double en; x_revtpss_para(p, rho, sigma[0], tau[0], &en, dedd, vsigma, dedtau); *e = en/(rho[0]+rho[1]); }else{ /* The spin polarized version is handle using the exact spin scaling Ex[n1, n2] = (Ex[2*n1] + Ex[2*n2])/2 */ *e = 0.0; double e2na, e2nb, rhoa[2], rhob[2]; double vsigmapart[3]; rhoa[0]=2*rho[0]; rhoa[1]=0.0; rhob[0]=2*rho[1]; rhob[1]=0.0; x_revtpss_para(p, rhoa, 4*sigma[0], 2.0*tau[0], &e2na, &(dedd[0]), &(vsigmapart[0]), &(dedtau[0])); x_revtpss_para(p, rhob, 4*sigma[2], 2.0*tau[1], &e2nb, &(dedd[1]), &(vsigmapart[2]), &(dedtau[1])); *e = (e2na + e2nb )/(2.*(rho[0]+rho[1])); vsigma[0] = 2*vsigmapart[0]; vsigma[2] = 2*vsigmapart[2]; } } static void revtpss_init(void *p) { revtpss_params *par = (revtpss_params*)p; par->x_aux = (XC(func_type) *) malloc(sizeof(XC(func_type))); XC(func_init)(par->x_aux, XC_LDA_X, XC_UNPOLARIZED); XC(func_init)(&par->c_aux1, XC_LDA_C_PW_MOD, par->common.nspin); XC(func_init)(&par->c_aux2, XC_LDA_C_PW_MOD, XC_POLARIZED); } static void revtpss_end(void *p) { revtpss_params *par = (revtpss_params*)p; XC(func_end)(par->x_aux); free(par->x_aux); XC(func_end)(&par->c_aux1); XC(func_end)(&par->c_aux2); } const mgga_func_info revtpss_info = { sizeof(revtpss_params), &revtpss_init, &revtpss_end, &XC(mgga_x_revtpss), &XC(mgga_c_revtpss) }; gpaw-0.11.0.13004/c/xc/xc.c0000664000175000017500000002135012553643466015074 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2009 CAMd * Please see the accompanying LICENSE file for further information. */ #include #define PY_ARRAY_UNIQUE_SYMBOL GPAW_ARRAY_API #define NO_IMPORT_ARRAY #include #include "xc_gpaw.h" #include "../extensions.h" // // __ 2 // a2 = |\/n| // // dE // dedrs = --- // dr // s // // dE // deda2 = --------- // __ 2 // d(|\/n| ) // void init_mgga(void** params, int code, int nspin); void calc_mgga(void** params, int nspin, int ng, const double* n_g, const double* sigma_g, const double* tau_g, double *e_g, double *v_g, double *dedsigma_g, double *dedtau_g); double pbe_exchange(const xc_parameters* par, double n, double rs, double a2, double* dedrs, double* deda2); double pbe_correlation(double n, double rs, double zeta, double a2, bool gga, bool spinpol, double* dedrs, double* dedzeta, double* deda2); double pw91_exchange(const xc_parameters* par, double n, double rs, double a2, double* dedrs, double* deda2); double pw91_correlation(double n, double rs, double zeta, double a2, bool gga, bool spinpol, double* dedrs, double* dedzeta, double* deda2); double rpbe_exchange(const xc_parameters* par, double n, double rs, double a2, double* dedrs, double* deda2); double beefvdw_exchange(const xc_parameters* par, double n, double rs, double a2, double* dedrs, double* deda2); // typedef struct { PyObject_HEAD double (*exchange)(const xc_parameters* par, double n, double rs, double a2, double* dedrs, double* deda2); double (*correlation)(double n, double rs, double zeta, double a2, bool gga, bool spinpol, double* dedrs, double* dedzeta, double* deda2); xc_parameters par; // below added by cpo for mgga functionals outside of libxc (TPSS, M06L, etc.) void* mgga; } XCFunctionalObject; static void XCFunctional_dealloc(XCFunctionalObject *self) { PyObject_DEL(self); } static PyObject* XCFunctional_calculate(XCFunctionalObject *self, PyObject *args) { PyArrayObject* e_array; PyArrayObject* n_array; PyArrayObject* v_array; PyArrayObject* sigma_array = 0; PyArrayObject* dedsigma_array = 0; PyArrayObject* tau_array = 0; PyArrayObject* dedtau_array = 0; if (!PyArg_ParseTuple(args, "OOO|OOOO", &e_array, &n_array, &v_array, &sigma_array, &dedsigma_array, &tau_array, &dedtau_array)) return NULL; int ng = 1; for (int d = 0; d < PyArray_NDIM(e_array); d++) ng *= PyArray_DIM(e_array, d); xc_parameters* par = &self->par; double* e_g = DOUBLEP(e_array); const double* n_g = DOUBLEP(n_array); double* v_g = DOUBLEP(v_array); const double* sigma_g = 0; double* dedsigma_g = 0; if (par->gga) { sigma_g = DOUBLEP(sigma_array); dedsigma_g = DOUBLEP(dedsigma_array); } const double* tau_g = 0; double* dedtau_g = 0; if (self->mgga) { tau_g = DOUBLEP(tau_array); dedtau_g = DOUBLEP(dedtau_array); } if (self->mgga) { int nspin = PyArray_DIM(n_array, 0) == 1 ? 1 : 2; calc_mgga(&self->mgga, nspin, ng, n_g, sigma_g, tau_g, e_g, v_g, dedsigma_g, dedtau_g); Py_RETURN_NONE; } if (PyArray_DIM(n_array, 0) == 1) for (int g = 0; g < ng; g++) { double n = n_g[g]; if (n < NMIN) n = NMIN; double rs = pow(C0I / n, THIRD); double dexdrs; double dexda2; double ex; double decdrs; double decda2; double ec; if (par->gga) { double a2 = sigma_g[g]; ex = self->exchange(par, n, rs, a2, &dexdrs, &dexda2); ec = self->correlation(n, rs, 0.0, a2, 1, 0, &decdrs, 0, &decda2); dedsigma_g[g] = n * (dexda2 + decda2); } else { ex = self->exchange(par, n, rs, 0.0, &dexdrs, 0); ec = self->correlation(n, rs, 0.0, 0.0, 0, 0, &decdrs, 0, 0); } e_g[g] = n * (ex + ec); v_g[g] += ex + ec - rs * (dexdrs + decdrs) / 3.0; } else { const double* na_g = n_g; double* va_g = v_g; const double* nb_g = na_g + ng; double* vb_g = va_g + ng; const double* sigma0_g = 0; const double* sigma1_g = 0; const double* sigma2_g = 0; double* dedsigma0_g = 0; double* dedsigma1_g = 0; double* dedsigma2_g = 0; const xc_parameters* par = &self->par; if (par->gga) { sigma0_g = sigma_g; sigma1_g = sigma0_g + ng; sigma2_g = sigma1_g + ng; dedsigma0_g = dedsigma_g; dedsigma1_g = dedsigma0_g + ng; dedsigma2_g = dedsigma1_g + ng; } for (int g = 0; g < ng; g++) { double na = 2.0 * na_g[g]; if (na < NMIN) na = NMIN; double rsa = pow(C0I / na, THIRD); double nb = 2.0 * nb_g[g]; if (nb < NMIN) nb = NMIN; double rsb = pow(C0I / nb, THIRD); double n = 0.5 * (na + nb); double rs = pow(C0I / n, THIRD); double zeta = 0.5 * (na - nb) / n; double dexadrs; double dexada2; double exa; double dexbdrs; double dexbda2; double exb; double decdrs; double decdzeta; double decda2; double ec; if (par->gga) { exa = self->exchange(par, na, rsa, 4.0 * sigma0_g[g], &dexadrs, &dexada2); exb = self->exchange(par, nb, rsb, 4.0 * sigma2_g[g], &dexbdrs, &dexbda2); double a2 = sigma0_g[g] + 2 * sigma1_g[g] + sigma2_g[g]; ec = self->correlation(n, rs, zeta, a2, 1, 1, &decdrs, &decdzeta, &decda2); dedsigma0_g[g] = 2 * na * dexada2 + n * decda2; dedsigma1_g[g] = 2 * n * decda2; dedsigma2_g[g] = 2 * nb * dexbda2 + n * decda2; } else { exa = self->exchange(par, na, rsa, 0.0, &dexadrs, 0); exb = self->exchange(par, nb, rsb, 0.0, &dexbdrs, 0); ec = self->correlation(n, rs, zeta, 0.0, 0, 1, &decdrs, &decdzeta, 0); } e_g[g] = 0.5 * (na * exa + nb * exb) + n * ec; va_g[g] += (exa + ec - (rsa * dexadrs + rs * decdrs) / 3.0 - (zeta - 1.0) * decdzeta); vb_g[g] += (exb + ec - (rsb * dexbdrs + rs * decdrs) / 3.0 - (zeta + 1.0) * decdzeta); } } Py_RETURN_NONE; } static PyMethodDef XCFunctional_Methods[] = { {"calculate", (PyCFunction)XCFunctional_calculate, METH_VARARGS, 0}, {NULL, NULL, 0, NULL} }; PyTypeObject XCFunctionalType = { PyVarObject_HEAD_INIT(NULL, 0) "XCFunctional", sizeof(XCFunctionalObject), 0, (destructor)XCFunctional_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, "XC object", 0, 0, 0, 0, 0, 0, XCFunctional_Methods }; PyObject * NewXCFunctionalObject(PyObject *obj, PyObject *args) { int code; PyArrayObject* parameters = 0; if (!PyArg_ParseTuple(args, "i|O", &code, ¶meters)) return NULL; XCFunctionalObject *self = PyObject_NEW(XCFunctionalObject, &XCFunctionalType); if (self == NULL) return NULL; self->mgga = NULL; self->par.gga = 1; self->correlation = pbe_correlation; self->exchange = pbe_exchange; if (code == -1) { // LDA self->par.gga = 0; } else if (code == 0) { // PBE self->par.kappa = 0.804; } else if (code == 1) { // revPBE self->par.kappa = 1.245; } else if (code == 2) { // RPBE self->exchange = rpbe_exchange; } else if (code == 14) { // PW91 self->exchange = pw91_exchange; } else if (code == 20 || code == 21 || code == 22) { // MGGA const int nspin = 1; // a guess, perhaps corrected later in calc_mgga init_mgga(&self->mgga,code,nspin); } else { assert (code == 17); // BEEF-vdW self->exchange = beefvdw_exchange; int n = PyArray_DIM(parameters, 0); assert(n <= 110); double* p = (double*)PyArray_BYTES(parameters); for (int i = 0; i < n; i++) self->par.parameters[i] = p[i]; self->par.nparameters = n / 2; } return (PyObject*)self; } gpaw-0.11.0.13004/c/xc/revtpss_c_pbe.c0000664000175000017500000003406312553643466017325 0ustar jensjjensj00000000000000 #include #include #include #include #include #include "xc_mgga.h" /************************************************************************ Implements Perdew, Burke & Ernzerhof Generalized Gradient Approximation correlation functional. I based this implementation on a routine from L.C. Balbas and J.M. Soler ************************************************************************/ // from old libxc util.h #define RS(x) (pow((3.0/(4*M_PI*x)), 1.0/3.0)) typedef struct XC(perdew_t) { int nspin; double dens, zeta, gdmt; double ecunif, vcunif[2], fcunif[3]; double rs, kf, ks, phi, t; double drs, dkf, dks, dphi, dt, decunif; double d2rs2, d2rskf, d2rsks, d2rsphi, d2rst, d2rsecunif; double d2kf2, d2kfks, d2kfphi, d2kft, d2kfecunif; double d2ks2, d2ksphi, d2kst, d2ksecunif; double d2phi2, d2phit, d2phiecunif; double d2t2, d2tecunif; double d2ecunif2; } XC(perdew_t); // from old libxc util.c /* this function converts the spin-density into total density and relative magnetization */ inline void XC(rho2dzeta)(int nspin, const double *rho, double *d, double *zeta) { assert(nspin==XC_UNPOLARIZED || nspin==XC_POLARIZED); if(nspin==XC_UNPOLARIZED){ *d = max(MIN_DENS, rho[0]); *zeta = 0.0; }else{ *d = max(MIN_DENS, rho[0]+rho[1]); *zeta = (*d > MIN_DENS) ? (rho[0]-rho[1])/(*d) : 0.0; } } // from old libxc gga_perdew.c static void XC(perdew_params)(const XC(func_type) *gga_p, const double *rho, const double *sigma, int order, XC(perdew_t) *pt) { pt->nspin = gga_p->nspin; XC(rho2dzeta)(pt->nspin, rho, &(pt->dens), &(pt->zeta)); const int np = 1; switch (order){ case 0: XC(lda_exc) (gga_p, np, rho, &(pt->ecunif)); break; case 1: XC(lda_exc_vxc)(gga_p, np, rho, &(pt->ecunif), pt->vcunif); break; case 2: XC(lda)(gga_p, np, rho, &(pt->ecunif), pt->vcunif, pt->fcunif, NULL); break; } pt->rs = RS(pt->dens); pt->kf = pow(3.0*M_PI*M_PI*pt->dens, 1.0/3.0); pt->ks = sqrt(4.0*pt->kf/M_PI); /* phi is bounded between 2^(-1/3) and 1 */ pt->phi = 0.5*(pow(1.0 + pt->zeta, 2.0/3.0) + pow(1.0 - pt->zeta, 2.0/3.0)); /* get gdmt = |nabla n| */ pt->gdmt = sigma[0]; if(pt->nspin == XC_POLARIZED) pt->gdmt += 2.0*sigma[1] + sigma[2]; if(pt->gdmt < MIN_GRAD*MIN_GRAD) pt->gdmt = MIN_GRAD*MIN_GRAD; pt->gdmt = sqrt(pt->gdmt); pt->t = pt->gdmt/(2.0 * pt->phi * pt->ks * pt->dens); if(order > 0) pt->drs = pt->dkf = pt->dks = pt->dphi = pt->dt = pt->decunif = 0.0; if(order > 1){ pt->d2rs2 = pt->d2rskf = pt->d2rsks = pt->d2rsphi = pt->d2rst = pt->d2rsecunif = 0.0; pt->d2kf2 = pt->d2kfks = pt->d2kfphi = pt->d2kft = pt->d2kfecunif = 0.0; pt->d2ks2 = pt->d2ksphi = pt->d2kst = pt->d2ksecunif = 0.0; pt->d2phi2 = pt->d2phit = pt->d2phiecunif = 0.0; pt->d2t2 = pt->d2tecunif = 0.0; pt->d2ecunif2 = 0.0; } } static void XC(perdew_potentials)(XC(perdew_t) *pt, const double *rho, double e_gga, int order, double *vrho, double *vsigma, double *v2rho2, double *v2rhosigma, double *v2sigma2) { /* alpha = {0->rs, 1->kf, 2->ks, 3->phi, 4->t, 5->ec */ double dalphadd[6][2], dFdalpha[6]; double d2alphadd2[6][3], d2Fdalpha2[6][6]; double dzdd[2], dpdz, d2zdd2[3], d2pdz2; double dtdsig, d2tdsig2; int is, js, ks, ns; if(order < 1) return; if(pt->nspin == XC_POLARIZED){ dpdz = 0.0; if(fabs(1.0 + pt->zeta) >= MIN_DENS) dpdz += 1.0/(3.0*pow(1.0 + pt->zeta, 1.0/3.0)); if(fabs(1.0 - pt->zeta) >= MIN_DENS) dpdz -= 1.0/(3.0*pow(1.0 - pt->zeta, 1.0/3.0)); dzdd[0] = (1.0 - pt->zeta)/pt->dens; dzdd[1] = -(1.0 + pt->zeta)/pt->dens; }else{ dpdz = 0.0; dzdd[0] = 0.0; } dFdalpha[0] = pt->drs; dFdalpha[1] = pt->dkf; dFdalpha[2] = pt->dks; dFdalpha[3] = pt->dphi; dFdalpha[4] = pt->dt; dFdalpha[5] = pt->decunif; for(is=0; isnspin; is++){ dalphadd[0][is] = -pt->rs/(3.0*pt->dens); dalphadd[1][is] = pt->kf/(3.0*pt->dens); dalphadd[2][is] = pt->ks*dalphadd[1][is]/(2.0*pt->kf); dalphadd[3][is] = dpdz*dzdd[is]; dalphadd[4][is] = -pt->t*(1.0/pt->dens + dalphadd[2][is]/pt->ks + dalphadd[3][is]/pt->phi);; dalphadd[5][is] = (pt->vcunif[is] - pt->ecunif)/pt->dens; } /* calculate vrho */ if(vrho != NULL) for(is=0; isnspin; is++){ if(rho[is] > MIN_DENS){ int k; vrho[is] = e_gga; for(k=0; k<6; k++) vrho[is] += pt->dens * dFdalpha[k]*dalphadd[k][is]; }else{ vrho[is] = 0.0; } } dtdsig = pt->t/(2.0*pt->gdmt*pt->gdmt); if(vrho != NULL){ /* calculate now vsigma */ vsigma[0] = pt->dens*pt->dt*dtdsig; if(pt->nspin == XC_POLARIZED){ vsigma[1] = 2.0*vsigma[0]; vsigma[2] = vsigma[0]; } } if(order < 2) return; /* first let us sort d2Fdalpha2 in a matrix format */ d2Fdalpha2[0][0] = pt->d2rs2; d2Fdalpha2[0][1] = pt->d2rskf; d2Fdalpha2[0][2] = pt->d2rsks; d2Fdalpha2[0][3] = pt->d2rst; d2Fdalpha2[0][4] = pt->d2rsphi; d2Fdalpha2[0][5] = pt->d2rsecunif; d2Fdalpha2[1][0] = d2Fdalpha2[0][1]; d2Fdalpha2[1][1] = pt->d2kf2; d2Fdalpha2[1][2] = pt->d2kfks; d2Fdalpha2[1][3] = pt->d2kft; d2Fdalpha2[1][4] = pt->d2kfphi; d2Fdalpha2[1][5] = pt->d2kfecunif; d2Fdalpha2[2][0] = d2Fdalpha2[0][2]; d2Fdalpha2[2][1] = d2Fdalpha2[1][2]; d2Fdalpha2[2][2] = pt->d2ks2; d2Fdalpha2[2][3] = pt->d2kst; d2Fdalpha2[2][4] = pt->d2ksphi; d2Fdalpha2[2][5] = pt->d2ksecunif; d2Fdalpha2[3][0] = d2Fdalpha2[0][3]; d2Fdalpha2[3][1] = d2Fdalpha2[1][3]; d2Fdalpha2[3][2] = d2Fdalpha2[2][3]; d2Fdalpha2[3][3] = pt->d2phi2; d2Fdalpha2[3][4] = pt->d2phit; d2Fdalpha2[3][5] = pt->d2phiecunif; d2Fdalpha2[4][0] = d2Fdalpha2[0][4]; d2Fdalpha2[4][1] = d2Fdalpha2[1][4]; d2Fdalpha2[4][2] = d2Fdalpha2[2][4]; d2Fdalpha2[4][3] = d2Fdalpha2[3][4]; d2Fdalpha2[4][4] = pt->d2t2; d2Fdalpha2[4][5] = pt->d2tecunif; d2Fdalpha2[5][0] = d2Fdalpha2[0][5]; d2Fdalpha2[5][1] = d2Fdalpha2[1][5]; d2Fdalpha2[5][2] = d2Fdalpha2[2][5]; d2Fdalpha2[5][3] = d2Fdalpha2[3][5]; d2Fdalpha2[5][4] = d2Fdalpha2[4][5]; d2Fdalpha2[5][5] = pt->d2ecunif2; /* now we sort d2alphadd2 */ if(pt->nspin == XC_POLARIZED){ d2pdz2 = 0.0; if(fabs(1.0 + pt->zeta) >= MIN_DENS) d2pdz2 += -(1.0/9.0)*pow(1.0 + pt->zeta, -4.0/3.0); if(fabs(1.0 - pt->zeta) >= MIN_DENS) d2pdz2 += -(1.0/9.0)*pow(1.0 - pt->zeta, -4.0/3.0); d2zdd2[0] = -2.0*dzdd[0]/pt->dens; d2zdd2[1] = 2.0*pt->zeta/(pt->dens*pt->dens); d2zdd2[2] = -2.0*dzdd[1]/pt->dens; }else{ d2pdz2 = 0.0; d2zdd2[0] = 0.0; } ns = (pt->nspin == XC_UNPOLARIZED) ? 0 : 2; for(ks=0; ks<=ns; ks++){ is = (ks == 0 || ks == 1) ? 0 : 1; js = (ks == 0 ) ? 0 : 1; d2alphadd2[0][ks] = 4.0/9.0*pt->rs/(pt->dens*pt->dens); d2alphadd2[1][ks] = -2.0/9.0*pt->kf/(pt->dens*pt->dens); d2alphadd2[2][ks] = pt->ks/(2.0*pt->kf)* (d2alphadd2[1][ks] - dalphadd[1][is]*dalphadd[1][js]/(2.0*pt->kf)); d2alphadd2[3][ks] = d2pdz2*dzdd[is]*dzdd[js] + dpdz*d2zdd2[ks]; d2alphadd2[4][ks] = pt->t * (+2.0/(pt->dens*pt->dens) +2.0/(pt->ks*pt->ks) *(dalphadd[2][is] * dalphadd[2][js]) +2.0/(pt->phi*pt->phi) *(dalphadd[3][is] * dalphadd[3][js]) +1.0/(pt->dens*pt->ks) *(dalphadd[2][is] + dalphadd[2][js]) +1.0/(pt->dens*pt->phi)*(dalphadd[3][is] + dalphadd[3][js]) +1.0/(pt->ks*pt->phi) *(dalphadd[2][is]*dalphadd[3][js] + dalphadd[2][js]*dalphadd[3][is]) -1.0/(pt->ks)*d2alphadd2[2][ks] -1.0/(pt->phi)*d2alphadd2[3][ks]); d2alphadd2[5][ks] = pt->fcunif[ks]/pt->dens - (pt->vcunif[is] + pt->vcunif[js] - 2.0*pt->ecunif)/(pt->dens*pt->dens); } for(ks=0; ks<=ns; ks++){ int j, k; is = (ks == 0 || ks == 1) ? 0 : 1; js = (ks == 0 ) ? 0 : 1; v2rho2[ks] = 0.0; for(j=0; j<6; j++){ v2rho2[ks] += dFdalpha[j]*(dalphadd[j][is] + dalphadd[j][js]); v2rho2[ks] += pt->dens * dFdalpha[j]*d2alphadd2[j][ks]; for(k=0; k<6; k++) v2rho2[ks] += pt->dens * d2Fdalpha2[j][k]*dalphadd[j][is]*dalphadd[k][js]; } } /* now we handle v2rhosigma */ for(is=0; isnspin; is++){ int j; ks = (is == 0) ? 0 : 5; v2rhosigma[ks] = dFdalpha[4]*dtdsig; for(j=0; j<6; j++) v2rhosigma[ks] += pt->dens * d2Fdalpha2[4][j]*dalphadd[j][is]*dtdsig; v2rhosigma[ks] += pt->dens * dFdalpha[4]*dalphadd[4][is]/(2.0*pt->gdmt*pt->gdmt); } if(pt->nspin == XC_POLARIZED){ v2rhosigma[1] = 2.0*v2rhosigma[0]; v2rhosigma[2] = v2rhosigma[0]; v2rhosigma[3] = v2rhosigma[5]; v2rhosigma[4] = 2.0*v2rhosigma[5]; } /* now wwe take care of v2sigma2 */ d2tdsig2 = -dtdsig/(2.0*pt->gdmt*pt->gdmt); v2sigma2[0] = pt->dens*(pt->d2t2*dtdsig*dtdsig + pt->dt*d2tdsig2); if(pt->nspin == XC_POLARIZED){ v2sigma2[1] = 2.0*v2sigma2[0]; /* aa_ab */ v2sigma2[2] = v2sigma2[0]; /* aa_bb */ v2sigma2[3] = 4.0*v2sigma2[0]; /* ab_ab */ v2sigma2[4] = 2.0*v2sigma2[0]; /* ab_bb */ v2sigma2[5] = v2sigma2[0]; /* bb_bb */ } } // from old libxc gga_c_pbe.c static const double beta[4] = { 0.06672455060314922, /* original PBE */ 0.046, /* PBE sol */ 0.089809, 0.06672455060314922 /* PBE for revTPSS */ }; static double gamm[4]; static inline void pbe_eq8(int func, int order, double rs, double ecunif, double phi, double *A, double *dec, double *dphi, double *drs, double *dec2, double *decphi, double *dphi2) { double phi3, f1, df1dphi, d2f1dphi2, f2, f3, dx, d2x; phi3 = pow(phi, 3); f1 = ecunif/(gamm[func]*phi3); f2 = exp(-f1); f3 = f2 - 1.0; *A = beta[func]/(gamm[func]*f3); if(func == 3) *A *= (1. + 0.1*rs)/(1. + 0.1778*rs); if(order < 1) return; df1dphi = -3.0*f1/phi; dx = (*A)*f2/f3; *dec = dx/(gamm[func]*phi3); *dphi = dx*df1dphi; *drs = 0.0; if(func == 3) *drs = beta[func]*((0.1-0.1778)/pow(1+0.1778*rs,2))/(gamm[func]*f3); if(func ==3) return; if(order < 2) return; d2f1dphi2 = -4.0*df1dphi/phi; d2x = dx*(2.0*f2 - f3)/f3; *dphi2 = d2x*df1dphi*df1dphi + dx*d2f1dphi2; *decphi = (d2x*df1dphi*f1 + dx*df1dphi)/ecunif; *dec2 = d2x/(gamm[func]*gamm[func]*phi3*phi3); } static void pbe_eq7(int func, int order, double rs, double phi, double t, double A, double *H, double *dphi, double *drs, double *dt, double *dA, double *d2phi, double *d2phit, double *d2phiA, double *d2t2, double *d2tA, double *d2A2) { double t2, phi3, f1, f2, f3; double df1dt, df2drs, df2dt, df1dA, df2dA; double d2f1dt2, d2f2dt2, d2f2dA2, d2f1dtA, d2f2dtA; t2 = t*t; phi3 = pow(phi, 3); f1 = t2 + A*t2*t2; f3 = 1.0 + A*f1; f2 = beta[func]*f1/(gamm[func]*f3); if(func == 3) f2 *= (1. + 0.1*rs)/(1. + 0.1778*rs); *H = gamm[func]*phi3*log(1.0 + f2); if(order < 1) return; *dphi = 3.0*(*H)/phi; df1dt = t*(2.0 + 4.0*A*t2); df2dt = beta[func]/(gamm[func]*f3*f3) * df1dt; if(func == 3) df2dt*=(1. + 0.1*rs)/(1. + 0.1778*rs); *dt = gamm[func]*phi3*df2dt/(1.0 + f2); df1dA = t2*t2; df2dA = beta[func]/(gamm[func]*f3*f3) * (df1dA - f1*f1); if(func == 3) df2dA *= (1. + 0.1*rs)/(1. + 0.1778*rs); *dA = gamm[func]*phi3*df2dA/(1.0 + f2); df2drs = 0.0; *drs = 0.0; if(func == 3){ df2drs = beta[func]*((0.1-0.1778)/pow(1+0.1778*rs,2))*f1/(gamm[func]*f3); *drs = gamm[func]*phi3*df2drs/(1.0 + f2); } if(func ==3) return; if(order < 2) return; *d2phi = 2.0*(*dphi)/phi; *d2phit = 3.0*(*dt)/phi; *d2phiA = 3.0*(*dA)/phi; d2f1dt2 = 2.0 + 4.0*3.0*A*t2; d2f2dt2 = beta[func]/(gamm[func]*f3*f3) * (d2f1dt2 - 2.0*A/f3*df1dt*df1dt); *d2t2 = gamm[func]*phi3*(d2f2dt2*(1.0 + f2) - df2dt*df2dt)/((1.0 + f2)*(1.0 + f2)); d2f1dtA = 4.0*t*t2; d2f2dtA = beta[func]/(gamm[func]*f3*f3) * (d2f1dtA - 2.0*df1dt*(f1 + A*df1dA)/f3); *d2tA = gamm[func]*phi3*(d2f2dtA*(1.0 + f2) - df2dt*df2dA)/((1.0 + f2)*(1.0 + f2)); d2f2dA2 = beta[func]/(gamm[func]*f3*f3*f3) *(-2.0)*(2.0*f1*df1dA - f1*f1*f1 + A*df1dA*df1dA); *d2A2 = gamm[func]*phi3*(d2f2dA2*(1.0 + f2) - df2dA*df2dA)/((1.0 + f2)*(1.0 + f2)); } void gga_c_pbe_revtpss(XC(func_type) *p, const double *rho, const double *sigma, double *e, double *vrho, double *vsigma, double *v2rho2, double *v2rhosigma, double *v2sigma2) { gamm[0] = gamm[1] = gamm[3] = (1.0 - log(2.0))/(M_PI*M_PI); XC(perdew_t) pt; int func, order; double me; double A, dAdec, dAdphi, dAdrs, d2Adec2, d2Adecphi, d2Adphi2; double H, dHdphi, dHdrs, dHdt, dHdA, d2Hdphi2, d2Hdphit, d2HdphiA, d2Hdt2, d2HdtA, d2HdA2; d2HdphiA = 0.0; d2Hdphi2 = 0.0; d2Adphi2 = 0.0; d2HdA2 = 0.0; d2HdtA = 0.0; d2Hdphit = 0.0; d2Adecphi = 0.0; d2Hdt2 = 0.0; d2Adec2 = 0.0; dAdrs = 0.0; dAdphi = 0.0; dAdec = 0.0; dHdA = 0.0; dHdt = 0.0; dHdrs = 0.0; dHdphi = 0.0; func = 3; // for revTPSS order = 0; if(vrho != NULL) order = 1; if(v2rho2 != NULL) order = 2; XC(perdew_params)(p, rho, sigma, order, &pt); pbe_eq8(func, order, pt.rs, pt.ecunif, pt.phi, &A, &dAdec, &dAdphi, &dAdrs, &d2Adec2, &d2Adecphi, &d2Adphi2); pbe_eq7(func, order, pt.rs, pt.phi, pt.t, A, &H, &dHdphi, &dHdrs, &dHdt, &dHdA, &d2Hdphi2, &d2Hdphit, &d2HdphiA, &d2Hdt2, &d2HdtA, &d2HdA2); me = pt.ecunif + H; if(e != NULL) *e = me; if(order >= 1){ pt.dphi = dHdphi + dHdA*dAdphi; pt.drs = dHdrs + dHdA*dAdrs; pt.dt = dHdt; pt.decunif = 1.0 + dHdA*dAdec; } if(order >= 2){ pt.d2phi2 = d2Hdphi2 + 2.0*d2HdphiA*dAdphi + dHdA*d2Adphi2 + d2HdA2*dAdphi*dAdphi; pt.d2phit = d2Hdphit + d2HdtA*dAdphi; pt.d2phiecunif = d2HdphiA*dAdec + d2HdA2*dAdphi*dAdec + dHdA*d2Adecphi; pt.d2t2 = d2Hdt2; pt.d2tecunif = d2HdtA*dAdec; pt.d2ecunif2 = d2HdA2*dAdec*dAdec + dHdA*d2Adec2; } XC(perdew_potentials)(&pt, rho, me, order, vrho, vsigma, v2rho2, v2rhosigma, v2sigma2); } gpaw-0.11.0.13004/c/xc/rpbe.c0000664000175000017500000000131412553643466015410 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Please see the accompanying LICENSE file for further information. */ #include #include "xc_gpaw.h" double rpbe_exchange(const xc_parameters* par, double n, double rs, double a2, double* dedrs, double* deda2) { double e = C1 / rs; *dedrs = -e / rs; if (par->gga) // not really needed? XXX { double c = C2 * rs / n; c *= c; double s2 = a2 * c; double x = exp(-MU * s2 / 0.804); double Fx = 1.0 + 0.804 * (1 - x); double dFxds2 = MU * x; double ds2drs = 8.0 * c * a2 / rs; *dedrs = *dedrs * Fx + e * dFxds2 * ds2drs; *deda2 = e * dFxds2 * c; e *= Fx; } return e; } gpaw-0.11.0.13004/c/xc/xc_mgga.h0000664000175000017500000000213112553643466016070 0ustar jensjjensj00000000000000 #ifndef GPAW_XC_MGGA_H #define GPAW_XC_MGGA_H #define M_PI 3.14159265358979323846 #define MIN_DENS 1.0e-20 #define MIN_GRAD 1.0e-20 #define max(x,y) ((x= nD - 1) { double d12 = d1 * d1; double d22 = d2 * d2; const double C = -1024.0 / 243.0 * M_PI * M_PI * M_PI * M_PI; e12 = C / (d12 * d22 * (d12 + d22)); } else { double x = fabs(0.5 * (d1 - d2) / D) / ddelta; int i = (int)x; if (i >= ndelta - 1) { i = ndelta - 2; x = 1.0; } else x -= i; y -= j; e12 = ((x * y * phi[i + 1][j + 1] + x * (1.0 - y) * phi[i + 1][j ] + (1.0 - x) * y * phi[i ][j + 1] + (1.0 - x) * (1.0 - y) * phi[i ][j ])); } return e12; } PyObject * vdw(PyObject* self, PyObject *args) { PyArrayObject* n_obj; PyArrayObject* q0_obj; PyArrayObject* R_obj; PyArrayObject* cell_obj; PyArrayObject* pbc_obj; PyArrayObject* repeat_obj; PyArrayObject* phi_obj; double ddelta; double dD; int iA; int iB; PyArrayObject* rhistogram_obj; double drhist; PyArrayObject* Dhistogram_obj; double dDhist; if (!PyArg_ParseTuple(args, "OOOOOOOddiiOdOd", &n_obj, &q0_obj, &R_obj, &cell_obj, &pbc_obj, &repeat_obj, &phi_obj, &ddelta, &dD, &iA, &iB, &rhistogram_obj, &drhist, &Dhistogram_obj, &dDhist)) return NULL; int ndelta = PyArray_DIMS(phi_obj)[0]; int nD = PyArray_DIMS(phi_obj)[1]; const double* n = (const double*)DOUBLEP(n_obj); const int ni = PyArray_SIZE(n_obj); const double* q0 = (const double*)DOUBLEP(q0_obj); const double (*R)[3] = (const double (*)[3])DOUBLEP(R_obj); const double* cell = (const double*)DOUBLEP(cell_obj); const char* pbc = (const char*)(PyArray_DATA(pbc_obj)); const long* repeat = (const long*)(PyArray_DATA(repeat_obj)); const double (*phi)[nD] = (const double (*)[nD])DOUBLEP(phi_obj); double* rhistogram = (double*)DOUBLEP(rhistogram_obj); double* Dhistogram = (double*)DOUBLEP(Dhistogram_obj); int nbinsr = PyArray_DIMS(rhistogram_obj)[0]; int nbinsD = PyArray_DIMS(Dhistogram_obj)[0]; double energy = 0.0; if (repeat[0] == 0 && repeat[1] == 0 && repeat[2] == 0) for (int i1 = iA; i1 < iB; i1++) { const double* R1 = R[i1]; double q01 = q0[i1]; for (int i2 = 0; i2 <= i1; i2++) { double rr = 0.0; for (int c = 0; c < 3; c++) { double f = R[i2][c] - R1[c]; if (pbc[c]) f = fmod(f + 1.5 * cell[c], cell[c]) - 0.5 * cell[c]; rr += f * f; } double r = sqrt(rr); double d1 = r * q01; double d2 = r * q0[i2]; double D = 0.5 * (d1 + d2); double e12 = (vdwkernel(D, d1, d2, nD, ndelta, dD, ddelta, phi) * n[i1] * n[i2]); if (i1 == i2) e12 /= 2.0; int bin = (int)(r / drhist); if (bin < nbinsr) rhistogram[bin] += e12; bin = (int)(D / dDhist); if (bin < nbinsD) Dhistogram[bin] += e12; energy += e12; } } else for (int i1 = iA; i1 < iB; i1++) { const double* R1 = R[i1]; double q01 = q0[i1]; for (int a1 = -repeat[0]; a1 <= repeat[0]; a1++) for (int a2 = -repeat[1]; a2 <= repeat[1]; a2++) for (int a3 = -repeat[2]; a3 <= repeat[2]; a3++) { double x = 0.5; int i2max = ni-1; if (a1 == 0 && a2 == 0 && a3 == 0) { i2max = i1; x = 1.0; } double R1a[3] = {R1[0] + a1 * cell[0], R1[1] + a2 * cell[1], R1[2] + a3 * cell[2]}; for (int i2 = 0; i2 <= i2max; i2++) { double rr = 0.0; for (int c = 0; c < 3; c++) { double f = R[i2][c] - R1a[c]; rr += f * f; } double r = sqrt(rr); double d1 = r * q01; double d2 = r * q0[i2]; double D = 0.5 * (d1 + d2); double e12 = (vdwkernel(D, d1, d2, nD, ndelta, dD, ddelta, phi) * n[i1] * n[i2] * x); int bin = (int)(r / drhist); if (bin < nbinsr) rhistogram[bin] += e12; bin = (int)(D / dDhist); if (bin < nbinsD) Dhistogram[bin] += e12; energy += e12; } } } return PyFloat_FromDouble(energy); } PyObject * vdw2(PyObject* self, PyObject *args) { PyArrayObject* phi_jp_obj; PyArrayObject* j_k_obj; PyArrayObject* dk_k_obj; PyArrayObject* theta_k_obj; PyArrayObject* F_k_obj; if (!PyArg_ParseTuple(args, "OOOOO", &phi_jp_obj, &j_k_obj, &dk_k_obj, &theta_k_obj, &F_k_obj)) return NULL; const double* phi_jp = (const double*)PyArray_DATA(phi_jp_obj); const long* j_k = (const long*)PyArray_DATA(j_k_obj); const double* dk_k = (const double*)PyArray_DATA(dk_k_obj); const complex double* theta_k = (const complex double*)PyArray_DATA(theta_k_obj); complex double* F_k = (complex double*)PyArray_DATA(F_k_obj); int nk = PyArray_SIZE(j_k_obj); for (int k = 0; k < nk; k++) { const double* phi_p = phi_jp + 4 * j_k[k]; double a = phi_p[0]; double b = phi_p[1]; double c = phi_p[2]; double d = phi_p[3]; double x = dk_k[k]; F_k[k] += theta_k[k] * (a + x * (b + x * (c + x * d))); } Py_RETURN_NONE; } gpaw-0.11.0.13004/c/xc/pbe.c0000664000175000017500000001164212553643466015233 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Please see the accompanying LICENSE file for further information. */ #include #include "xc_gpaw.h" double pbe_exchange(const xc_parameters* par, double n, double rs, double a2, double* dedrs, double* deda2) { double e = C1 / rs; *dedrs = -e / rs; if (par->gga) { double c = C2 * rs / n; c *= c; double s2 = a2 * c; double x = 1.0 + MU * s2 / par->kappa; double Fx = 1.0 + par->kappa - par->kappa / x; double dFxds2 = MU / (x * x); double ds2drs = 8.0 * c * a2 / rs; //double ds2drs = 8.0 * s2 / rs; *dedrs = *dedrs * Fx + e * dFxds2 * ds2drs; *deda2 = e * dFxds2 * c; e *= Fx; } return e; } /* inline */ double G(double rtrs, double A, double alpha1, double beta1, double beta2, double beta3, double beta4, double* dGdrs) { double Q0 = -2.0 * A * (1.0 + alpha1 * rtrs * rtrs); double Q1 = 2.0 * A * rtrs * (beta1 + rtrs * (beta2 + rtrs * (beta3 + rtrs * beta4))); double G1 = Q0 * log(1.0 + 1.0 / Q1); double dQ1drs = A * (beta1 / rtrs + 2.0 * beta2 + rtrs * (3.0 * beta3 + 4.0 * beta4 * rtrs)); *dGdrs = -2.0 * A * alpha1 * G1 / Q0 - Q0 * dQ1drs / (Q1 * (Q1 + 1.0)); return G1; } /* * In[1]:= H=g Log[1+b/g t^2(1+a t^2)/(1+a t^2 + a^2 t^4)] * * 2 2 * b t (1 + a t ) * Out[1]= g Log[1 + --------------------] * 2 2 4 * g (1 + a t + a t ) * * In[4]:= Simplify[D[H,t]] * * 2 * 2 b g t (1 + 2 a t ) * Out[4]= --------------------------------------------------------- * 2 2 4 2 2 4 2 4 * (1 + a t + a t ) (g + b t + a g t + a b t + a g t ) * */ double pbe_correlation(double n, double rs, double zeta, double a2, bool gga, bool spinpol, double* dedrs, double* dedzeta, double* deda2) { double rtrs = sqrt(rs); double de0drs; double e0 = G(rtrs, GAMMA, 0.21370, 7.5957, 3.5876, 1.6382, 0.49294, &de0drs); double e; double xp = 117.0; double xm = 117.0; if (spinpol) { double de1drs; double e1 = G(rtrs, 0.015545, 0.20548, 14.1189, 6.1977, 3.3662, 0.62517, &de1drs); double dalphadrs; double alpha = -G(rtrs, 0.016887, 0.11125, 10.357, 3.6231, 0.88026, 0.49671, &dalphadrs); dalphadrs = -dalphadrs; double zp = 1.0 + zeta; double zm = 1.0 - zeta; xp = pow(zp, THIRD); xm = pow(zm, THIRD); double f = CC1 * (zp * xp + zm * xm - 2.0); double f1 = CC2 * (xp - xm); double zeta2 = zeta * zeta; double zeta3 = zeta2 * zeta; double zeta4 = zeta2 * zeta2; double x = 1.0 - zeta4; *dedrs = (de0drs * (1.0 - f * zeta4) + de1drs * f * zeta4 + dalphadrs * f * x * IF2); *dedzeta = (4.0 * zeta3 * f * (e1 - e0 - alpha * IF2) + f1 * (zeta4 * e1 - zeta4 * e0 + x * alpha * IF2)); e = e0 + alpha * IF2 * f * x + (e1 - e0) * f * zeta4; } else { *dedrs = de0drs; e = e0; } if (gga) { double n2 = n * n; double t2; double y; double phi = 117.0; double phi2 = 117.0; double phi3 = 117.0; if (spinpol) { phi = 0.5 * (xp * xp + xm * xm); phi2 = phi * phi; phi3 = phi * phi2; t2 = C3 * a2 * rs / (n2 * phi2); y = -e / (GAMMA * phi3); } else { t2 = C3 * a2 * rs / n2; y = -e / GAMMA; } double x = exp(y); double A; if (x != 1.0) A = BETA / (GAMMA * (x - 1.0)); else A = BETA / (GAMMA * y); double At2 = A * t2; double nom = 1.0 + At2; double denom = nom + At2 * At2; double H = GAMMA * log( 1.0 + BETA * t2 * nom / (denom * GAMMA)); double tmp = (GAMMA * BETA / (denom * (BETA * t2 * nom + GAMMA * denom))); double tmp2 = A * A * x / BETA; double dAdrs = tmp2 * *dedrs; if (spinpol) { H *= phi3; tmp *= phi3; dAdrs /= phi3; } double dHdt2 = (1.0 + 2.0 * At2) * tmp; double dHdA = -At2 * t2 * t2 * (2.0 + At2) * tmp; *dedrs += dHdt2 * 7 * t2 / rs + dHdA * dAdrs; *deda2 = dHdt2 * C3 * rs / n2; if (spinpol) { double dphidzeta = (1.0 / xp - 1.0 / xm) / 3.0; double dAdzeta = tmp2 * (*dedzeta - 3.0 * e * dphidzeta / phi) / phi3; *dedzeta += ((3.0 * H / phi - dHdt2 * 2.0 * t2 / phi ) * dphidzeta + dHdA * dAdzeta); *deda2 /= phi2; } e += H; } return e; } gpaw-0.11.0.13004/c/lapack.c0000664000175000017500000004116412553643466015310 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2009 CAMd * Copyright (C) 2005-2007 CSC - IT Center for Science Ltd. * Please see the accompanying LICENSE file for further information. */ #include #define PY_ARRAY_UNIQUE_SYMBOL GPAW_ARRAY_API #define NO_IMPORT_ARRAY #include #include "extensions.h" #ifdef GPAW_NO_UNDERSCORE_LAPACK # define dlamch_ dlamch # define dsyev_ dsyev # define zheev_ zheev # define dsyevr_ dsyevr # define zheevr_ zheevr # define dsygv_ dsygv # define dsygvx_ dsygvx # define dhegv_ dhegv # define zhegv_ zhegv # define zhegvx_ zhegvx # define dgeev_ dgeev # define dpotrf_ dpotrf # define dpotri_ dpotri # define zpotrf_ zpotrf # define zpotri_ zpotri # define dtrtri_ dtrtri # define ztrtri_ ztrtri # define dsytrf_ dsytrf # define zsytrf_ zsytrf # define dgetrf_ dgetrf # define zgetrf_ zgetrf # define dsytri_ dsytri # define zsytri_ zsytri # define dgetri_ dgetri # define zgetri_ zgetri # define zgbsv_ zgbsv # define zgttrf_ zgttrf # define zgttrs_ zgttrs # define ilaenv_ ilaenv #endif double dlamch_(char* cmach); void dsyev_(char *jobz, char *uplo, int *n, double *a, int *lda, double *w, double *work, int *lwork, int *info); void zheev_(char *jobz, char *uplo, int *n, void *a, int *lda, double *w, void *work, int *lwork, double *rwork, int *lrwork, int *info); void dsyevr_(char *jobz, char *range, char *uplo, int *n, double *a, int *lda, double *vl, double *vu, int *il, int*iu, double *abstol, int *m, double *w, double *z, int *ldz, int *isuppz, double *work, int *lwork, int *iwork, int *liwork, int *info); void zheevr_(char *jobz, char *range, char *uplo, int *n, void *a, int *lda, double *vl, double *vu, int *il, int *iu, double *abstol, int *m, double *w, void *z, int *ldz, int *isuppz, void *work, int *lwork, double *rwork, int *lrwork, int *iwork, int *liwork, int *info); void dsygv_(int *itype, char *jobz, char *uplo, int * n, double *a, int *lda, double *b, int *ldb, double *w, double *work, int *lwork, int *info); void dsygvx_(int *itype, char *jobz, char *range, char *uplo, int *n, void *a, int *lda, void *b, int *ldb, double *vl, double *vu, int *il, int *iu, double *abstol, int *m, double *w, void *z, int *ldz, void *work, int *lwork, int *iwork, int *ifail, int *info); void zhegv_(int *itype, char *jobz, char *uplo, int * n, void *a, int *lda, void *b, int *ldb, double *w, void *work, int *lwork, double *rwork, int *lrwork, int *info); void zhegvx_(int *itype, char *jobz, char *range, char *uplo, int *n, void *a, int *lda, void *b, int *ldb, double *vl, double *vu, int *il, int *iu, double *abstol, int *m, double *w, void *z, int *ldz, void *work, int *lwork, double *rwork, int *iwork, int *ifail, int *info); void dpotrf_(char *uplo, int *n, double *a, int * lda, int *info); void dpotri_(char *uplo, int *n, double *a, int * lda, int *info); void zpotrf_(char *uplo, int *n, void *a, int *lda, int *info); void zpotri_(char *uplo, int *n, void *a, int *lda, int *info); void dgeev_(char *jovl, char *jobvr, int *n, double *a, int *lda, double *wr, double *wl, double *vl, int *ldvl, double *vr, int *ldvr, double *work, int *lwork, int *info); void dtrtri_(char *uplo,char *diag, int *n, void *a, int *lda, int *info ); void ztrtri_(char *uplo,char *diag, int *n, void *a, int *lda, int *info ); void dsytrf_(char *uplo, int *n, double *a, int *lda, int *ipiv, double *work, int *lwork, int *info); void zsytrf_(char *uplo, int *n, void *a, int *lda, int *ipiv, void *work, int *lwork, int *info); void dgetrf_(int *n, int *m, double *a, int *lda, int *ipiv, int *info); void zgetrf_(int *n, int *m, void *a, int *lda, int *ipiv, int *info); void dsytri_(char *uplo, int *n, double *a, int *lda, int *ipiv, double *work, int *info); void zsytri_(char *uplo, int *n, void *a, int *lda, int *ipiv, void *work, int *info); void dgetri_(int *n, double *a, int *lda, int *ipiv, double *work, int *lwork, int *info); void zgetri_(int *n, void *a, int *lda, int *ipiv, void *work, int *lwork, int *info); void zgbsv_(int*n, int* kl, int* ku, int* nrhs, void* ab, int*ldab, int*ipiv, void* b, int*ldb, int*info); void zgttrf_(int* n, void* dl, void* d, void* du, void* du2, int* ipiv, int* info); void zgttrs_(char* tran, int* n, int* nrhs, void* dl, void* d, void* du, void* du2, int* ipiv, void* b, int* ldb, int* info); int ilaenv_(int* ispec, char* name, char* opts, int* n1, int* n2, int* n3, int* n4, short name_len, short opts_len); PyObject* diagonalize(PyObject *self, PyObject *args) { PyArrayObject* a; PyArrayObject* w; if (!PyArg_ParseTuple(args, "OO", &a, &w)) return NULL; int n = PyArray_DIMS(a)[0]; int lda = n; int info = 0; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { int lwork = 3 * n + 1; double* work = GPAW_MALLOC(double, lwork); dsyev_("V", "U", &n, DOUBLEP(a), &lda, DOUBLEP(w), work, &lwork, &info); free(work); } else { int lwork = 2 * n + 1; int lrwork = 3 * n + 1; void* work = GPAW_MALLOC(double_complex, lwork); double* rwork = GPAW_MALLOC(double, lrwork); zheev_("V", "U", &n, (void*)COMPLEXP(a), &lda, DOUBLEP(w), work, &lwork, rwork, &lrwork, &info); free(work); free(rwork); } return Py_BuildValue("i", info); } PyObject* diagonalize_mr3(PyObject *self, PyObject *args) { PyArrayObject* a; PyArrayObject* w; PyArrayObject* z; if (!PyArg_ParseTuple(args, "OOO", &a, &w, &z)) return NULL; char jobz = 'V'; char range = 'A'; char uplo = 'U'; int n = PyArray_DIMS(a)[0]; int lda = MAX(1, n); double vl, vu; int il, iu; double abstol = dlamch_("Safe minimum"); int m = n; /* assume we find all eigenvalues */ int ldz = lda; int info = 0; int* isuppz = GPAW_MALLOC(int, 2*m); if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { /* Minimum workspace plus a little extra */ int lwork = 26 * n + 1; int liwork = 10 * n + 1; double* work = GPAW_MALLOC(double, lwork); int* iwork = GPAW_MALLOC(int, liwork); dsyevr_(&jobz, &range, &uplo, &n, DOUBLEP(a), &lda, &vl, &vu, &il, &iu, &abstol, &m, DOUBLEP(w), DOUBLEP(z), &ldz, isuppz, work, &lwork, iwork, &liwork, &info); free(work); free(iwork); } else { /* Minimum workspace plus a little extra */ int lwork = 2 * n + 1; int lrwork = 24 * n + 1; int liwork = 10 * n + 1; void* work = GPAW_MALLOC(double_complex, lwork); double* rwork = GPAW_MALLOC(double, lrwork); int* iwork = GPAW_MALLOC(int, liwork); zheevr_(&jobz, &range, &uplo, &n, (void*)COMPLEXP(a), &lda, &vl, &vu, &il, &iu, &abstol, &m, DOUBLEP(w), (void*)COMPLEXP(z), &ldz, isuppz, work, &lwork, rwork, &lrwork, iwork, &liwork, &info); free(work); free(rwork); free(iwork); } free(isuppz); // If this fails, fewer eigenvalues than request were computed assert (m == n); return Py_BuildValue("i", info); } PyObject* general_diagonalize(PyObject *self, PyObject *args) { PyArrayObject* a; PyArrayObject* w; PyArrayObject* b; PyArrayObject* z; int iu = -1; if (!PyArg_ParseTuple(args, "OOO|Oi", &a, &w, &b, &z, &iu)) return NULL; int itype = 1; char jobz = 'V'; char range = 'I'; char uplo = 'U'; int n = PyArray_DIMS(a)[0]; int lda = MAX(1, n); int ldb = lda; double vl, vu; int il = 1; double abstol = dlamch_("Safe minimum"); int m; int ldz = lda; int info = 0; int ispec = 1; int dummy = -1; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { // Optimal number of blocks for dsygv(x)_ int NB = ilaenv_(&ispec, "dsytrd", &uplo, &n, &dummy, &dummy, &dummy, 6, 1); if (iu == -1) { int lwork = MAX((NB + 2) * n, 3 * n + 1); double* work = GPAW_MALLOC(double, lwork); dsygv_(&itype, &jobz, &uplo, &n, DOUBLEP(a), &lda, DOUBLEP(b), &ldb, DOUBLEP(w), work, &lwork, &info); free(work); } else { int lwork = MAX((NB + 3) * n, 8 * n); int liwork = 5 * n; double* work = GPAW_MALLOC(double, lwork); int* iwork = GPAW_MALLOC(int, liwork); int* ifail = GPAW_MALLOC(int, n); dsygvx_(&itype, &jobz, &range, &uplo, &n, DOUBLEP(a), &lda, DOUBLEP(b), &ldb, &vl, &vu, &il, &iu, &abstol, &m, DOUBLEP(w), DOUBLEP(z), &ldz, work, &lwork, iwork, ifail, &info); free(iwork); free(work); free(ifail); assert (m == iu); } } else { // Optimal number of blocks for zhegv(x)_ int NB = ilaenv_(&ispec, "zhetrd", &uplo, &n, &dummy, &dummy, &dummy, 6, 1); if (iu == -1) { int lwork = MAX((NB + 1) * n, 2 * n + 1); int lrwork = MAX(1, 3 * n + 1); void* work = GPAW_MALLOC(double_complex, lwork); double* rwork = GPAW_MALLOC(double, lrwork); zhegv_(&itype, &jobz, &uplo, &n, (void*)COMPLEXP(a), &lda, (void*)COMPLEXP(b), &lda, DOUBLEP(w), work, &lwork, rwork, &lrwork, &info); free(work); free(rwork); } else { int lwork = MAX((NB + 1) * n, 2 * n); int lrwork = 7 * n; int liwork = 5 * n; void* work = GPAW_MALLOC(double_complex, lwork); double* rwork = GPAW_MALLOC(double, lrwork); int* iwork = GPAW_MALLOC(int, liwork); int* ifail = GPAW_MALLOC(int, n); zhegvx_(&itype, &jobz, &range, &uplo, &n, (void*)COMPLEXP(a), &lda, (void*)COMPLEXP(b), &ldb, &vl, &vu, &il, &iu, &abstol, &m, DOUBLEP(w), (void*)COMPLEXP(z), &ldz, work, &lwork, rwork, iwork, ifail, &info); free(work); free(rwork); free(iwork); free(ifail); assert (m == iu); } } return Py_BuildValue("i", info); } PyObject* inverse_cholesky(PyObject *self, PyObject *args) { PyArrayObject* a; if (!PyArg_ParseTuple(args, "O", &a)) return NULL; int n = PyArray_DIMS(a)[0]; int lda = MAX(1, n); int info = 0; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { dpotrf_("U", &n, (void*)DOUBLEP(a), &lda, &info); if (info == 0) { dtrtri_("U", "N", &n, (void*)DOUBLEP(a), &lda, &info); if (info == 0) { /* Make sure that the other diagonal is zero */ double* ap = DOUBLEP(a); ap++; for (int i = 0; i < n - 1; i++) { memset(ap, 0, (n-1-i) * sizeof(double)); ap += n + 1; } } } } else { zpotrf_("U", &n, (void*)COMPLEXP(a), &lda, &info); if (info == 0) { ztrtri_("U", "N", &n, (void*)DOUBLEP(a), &lda, &info); if (info == 0) { /* Make sure that lower diagonal is zero */ double_complex* ap = COMPLEXP(a); ap++; for (int i = 0; i < n - 1; i++) { memset(ap, 0, (n-1-i) * sizeof(double_complex)); ap += n + 1; } } } } return Py_BuildValue("i", info); } void swap(double *a, double *b) { double tmp=*b; *b = *a; *a = tmp; } void transpose(double *A, int n) { int i, j; int in=0; for(i=0;itype_num == NPY_DOUBLE) { int lwork = -1; double* work = GPAW_MALLOC(double, 1); double* wr = GPAW_MALLOC(double, n); double* wi = GPAW_MALLOC(double, n); int ldvl = 1; int ldvr = n; double* vl = 0; int i; /* get size of work needed */ dgeev_("No eigenvectors left", "Vectors right", &n, DOUBLEP(A), &lda, wr, wi, vl, &ldvl, DOUBLEP(v), &ldvr, work, &lwork, &info); lwork = (int) work[0]; free(work); work = GPAW_MALLOC(double, lwork); transpose(DOUBLEP(A),n); /* transform to Fortran form */ dgeev_("No eigenvectors left", "Vectors right", &n, DOUBLEP(A), &lda, wr, wi, vl, &ldvl, DOUBLEP(v), &ldvr, work, &lwork, &info); for(i=0;i dgeev i=%d,wi[i]=%g\n", i,wi[i]); DOUBLEP(w)[i]=wr[i]; } free(wr); free(wi); free(work); } return Py_BuildValue("i", info); } PyObject* inverse_general(PyObject *self, PyObject *args) { PyArrayObject* a; if (!PyArg_ParseTuple(args, "O", &a)) return NULL; int n = PyArray_DIMS(a)[0]; int m = n; int lda = n; int lwork = n; int* ipiv = GPAW_MALLOC(int, n); int info = 0; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { double* work = GPAW_MALLOC(double, lwork); dgetrf_(&n, &m, DOUBLEP(a), &lda, ipiv, &info); dgetri_(&n, DOUBLEP(a), &lda, ipiv, work, &lwork, &info); free(work); } else { void *work = GPAW_MALLOC(double_complex, lwork); zgetrf_(&n, &m, (void*)COMPLEXP(a), &lda, ipiv, &info); zgetri_(&n, (void*)COMPLEXP(a), &lda, ipiv, work, &lwork, &info); free(work); } free(ipiv); return Py_BuildValue("i", info); } PyObject* inverse_symmetric(PyObject *self, PyObject *args) { PyArrayObject* a; if (!PyArg_ParseTuple(args, "O", &a)) return NULL; int n = PyArray_DIMS(a)[0]; int lda = n; int lwork =n; int* ipiv = GPAW_MALLOC(int, n); int info = 0; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) { double* work = GPAW_MALLOC(double, lwork); dsytrf_("U", &n, DOUBLEP(a), &lda, ipiv, work, &lwork, &info); dsytri_("U", &n, DOUBLEP(a), &lda, ipiv, work, &info); free(work); } else { void *work = GPAW_MALLOC(double_complex, lwork); zsytrf_("U", &n, (void*)COMPLEXP(a), &lda, ipiv, work, &lwork, &info); zsytri_("U", &n, (void*)COMPLEXP(a), &lda, ipiv, work, &info); free(work); } free(ipiv); return Py_BuildValue("i", info); } PyObject* linear_solve_band(PyObject *self, PyObject *args) { PyArrayObject* a; PyArrayObject* b; int kl, ku, info=0, *ipiv; if(!PyArg_ParseTuple(args,"OOii",&a, &b,&kl,&ku)) return NULL; int n=PyArray_DIMS(a)[0]; int ldab=PyArray_DIMS(a)[1]; int ldb=PyArray_DIMS(b)[0]; int nrhs=PyArray_DIMS(b)[1]; ipiv = GPAW_MALLOC(int, n); zgbsv_(&n, &kl,&ku, &nrhs, (void*)COMPLEXP(a), &ldab, ipiv, (void*)COMPLEXP(b), &ldb, &info); free(ipiv); return Py_BuildValue("i",info); } PyObject* linear_solve_tridiag(PyObject *self, PyObject *args) { PyArrayObject* A; PyArrayObject* du; PyArrayObject* du2; PyArrayObject* dl; PyArrayObject* phi; int dim=0, one=1, info=0; if(!PyArg_ParseTuple(args,"iOOOOO", &dim, &A, &du, &dl, &du2, &phi)) return NULL; int ldb = dim; int *ipiv = GPAW_MALLOC(int, dim); zgttrf_(&dim, (void*)COMPLEXP(dl), (void*)COMPLEXP(A), (void*)COMPLEXP(du), (void*)COMPLEXP(du2), ipiv, &info); zgttrs_("N", &dim, &one, (void*)COMPLEXP(dl), (void*)COMPLEXP(A), (void*)COMPLEXP(du), (void*)COMPLEXP(du2), ipiv, (void*)COMPLEXP(phi), &ldb, &info); free(ipiv); return Py_BuildValue("i",info); } gpaw-0.11.0.13004/c/bmgs/0000775000175000017500000000000012553644063014625 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/c/bmgs/wrelax.c0000664000175000017500000000553512553643466016311 0ustar jensjjensj00000000000000/* This file (wrelax.c) is a modified copy of relax.c * with added support for nonlocal operator weights. * The original copyright note of relax.c follows: * Copyright (C) 2003-2007 CAMP * Copyright (C) 2005 CSC - IT Center for Science Ltd. * Please see the accompanying LICENSE file for further information. */ #include "bmgs.h" void bmgs_wrelax(const int relax_method, const int nweights, const bmgsstencil* stencils, const double** weights, double* a, double* b, const double* src, const double w) { const int n0 = stencils[0].n[0]; const int n1 = stencils[0].n[1]; const int n2 = stencils[0].n[2]; const int j0 = stencils[0].j[0]; const int j1 = stencils[0].j[1]; const int j2 = stencils[0].j[2]; a += (j0 + j1 + j2) / 2; if (relax_method == 1) { /* Weighted Gauss-Seidel relaxation for the equation "operator" b = src a contains the temporary array holding also the boundary values. */ for (int i0 = 0; i0 < n0; i0++) { for (int i1 = 0; i1 < n1; i1++) { for (int i2 = 0; i2 < n2; i2++) { double x = 0.0; double coef = 0.0; for (int iw = 0; iw < nweights; iw++) { double weight = weights[iw][0]; double tmp = 0.0; const bmgsstencil* s = &(stencils[iw]); for (int c = 1; c < s->ncoefs; c++) tmp += a[s->offsets[c]] * s->coefs[c]; tmp *= weight; x += tmp; coef += weight * s->coefs[0]; weights[iw]++; } x = (*src - x) / coef; *b++ = x; *a++ = x; src++; } a += j2; } a += j1; } } else { /* Weighted Jacobi relaxation for the equation "operator" b = src a contains the temporariry array holding also the boundary values. */ double temp; for (int i0 = 0; i0 < n0; i0++) { for (int i1 = 0; i1 < n1; i1++) { for (int i2 = 0; i2 < n2; i2++) { double x = 0.0; double coef = 0.0; for (int iw = 0; iw < nweights; iw++) { double weight = weights[iw][0]; double tmp = 0.0; const bmgsstencil* s = &(stencils[iw]); for (int c = 1; c < s->ncoefs; c++) tmp += a[s->offsets[c]] * s->coefs[c]; tmp *= weight; x += tmp; coef += weight * s->coefs[0]; weights[iw]++; } temp = (1.0 - w) * *b + w * (*src - x) / coef; *b++ = temp; a++; src++; } a += j2; } a += j1; } } } gpaw-0.11.0.13004/c/bmgs/bmgs.c0000664000175000017500000000106312553643466015727 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2005 CSC - IT Center for Science Ltd. * Please see the accompanying LICENSE file for further information. */ #include "fd.c" #include "wfd.c" #include "relax.c" #include "wrelax.c" #include "cut.c" #include "zero.c" #include "paste.c" #include "spline.c" #include "stencils.c" #include "restrict.c" #include "translate.c" #include "interpolate.c" #define BMGSCOMPLEX #include "fd.c" #include "wfd.c" #include "cut.c" #include "zero.c" #include "paste.c" #include "restrict.c" #include "interpolate.c" gpaw-0.11.0.13004/c/bmgs/fd.c0000664000175000017500000000364512553643466015400 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Please see the accompanying LICENSE file for further information. */ #include "bmgs.h" #include #include "../extensions.h" struct Z(fds){ int thread_id; int nthds; const bmgsstencil* s; const T* a; T* b; }; void *Z(bmgs_fd_worker)(void *threadarg) { struct Z(fds) *args = (struct Z(fds) *) threadarg; const T* a = args->a; T* b = args->b; const bmgsstencil* s = args->s; int chunksize = s->n[0] / args->nthds + 1; int nstart = args->thread_id * chunksize; if (nstart >= s->n[0]) return NULL; int nend = nstart + chunksize; if (nend > s->n[0]) nend = s->n[0]; for (int i0 = nstart; i0 < nend; i0++) { const T* aa = a + i0 * (s->j[1] + s->n[1] * (s->j[2] + s->n[2])); T* bb = b + i0 * s->n[1] * s->n[2]; for (int i1 = 0; i1 < s->n[1]; i1++) { for (int i2 = 0; i2 < s->n[2]; i2++) { T x = 0.0; for (int c = 0; c < s->ncoefs; c++) x += aa[s->offsets[c]] * s->coefs[c]; *bb++ = x; aa++; } aa += s->j[2]; } } return NULL; } void Z(bmgs_fd)(const bmgsstencil* s, const T* a, T* b) { a += (s->j[0] + s->j[1] + s->j[2]) / 2; int nthds = 1; #ifdef GPAW_OMP_MONLY if (getenv("OMP_NUM_THREADS") != NULL) nthds = atoi(getenv("OMP_NUM_THREADS")); #endif struct Z(fds) *wargs = GPAW_MALLOC(struct Z(fds), nthds); pthread_t *thds = GPAW_MALLOC(pthread_t, nthds); for(int i=0; i < nthds; i++) { (wargs+i)->thread_id = i; (wargs+i)->nthds = nthds; (wargs+i)->s = s; (wargs+i)->a = a; (wargs+i)->b = b; } #ifdef GPAW_OMP_MONLY for(int i=1; i < nthds; i++) pthread_create(thds + i, NULL, Z(bmgs_fd_worker), (void*) (wargs+i)); #endif Z(bmgs_fd_worker)(wargs); #ifdef GPAW_OMP_MONLY for(int i=1; i < nthds; i++) pthread_join(*(thds+i), NULL); #endif free(wargs); free(thds); } gpaw-0.11.0.13004/c/bmgs/stencils.c0000664000175000017500000001155512553643466016632 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2005 CSC - IT Center for Science Ltd. * Please see the accompanying LICENSE file for further information. */ #include #include "bmgs.h" // Expansion coefficients for finite difference Laplacian. The numbers are // from J. R. Chelikowsky et al., Phys. Rev. B 50, 11355 (1994): bmgsstencil bmgs_stencil(int ncoefs, const double* coefs, const long* offsets, int r, const long n[3]) { bmgsstencil stencil = {ncoefs, (double*)malloc(ncoefs * sizeof(double)), (long*)malloc(ncoefs * sizeof(long)), {n[0], n[1], n[2]}, {2 * r * (n[2] + 2 * r) * (n[1] + 2 * r), 2 * r * (n[2] + 2 * r), 2 * r}}; assert((stencil.coefs != NULL) && (stencil.offsets != NULL)); memcpy(stencil.coefs, coefs, ncoefs * sizeof(double)); memcpy(stencil.offsets, offsets, ncoefs * sizeof(long)); return stencil; } static const double laplace[4][5] = {{-2.0, 1.0, 0.0, 0.0, 0.0}, {-5.0/2.0, 4.0/3.0, -1.0/12.0, 0.0, 0.0}, {-49.0/18.0, 3.0/2.0, -3.0/20.0, 1.0/90.0, 0.0}, {-205.0/72.0, 8.0/5.0, -1.0/5.0, 8.0/315.0, -1.0/560.0}}; bmgsstencil bmgs_laplace(int k, double scale, const double h[3], const long n[3]) { int ncoefs = 3 * k - 2; double* coefs = (double*)malloc(ncoefs * sizeof(double)); long* offsets = (long*)malloc(ncoefs * sizeof(long)); assert((coefs != NULL) && (offsets != NULL)); double f1 = 1.0 / (h[0] * h[0]); double f2 = 1.0 / (h[1] * h[1]); double f3 = 1.0 / (h[2] * h[2]); int r = (k - 1) / 2; // range double s[3] = {(n[2] + 2 * r) * (n[1] + 2 * r), n[2] + 2 * r, 1}; int m = 0; for (int j = 1; j <= r; j++) { double c = scale * laplace[r - 1][j]; coefs[m] = c * f1; offsets[m++] = -j * s[0]; coefs[m] = c * f1; offsets[m++] = +j * s[0]; coefs[m] = c * f2; offsets[m++] = -j * s[1]; coefs[m] = c * f2; offsets[m++] = +j * s[1]; coefs[m] = c * f3; offsets[m++] = -j; coefs[m] = c * f3; offsets[m++] = +j; } double c = scale * laplace[r - 1][0]; coefs[m] = c * (f1 + f2 + f3); offsets[m] = 0; bmgsstencil stencil = {ncoefs, coefs, offsets, {n[0], n[1], n[2]}, {2 * r * (n[2] + 2 * r) * (n[1] + 2 * r), 2 * r * (n[2] + 2 * r), 2 * r}}; return stencil; } bmgsstencil bmgs_mslaplaceA(double scale, const double h[3], const long n[3]) { int ncoefs = 19; double* coefs = (double*)malloc(ncoefs * sizeof(double)); long* offsets = (long*)malloc(ncoefs * sizeof(long)); assert((coefs != NULL) && (offsets != NULL)); double e[3] = {-scale / (12.0 * h[0] * h[0]), -scale / (12.0 * h[1] * h[1]), -scale / (12.0 * h[2] * h[2])}; double f = -16.0 * (e[0] + e[1] + e[2]); double g[3] = {10.0 * e[0] + 0.125 * f, 10.0 * e[1] + 0.125 * f, 10.0 * e[2] + 0.125 * f}; double s[3] = {(n[2] + 2) * (n[1] + 2), n[2] + 2, 1}; int m = 0; coefs[m] = f; offsets[m++] = 0; for (int j = -1; j <= 1; j += 2) { coefs[m] = g[0]; offsets[m++] = j * s[0]; coefs[m] = g[1]; offsets[m++] = j * s[1]; coefs[m] = g[2]; offsets[m++] = j * s[2]; } for (int j = -1; j <= 1; j += 2) for (int k = -1; j <= 1; j += 2) { coefs[m] = e[1] + e[2]; offsets[m++] = -j * s[1] - k * s[2]; coefs[m] = e[0] + e[2]; offsets[m++] = -j * s[0] - k * s[2]; coefs[m] = e[0] + e[1]; offsets[m++] = -j * s[0] - k * s[1]; } bmgsstencil stencil = {ncoefs, coefs, offsets, {n[0], n[1], n[2]}, {2 * s[0], 2 * s[1], 2}}; return stencil; } bmgsstencil bmgs_mslaplaceB(const long n[3]) { int ncoefs = 7; double* coefs = (double*)malloc(ncoefs * sizeof(double)); long* offsets = (long*)malloc(ncoefs * sizeof(long)); assert((coefs != NULL) && (offsets != NULL)); double s[3] = {(n[2] + 2) * (n[1] + 2), n[2] + 2, 1}; int k = 0; coefs[k] = 0.5; offsets[k++] = 0; for (int j = -1; j <= 1; j += 2) { coefs[k] = 1.0 / 12.0; offsets[k++] = j * s[0]; coefs[k] = 1.0 / 12.0; offsets[k++] = j * s[1]; coefs[k] = 1.0 / 12.0; offsets[k++] = j * s[2]; } bmgsstencil stencil = {ncoefs, coefs, offsets, {n[0], n[1], n[2]}, {2 * s[0], 2 * s[1], 2}}; return stencil; } bmgsstencil bmgs_gradient(int k, int i, double h, const long n[3]) { int ncoefs = k - 1; double* coefs = (double*)malloc(ncoefs * sizeof(double)); long* offsets = (long*)malloc(ncoefs * sizeof(long)); assert((coefs != NULL) && (offsets != NULL)); int r = 1; double s[3] = {(n[2] + 2 * r) * (n[1] + 2 * r), n[2] + 2 * r, 1}; double c = 0.5 / h; coefs[0] = +c; offsets[0] = +s[i]; coefs[1] = -c; offsets[1] = -s[i]; bmgsstencil stencil = {ncoefs, coefs, offsets, {n[0], n[1], n[2]}, {2 * r * s[0], 2 * r * s[1], 2 * r}}; return stencil; } void bmgs_deletestencil(bmgsstencil* stencil) { free(stencil->coefs); free(stencil->offsets); } gpaw-0.11.0.13004/c/bmgs/spherical_harmonics.h0000664000175000017500000001526112553643466021026 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2009 CAMd * Please see the accompanying LICENSE file for further information. */ #define spherical_harmonics(l, f, x, y, z, r2, p) (\ {\ switch(l)\ {\ case 0:\ p[0] = f * 0.28209479177387814;\ break;\ case 1:\ p[0] = f * 0.48860251190291992 * y;\ p[1] = f * 0.48860251190291992 * z;\ p[2] = f * 0.48860251190291992 * x;\ break;\ case 2:\ p[0] = f * 1.0925484305920792 * x*y;\ p[1] = f * 1.0925484305920792 * y*z;\ p[2] = f * 0.31539156525252005 * (-r2+3*z*z);\ p[3] = f * 1.0925484305920792 * x*z;\ p[4] = f * 0.54627421529603959 * (-y*y+x*x);\ break;\ case 3:\ p[0] = f * 0.59004358992664352 * (-y*y*y+3*x*x*y);\ p[1] = f * 2.8906114426405538 * x*y*z;\ p[2] = f * 0.45704579946446577 * (5*y*z*z-y*r2);\ p[3] = f * 0.3731763325901154 * (-3*z*r2+5*z*z*z);\ p[4] = f * 0.45704579946446577 * (-x*r2+5*x*z*z);\ p[5] = f * 1.4453057213202769 * (-y*y*z+x*x*z);\ p[6] = f * 0.59004358992664352 * (x*x*x-3*x*y*y);\ break;\ case 4:\ p[0] = f * 2.5033429417967046 * (x*x*x*y-x*y*y*y);\ p[1] = f * 1.7701307697799307 * (3*x*x*y*z-y*y*y*z);\ p[2] = f * 0.94617469575756008 * (-x*y*r2+7*x*y*z*z);\ p[3] = f * 0.66904654355728921 * (-3*y*z*r2+7*y*z*z*z);\ p[4] = f * 0.10578554691520431 * (3*r2*r2-30*z*z*r2+35*z*z*z*z);\ p[5] = f * 0.66904654355728921 * (7*x*z*z*z-3*x*z*r2);\ p[6] = f * 0.47308734787878004 * (y*y*r2+7*x*x*z*z-x*x*r2-7*y*y*z*z);\ p[7] = f * 1.7701307697799307 * (x*x*x*z-3*x*y*y*z);\ p[8] = f * 0.62583573544917614 * (-6*x*x*y*y+x*x*x*x+y*y*y*y);\ break;\ default:\ assert(0 == 1);\ }\ }\ )\ #define spherical_harmonics_derivative_x(l, f, x, y, z, r2, p) (\ {\ switch(l)\ {\ case 0:\ p[0] = f * 0;\ break;\ case 1:\ p[0] = f * 0;\ p[1] = f * 0;\ p[2] = f * 0.48860251190291992;\ break;\ case 2:\ p[0] = f * 1.0925484305920792 * y;\ p[1] = f * 0;\ p[2] = f * 0.63078313050504009 * -x;\ p[3] = f * 1.0925484305920792 * z;\ p[4] = f * 1.0925484305920792 * x;\ break;\ case 3:\ p[0] = f * 3.5402615395598613 * x*y;\ p[1] = f * 2.8906114426405538 * y*z;\ p[2] = f * 0.91409159892893155 * -x*y;\ p[3] = f * 2.2390579955406924 * -x*z;\ p[4] = f * 0.45704579946446577 * (-r2-2*x*x+5*z*z);\ p[5] = f * 2.8906114426405538 * x*z;\ p[6] = f * 1.7701307697799307 * (-y*y+x*x);\ break;\ case 4:\ p[0] = f * 2.5033429417967046 * (-y*y*y+3*x*x*y);\ p[1] = f * 10.620784618679583 * x*y*z;\ p[2] = f * 0.94617469575756008 * (7*y*z*z-y*r2-2*x*x*y);\ p[3] = f * 4.0142792613437353 * -x*y*z;\ p[4] = f * 1.2694265629824517 * (x*r2-5*x*z*z);\ p[5] = f * 0.66904654355728921 * (-3*z*r2-6*x*x*z+7*z*z*z);\ p[6] = f * 0.94617469575756008 * (-x*r2-x*x*x+x*y*y+7*x*z*z);\ p[7] = f * 5.3103923093397913 * (-y*y*z+x*x*z);\ p[8] = f * 2.5033429417967046 * (-3*x*y*y+x*x*x);\ break;\ default:\ assert(0 == 1);\ }\ }\ )\ #define spherical_harmonics_derivative_y(l, f, x, y, z, r2, p) (\ {\ switch(l)\ {\ case 0:\ p[0] = f * 0;\ break;\ case 1:\ p[0] = f * 0.48860251190291992;\ p[1] = f * 0;\ p[2] = f * 0;\ break;\ case 2:\ p[0] = f * 1.0925484305920792 * x;\ p[1] = f * 1.0925484305920792 * z;\ p[2] = f * 0.63078313050504009 * -y;\ p[3] = f * 0;\ p[4] = f * 1.0925484305920792 * -y;\ break;\ case 3:\ p[0] = f * 1.7701307697799307 * (-y*y+x*x);\ p[1] = f * 2.8906114426405538 * x*z;\ p[2] = f * 0.45704579946446577 * (-2*y*y-r2+5*z*z);\ p[3] = f * 2.2390579955406924 * -y*z;\ p[4] = f * 0.91409159892893155 * -x*y;\ p[5] = f * 2.8906114426405538 * -y*z;\ p[6] = f * 3.5402615395598613 * -x*y;\ break;\ case 4:\ p[0] = f * 2.5033429417967046 * (x*x*x-3*x*y*y);\ p[1] = f * 5.3103923093397913 * (-y*y*z+x*x*z);\ p[2] = f * 0.94617469575756008 * (-x*r2-2*x*y*y+7*x*z*z);\ p[3] = f * 0.66904654355728921 * (-6*y*y*z-3*z*r2+7*z*z*z);\ p[4] = f * 1.2694265629824517 * (-5*y*z*z+y*r2);\ p[5] = f * 4.0142792613437353 * -x*y*z;\ p[6] = f * 0.94617469575756008 * (y*y*y-7*y*z*z+y*r2-x*x*y);\ p[7] = f * 10.620784618679583 * -x*y*z;\ p[8] = f * 2.5033429417967046 * (y*y*y-3*x*x*y);\ break;\ default:\ assert(0 == 1);\ }\ }\ )\ #define spherical_harmonics_derivative_z(l, f, x, y, z, r2, p) (\ {\ switch(l)\ {\ case 0:\ p[0] = f * 0;\ break;\ case 1:\ p[0] = f * 0;\ p[1] = f * 0.48860251190291992;\ p[2] = f * 0;\ break;\ case 2:\ p[0] = f * 0;\ p[1] = f * 1.0925484305920792 * y;\ p[2] = f * 1.2615662610100802 * z;\ p[3] = f * 1.0925484305920792 * x;\ p[4] = f * 0;\ break;\ case 3:\ p[0] = f * 0;\ p[1] = f * 2.8906114426405538 * x*y;\ p[2] = f * 3.6563663957157262 * y*z;\ p[3] = f * 1.1195289977703462 * (-r2+3*z*z);\ p[4] = f * 3.6563663957157262 * x*z;\ p[5] = f * 1.4453057213202769 * (-y*y+x*x);\ p[6] = f * 0;\ break;\ case 4:\ p[0] = f * 0;\ p[1] = f * 1.7701307697799307 * (-y*y*y+3*x*x*y);\ p[2] = f * 11.354096349090721 * x*y*z;\ p[3] = f * 2.0071396306718676 * (5*y*z*z-y*r2);\ p[4] = f * 1.6925687506432689 * (-3*z*r2+5*z*z*z);\ p[5] = f * 2.0071396306718676 * (-x*r2+5*x*z*z);\ p[6] = f * 5.6770481745453605 * (-y*y*z+x*x*z);\ p[7] = f * 1.7701307697799307 * (x*x*x-3*x*y*y);\ p[8] = f * 0;\ break;\ default:\ assert(0 == 1);\ }\ }\ )\ gpaw-0.11.0.13004/c/bmgs/paste.c0000664000175000017500000000163412553643466016117 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Please see the accompanying LICENSE file for further information. */ #include "bmgs.h" void Z(bmgs_paste)(const T* a, const int sizea[3], T* b, const int sizeb[3], const int startb[3]) { b += startb[2] + (startb[1] + startb[0] * sizeb[1]) * sizeb[2]; for (int i0 = 0; i0 < sizea[0]; i0++) { for (int i1 = 0; i1 < sizea[1]; i1++) { memcpy(b, a, sizea[2] * sizeof(T)); a += sizea[2]; b += sizeb[2]; } b += sizeb[2] * (sizeb[1] - sizea[1]); } } void Z(bmgs_pastep)(const T* a, const int sizea[3], T* b, const int sizeb[3], const int startb[3]) { b += startb[2] + (startb[1] + startb[0] * sizeb[1]) * sizeb[2]; for (int i0 = 0; i0 < sizea[0]; i0++) { for (int i1 = 0; i1 < sizea[1]; i1++) { for (int i2 = 0; i2 < sizea[2]; i2++) b[i2] += *a++; b += sizeb[2]; } b += sizeb[2] * (sizeb[1] - sizea[1]); } } gpaw-0.11.0.13004/c/bmgs/spline.c0000664000175000017500000006004212553643466016273 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2008 CAMd * Please see the accompanying LICENSE file for further information. */ #include #include #include #include "bmgs.h" bmgsspline bmgs_spline(int l, double dr, int nbins, double* f) { double c = 3.0 / (dr * dr); double* f2 = (double*)malloc((nbins + 1) * sizeof(double)); assert(f2 != NULL); double* u = (double*)malloc(nbins * sizeof(double)); assert(u != NULL); f2[0] = -0.5; u[0] = (f[1] - f[0]) * c; for (int b = 1; b < nbins; b++) { double p = 0.5 * f2[b - 1] + 2.0; f2[b] = -0.5 / p; u[b] = ((f[b + 1] - 2.0 * f[b] + f[b - 1]) * c - 0.5 * u[b - 1]) / p; } f2[nbins] = ((f[nbins - 1] * c - 0.5 * u[nbins - 1]) / (0.5 * f2[nbins - 1] + 1.0)); for (int b = nbins - 1; b >= 0; b--) f2[b] = f2[b] * f2[b + 1] + u[b]; double* data = (double*)malloc(4 * (nbins + 1) * sizeof(double)); assert(data != NULL); bmgsspline spline = {l, dr, nbins, data}; for (int b = 0; b < nbins; b++) { *data++ = f[b]; *data++ = (f[b + 1] - f[b]) / dr - (f2[b] / 3 + f2[b + 1] / 6) * dr; *data++ = 0.5 * f2[b]; *data++ = (f2[b + 1] - f2[b]) / (6 * dr); } data[0] = 0.0; data[1] = 0.0; data[2] = 0.0; data[3] = 0.0; free(u); free(f2); return spline; } double bmgs_splinevalue(const bmgsspline* spline, double r) { int b = r / spline->dr; if (b >= spline->nbins) return 0.0; double u = r - b * spline->dr; double* s = spline->data + 4 * b; return s[0] + u * (s[1] + u * (s[2] + u * s[3])); } void bmgs_get_value_and_derivative(const bmgsspline* spline, double r, double *f, double *dfdr) { int b = r / spline->dr; if (b >= spline->nbins) { *f = 0.0; *dfdr = 0.0; return; } double u = r - b * spline->dr; double* s = spline->data + 4 * b; *f = s[0] + u * (s[1] + u * (s[2] + u * s[3])); *dfdr = s[1] + u * (2.0 * s[2] + u * 3.0 * s[3]); } void bmgs_deletespline(bmgsspline* spline) { free(spline->data); } void bmgs_radial1(const bmgsspline* spline, const int n[3], const double C[3], const double h[3], int* b, double* d) { int nbins = spline->nbins; double dr = spline->dr; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double xx = x * x; double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double xxpyy = xx + y * y; double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++) { double r = sqrt(xxpyy + z * z); int j = r / dr; if (j < nbins) { *b++ = j; *d++ = r - j * dr; } else { *b++ = nbins; *d++ = 0.0; } z += h[2]; } y += h[1]; } x += h[0]; } } void bmgs_radial2(const bmgsspline* spline, const int n[3], const int* b, const double* d, double* f, double* g) { double dr = spline->dr; for (int q = 0; q < n[0] * n[1] * n[2]; q++) { int j = b[q]; const double* s = spline->data + 4 * j; double u = d[q]; f[q] = s[0] + u * (s[1] + u * (s[2] + u * s[3])); if (g != 0) { if (j == 0) g[q] = 2.0 * s[2] + u * 3.0 * s[3]; else g[q] = (s[1] + u * (2.0 * s[2] + u * 3.0 * s[3])) / (j * dr + u); } } } //Computer generated code! Hands off! // inserts values of f(r) r^l Y_lm(theta, phi) in elements of input array 'a' void bmgs_radial3(const bmgsspline* spline, int m, const int n[3], const double C[3], const double h[3], const double* f, double* a) { int l = spline->l; if (l == 0) for (int q = 0; q < n[0] * n[1] * n[2]; q++) a[q] = 0.28209479177387814 * f[q]; else if (l == 1) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { if (m == -1) a[q] = f[q] * 0.48860251190291992 * y; else if (m == 0) a[q] = f[q] * 0.48860251190291992 * z; else a[q] = f[q] * 0.48860251190291992 * x; z += h[2]; } y += h[1]; } x += h[0]; } } else if (l == 2) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { double r2 = x*x+y*y+z*z; if (m == -2) a[q] = f[q] * 1.0925484305920792 * x*y; else if (m == -1) a[q] = f[q] * 1.0925484305920792 * y*z; else if (m == 0) a[q] = f[q] * 0.31539156525252005 * (3*z*z-r2); else if (m == 1) a[q] = f[q] * 1.0925484305920792 * x*z; else a[q] = f[q] * 0.54627421529603959 * (x*x-y*y); z += h[2]; } y += h[1]; } x += h[0]; } } else if (l == 3) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { double r2 = x*x+y*y+z*z; if (m == -3) a[q] = f[q] * 0.59004358992664352 * (-y*y*y+3*x*x*y); else if (m == -2) a[q] = f[q] * 2.8906114426405538 * x*y*z; else if (m == -1) a[q] = f[q] * 0.45704579946446577 * (-y*r2+5*y*z*z); else if (m == 0) a[q] = f[q] * 0.3731763325901154 * (5*z*z*z-3*z*r2); else if (m == 1) a[q] = f[q] * 0.45704579946446577 * (5*x*z*z-x*r2); else if (m == 2) a[q] = f[q] * 1.4453057213202769 * (x*x*z-y*y*z); else a[q] = f[q] * 0.59004358992664352 * (x*x*x-3*x*y*y); z += h[2]; } y += h[1]; } x += h[0]; } } else if (l == 4) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { double r2 = x*x+y*y+z*z; if (m == -4) a[q] = f[q] * 2.5033429417967046 * (x*x*x*y-x*y*y*y); else if (m == -3) a[q] = f[q] * 1.7701307697799307 * (-y*y*y*z+3*x*x*y*z); else if (m == -2) a[q] = f[q] * 0.94617469575756008 * (-x*y*r2+7*x*y*z*z); else if (m == -1) a[q] = f[q] * 0.66904654355728921 * (-3*y*z*r2+7*y*z*z*z); else if (m == 0) a[q] = f[q] * 0.10578554691520431 * (-30*z*z*r2+3*r2*r2+35*z*z*z*z); else if (m == 1) a[q] = f[q] * 0.66904654355728921 * (7*x*z*z*z-3*x*z*r2); else if (m == 2) a[q] = f[q] * 0.47308734787878004 * (-x*x*r2+7*x*x*z*z+y*y*r2-7*y*y*z*z); else if (m == 3) a[q] = f[q] * 1.7701307697799307 * (x*x*x*z-3*x*y*y*z); else a[q] = f[q] * 0.62583573544917614 * (-6*x*x*y*y+x*x*x*x+y*y*y*y); z += h[2]; } y += h[1]; } x += h[0]; } } else assert(0 == 1); } // insert values of // d( f(r) * r^l Y_l^m ) d( r^l Y_l^m ) // --------------------- = g(r) q r^l Y_l^m + f(r) -------------- // dq dq // where q={x, y, z} and g(r) = 1/r*(df/dr) void bmgs_radiald3(const bmgsspline* spline, int m, int c, const int n[3], const double C[3], const double h[3], const double* f, const double* g, double* a) { int l = spline->l; // x if (c == 0 && l == 0) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { if (m == 0) a[q] = g[q] * 0.28209479177387814 * x; z += h[2]; } y += h[1]; } x += h[0]; } } else if (c == 0 && l == 1) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { if (m == -1) a[q] = g[q] * 0.48860251190291992 * x*y; else if (m == 0) a[q] = g[q] * 0.48860251190291992 * x*z; else a[q] = g[q] * 0.48860251190291992 * x*x + f[q] * 0.48860251190291992; z += h[2]; } y += h[1]; } x += h[0]; } } else if (c == 0 && l == 2) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { double r2 = x*x+y*y+z*z; if (m == -2) a[q] = g[q] * 1.0925484305920792 * x*x*y + f[q] * 1.0925484305920792 * y; else if (m == -1) a[q] = g[q] * 1.0925484305920792 * x*y*z; else if (m == 0) a[q] = g[q] * 0.31539156525252005 * (3*x*z*z-x*r2) + f[q] * 0.63078313050504009 * -x; else if (m == 1) a[q] = g[q] * 1.0925484305920792 * x*x*z + f[q] * 1.0925484305920792 * z; else a[q] = g[q] * 0.54627421529603959 * (x*x*x-x*y*y) + f[q] * 1.0925484305920792 * x; z += h[2]; } y += h[1]; } x += h[0]; } } else if (c == 0 && l == 3) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { double r2 = x*x+y*y+z*z; if (m == -3) a[q] = g[q] * 0.59004358992664352 * (3*x*x*x*y-x*y*y*y) + f[q] * 3.5402615395598613 * x*y; else if (m == -2) a[q] = g[q] * 2.8906114426405538 * x*x*y*z + f[q] * 2.8906114426405538 * y*z; else if (m == -1) a[q] = g[q] * 0.45704579946446577 * (-x*y*r2+5*x*y*z*z) + f[q] * 0.91409159892893155 * -x*y; else if (m == 0) a[q] = g[q] * 0.3731763325901154 * (5*x*z*z*z-3*x*z*r2) + f[q] * 2.2390579955406924 * -x*z; else if (m == 1) a[q] = g[q] * 0.45704579946446577 * (-x*x*r2+5*x*x*z*z) + f[q] * 0.45704579946446577 * (5*z*z-r2-2*x*x); else if (m == 2) a[q] = g[q] * 1.4453057213202769 * (x*x*x*z-x*y*y*z) + f[q] * 2.8906114426405538 * x*z; else a[q] = g[q] * 0.59004358992664352 * (-3*x*x*y*y+x*x*x*x) + f[q] * 1.7701307697799307 * (x*x-y*y); z += h[2]; } y += h[1]; } x += h[0]; } } else if (c == 0 && l == 4) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { double r2 = x*x+y*y+z*z; if (m == -4) a[q] = g[q] * 2.5033429417967046 * (-x*x*y*y*y+x*x*x*x*y) + f[q] * 2.5033429417967046 * (-y*y*y+3*x*x*y); else if (m == -3) a[q] = g[q] * 1.7701307697799307 * (-x*y*y*y*z+3*x*x*x*y*z) + f[q] * 10.620784618679583 * x*y*z; else if (m == -2) a[q] = g[q] * 0.94617469575756008 * (7*x*x*y*z*z-x*x*y*r2) + f[q] * 0.94617469575756008 * (-y*r2+7*y*z*z-2*x*x*y); else if (m == -1) a[q] = g[q] * 0.66904654355728921 * (-3*x*y*z*r2+7*x*y*z*z*z) + f[q] * 4.0142792613437353 * -x*y*z; else if (m == 0) a[q] = g[q] * 0.10578554691520431 * (-30*x*z*z*r2+3*x*r2*r2+35*x*z*z*z*z) + f[q] * 1.2694265629824517 * (-5*x*z*z+x*r2); else if (m == 1) a[q] = g[q] * 0.66904654355728921 * (-3*x*x*z*r2+7*x*x*z*z*z) + f[q] * 0.66904654355728921 * (7*z*z*z-6*x*x*z-3*z*r2); else if (m == 2) a[q] = g[q] * 0.47308734787878004 * (-x*x*x*r2+x*y*y*r2+7*x*x*x*z*z-7*x*y*y*z*z) + f[q] * 0.94617469575756008 * (-x*x*x+7*x*z*z-x*r2+x*y*y); else if (m == 3) a[q] = g[q] * 1.7701307697799307 * (-3*x*x*y*y*z+x*x*x*x*z) + f[q] * 5.3103923093397913 * (x*x*z-y*y*z); else a[q] = g[q] * 0.62583573544917614 * (-6*x*x*x*y*y+x*y*y*y*y+x*x*x*x*x) + f[q] * 2.5033429417967046 * (-3*x*y*y+x*x*x); z += h[2]; } y += h[1]; } x += h[0]; } } // y else if (c == 1 && l == 0) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { if (m == 0) a[q] = g[q] * 0.28209479177387814 * y; z += h[2]; } y += h[1]; } x += h[0]; } } else if (c == 1 && l == 1) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { if (m == -1) a[q] = g[q] * 0.48860251190291992 * y*y + f[q] * 0.48860251190291992; else if (m == 0) a[q] = g[q] * 0.48860251190291992 * y*z; else a[q] = g[q] * 0.48860251190291992 * x*y; z += h[2]; } y += h[1]; } x += h[0]; } } else if (c == 1 && l == 2) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { double r2 = x*x+y*y+z*z; if (m == -2) a[q] = g[q] * 1.0925484305920792 * x*y*y + f[q] * 1.0925484305920792 * x; else if (m == -1) a[q] = g[q] * 1.0925484305920792 * y*y*z + f[q] * 1.0925484305920792 * z; else if (m == 0) a[q] = g[q] * 0.31539156525252005 * (-y*r2+3*y*z*z) + f[q] * 0.63078313050504009 * -y; else if (m == 1) a[q] = g[q] * 1.0925484305920792 * x*y*z; else a[q] = g[q] * 0.54627421529603959 * (-y*y*y+x*x*y) + f[q] * 1.0925484305920792 * -y; z += h[2]; } y += h[1]; } x += h[0]; } } else if (c == 1 && l == 3) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { double r2 = x*x+y*y+z*z; if (m == -3) a[q] = g[q] * 0.59004358992664352 * (3*x*x*y*y-y*y*y*y) + f[q] * 1.7701307697799307 * (x*x-y*y); else if (m == -2) a[q] = g[q] * 2.8906114426405538 * x*y*y*z + f[q] * 2.8906114426405538 * x*z; else if (m == -1) a[q] = g[q] * 0.45704579946446577 * (-y*y*r2+5*y*y*z*z) + f[q] * 0.45704579946446577 * (5*z*z-r2-2*y*y); else if (m == 0) a[q] = g[q] * 0.3731763325901154 * (-3*y*z*r2+5*y*z*z*z) + f[q] * 2.2390579955406924 * -y*z; else if (m == 1) a[q] = g[q] * 0.45704579946446577 * (-x*y*r2+5*x*y*z*z) + f[q] * 0.91409159892893155 * -x*y; else if (m == 2) a[q] = g[q] * 1.4453057213202769 * (-y*y*y*z+x*x*y*z) + f[q] * 2.8906114426405538 * -y*z; else a[q] = g[q] * 0.59004358992664352 * (x*x*x*y-3*x*y*y*y) + f[q] * 3.5402615395598613 * -x*y; z += h[2]; } y += h[1]; } x += h[0]; } } else if (c == 1 && l == 4) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { double r2 = x*x+y*y+z*z; if (m == -4) a[q] = g[q] * 2.5033429417967046 * (x*x*x*y*y-x*y*y*y*y) + f[q] * 2.5033429417967046 * (x*x*x-3*x*y*y); else if (m == -3) a[q] = g[q] * 1.7701307697799307 * (3*x*x*y*y*z-y*y*y*y*z) + f[q] * 5.3103923093397913 * (x*x*z-y*y*z); else if (m == -2) a[q] = g[q] * 0.94617469575756008 * (-x*y*y*r2+7*x*y*y*z*z) + f[q] * 0.94617469575756008 * (-2*x*y*y+7*x*z*z-x*r2); else if (m == -1) a[q] = g[q] * 0.66904654355728921 * (-3*y*y*z*r2+7*y*y*z*z*z) + f[q] * 0.66904654355728921 * (7*z*z*z-3*z*r2-6*y*y*z); else if (m == 0) a[q] = g[q] * 0.10578554691520431 * (3*y*r2*r2-30*y*z*z*r2+35*y*z*z*z*z) + f[q] * 1.2694265629824517 * (y*r2-5*y*z*z); else if (m == 1) a[q] = g[q] * 0.66904654355728921 * (-3*x*y*z*r2+7*x*y*z*z*z) + f[q] * 4.0142792613437353 * -x*y*z; else if (m == 2) a[q] = g[q] * 0.47308734787878004 * (-7*y*y*y*z*z+y*y*y*r2+7*x*x*y*z*z-x*x*y*r2) + f[q] * 0.94617469575756008 * (y*r2+y*y*y-7*y*z*z-x*x*y); else if (m == 3) a[q] = g[q] * 1.7701307697799307 * (x*x*x*y*z-3*x*y*y*y*z) + f[q] * 10.620784618679583 * -x*y*z; else a[q] = g[q] * 0.62583573544917614 * (x*x*x*x*y-6*x*x*y*y*y+y*y*y*y*y) + f[q] * 2.5033429417967046 * (y*y*y-3*x*x*y); z += h[2]; } y += h[1]; } x += h[0]; } } // z else if (c == 2 && l == 0) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { if (m == 0) a[q] = g[q] * 0.28209479177387814 * z; z += h[2]; } y += h[1]; } x += h[0]; } } else if (c == 2 && l == 1) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { if (m == -1) a[q] = g[q] * 0.48860251190291992 * y*z; else if (m == 0) a[q] = g[q] * 0.48860251190291992 * z*z + f[q] * 0.48860251190291992; else a[q] = g[q] * 0.48860251190291992 * x*z; z += h[2]; } y += h[1]; } x += h[0]; } } else if (c == 2 && l == 2) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { double r2 = x*x+y*y+z*z; if (m == -2) a[q] = g[q] * 1.0925484305920792 * x*y*z; else if (m == -1) a[q] = g[q] * 1.0925484305920792 * y*z*z + f[q] * 1.0925484305920792 * y; else if (m == 0) a[q] = g[q] * 0.31539156525252005 * (3*z*z*z-z*r2) + f[q] * 1.2615662610100802 * z; else if (m == 1) a[q] = g[q] * 1.0925484305920792 * x*z*z + f[q] * 1.0925484305920792 * x; else a[q] = g[q] * 0.54627421529603959 * (x*x*z-y*y*z); z += h[2]; } y += h[1]; } x += h[0]; } } else if (c == 2 && l == 3) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { double r2 = x*x+y*y+z*z; if (m == -3) a[q] = g[q] * 0.59004358992664352 * (-y*y*y*z+3*x*x*y*z); else if (m == -2) a[q] = g[q] * 2.8906114426405538 * x*y*z*z + f[q] * 2.8906114426405538 * x*y; else if (m == -1) a[q] = g[q] * 0.45704579946446577 * (-y*z*r2+5*y*z*z*z) + f[q] * 3.6563663957157262 * y*z; else if (m == 0) a[q] = g[q] * 0.3731763325901154 * (-3*z*z*r2+5*z*z*z*z) + f[q] * 1.1195289977703462 * (3*z*z-r2); else if (m == 1) a[q] = g[q] * 0.45704579946446577 * (5*x*z*z*z-x*z*r2) + f[q] * 3.6563663957157262 * x*z; else if (m == 2) a[q] = g[q] * 1.4453057213202769 * (x*x*z*z-y*y*z*z) + f[q] * 1.4453057213202769 * (x*x-y*y); else a[q] = g[q] * 0.59004358992664352 * (x*x*x*z-3*x*y*y*z); z += h[2]; } y += h[1]; } x += h[0]; } } else if (c == 2 && l == 4) { int q = 0; double x = C[0]; for (int i0 = 0; i0 < n[0]; i0++) { double y = C[1]; for (int i1 = 0; i1 < n[1]; i1++) { double z = C[2]; for (int i2 = 0; i2 < n[2]; i2++, q++) { double r2 = x*x+y*y+z*z; if (m == -4) a[q] = g[q] * 2.5033429417967046 * (x*x*x*y*z-x*y*y*y*z); else if (m == -3) a[q] = g[q] * 1.7701307697799307 * (-y*y*y*z*z+3*x*x*y*z*z) + f[q] * 1.7701307697799307 * (-y*y*y+3*x*x*y); else if (m == -2) a[q] = g[q] * 0.94617469575756008 * (-x*y*z*r2+7*x*y*z*z*z) + f[q] * 11.354096349090721 * x*y*z; else if (m == -1) a[q] = g[q] * 0.66904654355728921 * (-3*y*z*z*r2+7*y*z*z*z*z) + f[q] * 2.0071396306718676 * (-y*r2+5*y*z*z); else if (m == 0) a[q] = g[q] * 0.10578554691520431 * (-30*z*z*z*r2+3*z*r2*r2+35*z*z*z*z*z) + f[q] * 1.6925687506432689 * (5*z*z*z-3*z*r2); else if (m == 1) a[q] = g[q] * 0.66904654355728921 * (-3*x*z*z*r2+7*x*z*z*z*z) + f[q] * 2.0071396306718676 * (5*x*z*z-x*r2); else if (m == 2) a[q] = g[q] * 0.47308734787878004 * (-x*x*z*r2+7*x*x*z*z*z+y*y*z*r2-7*y*y*z*z*z) + f[q] * 5.6770481745453605 * (x*x*z-y*y*z); else if (m == 3) a[q] = g[q] * 1.7701307697799307 * (x*x*x*z*z-3*x*y*y*z*z) + f[q] * 1.7701307697799307 * (x*x*x-3*x*y*y); else a[q] = g[q] * 0.62583573544917614 * (x*x*x*x*z-6*x*x*y*y*z+y*y*y*y*z); z += h[2]; } y += h[1]; } x += h[0]; } } else assert(0 == 1); } gpaw-0.11.0.13004/c/bmgs/translate.c0000664000175000017500000000265012553643466016777 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Please see the accompanying LICENSE file for further information. */ #include #include "bmgs.h" void bmgs_translate(double* a, const int sizea[3], const int size[3], const int start1[3], const int start2[3]) { const double* restrict s = a + start1[2] + (start1[1] + start1[0] * sizea[1]) * sizea[2]; double* restrict d = a + start2[2] + (start2[1] + start2[0] * sizea[1]) * sizea[2]; for (int i0 = 0; i0 < size[0]; i0++) { for (int i1 = 0; i1 < size[1]; i1++) { memcpy(d, s, size[2] * sizeof(double)); s += sizea[2]; d += sizea[2]; } s += sizea[2] * (sizea[1] - size[1]); d += sizea[2] * (sizea[1] - size[1]); } } void bmgs_translatemz(double_complex* a, const int sizea[3], const int size[3], const int start1[3], const int start2[3], double_complex phase) { const double_complex* restrict s = a + start1[2] + (start1[1] + start1[0] * sizea[1]) * sizea[2]; double_complex* restrict d = a + start2[2] + (start2[1] + start2[0] * sizea[1]) * sizea[2]; for (int i0 = 0; i0 < size[0]; i0++) { for (int i1 = 0; i1 < size[1]; i1++) { for (int i2 = 0; i2 < size[2]; i2++) d[i2] = phase * s[i2]; s += sizea[2]; d += sizea[2]; } s += sizea[2] * (sizea[1] - size[1]); d += sizea[2] * (sizea[1] - size[1]); } } gpaw-0.11.0.13004/c/bmgs/bmgs.h0000664000175000017500000001153312553643466015737 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2008 CAMd * Copyright (C) 2005 CSC - IT Center for Science Ltd. * Please see the accompanying LICENSE file for further information. */ #ifndef DOUBLECOMPLEXDEFINED # define DOUBLECOMPLEXDEFINED 1 # include typedef double complex double_complex; #endif #undef T #undef Z #ifndef BMGSCOMPLEX # define T double # define Z(f) f #else # define T double_complex # define Z(f) f ## z #endif #ifndef BMGS_H #define BMGS_H //#ifdef NO_C99_COMPLEX typedef int bool; #define true 1 #define false 0 //#else //#include //#endif typedef struct { int ncoefs; double* coefs; long* offsets; long n[3]; long j[3]; } bmgsstencil; typedef struct { int l; double dr; int nbins; double* data; } bmgsspline; bmgsstencil bmgs_stencil(int ncoefs, const double* coefs, const long* offsets, int range, const long size[3]); bmgsstencil bmgs_laplace(int k, double scale, const double h[3], const long n[3]); bmgsstencil bmgs_mslaplaceA(double scale, const double h[3], const long n[3]); bmgsstencil bmgs_mslaplaceB(const long n[3]); bmgsstencil bmgs_gradient(int k, int i, double h, const long n[3]); void bmgs_deletestencil(bmgsstencil* spline); bmgsspline bmgs_spline(int l, double dr, int nbins, double* f); double bmgs_splinevalue(const bmgsspline* spline, double r); void bmgs_get_value_and_derivative(const bmgsspline* spline, double r, double *f, double *dfdr); void bmgs_deletespline(bmgsspline* spline); void bmgs_radial1(const bmgsspline* spline, const int n[3], const double C[3], const double h[3], int* b, double* d); void bmgs_radial2(const bmgsspline* spline, const int n[3], const int* b, const double* d, double* f, double* g); void bmgs_radial3(const bmgsspline* spline, int m, const int n[3], const double C[3], const double h[3], const double* f, double* a); void bmgs_radiald3(const bmgsspline* spline, int m, int c, const int n[3], const double C[3], const double h[3], const double* f, const double* g, double* a); void bmgs_fd(const bmgsstencil* s, const double* a, double* b); void bmgs_wfd(int nweights, const bmgsstencil* stencils, const double** weights, const double* a, double* b); void bmgs_relax(const int relax_method, const bmgsstencil* s, double* a, double* b, const double* src, const double w); void bmgs_wrelax(const int relax_method, const int nweights, const bmgsstencil* stencils, const double** weights, double* a, double* b, const double* src, const double w); void bmgs_cut(const double* a, const int n[3], const int c[3], double* b, const int m[3]); void bmgs_zero(double* a, const int n[3], const int c[3], const int s[3]); void bmgs_paste(const double* a, const int n[3], double* b, const int m[3], const int c[3]); void bmgs_pastep(const double* a, const int n[3], double* b, const int m[3], const int c[3]); void bmgs_rotate(const double* a, const int size[3], double* b, double angle, int d, long c, double*, long*, long*, double*, long*, long*, int exact); void bmgs_translate(double* a, const int sizea[3], const int size[3], const int start1[3], const int start2[3]); void bmgs_restrict(int k, double* a, const int n[3], double* b, double* w); void bmgs_interpolate(int k, int skip[3][2], const double* a, const int n[3], double* b, double* w); // complex routines: void bmgs_fdz(const bmgsstencil* s, const double_complex* a, double_complex* b); void bmgs_wfdz(int nweights, const bmgsstencil* stencils, const double** weights, const double_complex* a, double_complex* b); void bmgs_cutz(const double_complex* a, const int n[3], const int c[3], double_complex* b, const int m[3]); void bmgs_cutmz(const double_complex* a, const int n[3], const int c[3], double_complex* b, const int m[3], double_complex phase); void bmgs_zeroz(double_complex* a, const int n[3], const int c[3], const int s[3]); void bmgs_pastez(const double_complex* a, const int n[3], double_complex* b, const int m[3], const int c[3]); void bmgs_pastepz(const double_complex* a, const int n[3], double_complex* b, const int m[3], const int c[3]); void bmgs_rotatez(const double_complex* a, const int size[3], double_complex* b, double angle, int d, long c, double*, long*, long*, double*, long*, long*, int exact); void bmgs_translatemz(double_complex* a, const int sizea[3], const int size[3], const int start1[3], const int start2[3], double_complex phase); void bmgs_restrictz(int k, double_complex* a, const int n[3], double_complex* b, double_complex* w); void bmgs_interpolatez(int k, int skip[3][2], const double_complex* a, const int n[3], double_complex* b, double_complex* w); #endif gpaw-0.11.0.13004/c/bmgs/restrict.c0000664000175000017500000000706512553643466016646 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Please see the accompanying LICENSE file for further information. */ #include "bmgs.h" #include #include "../extensions.h" #ifdef K struct RST1DA{ int thread_id; int nthds; const T* a; int n; int m; T* b; }; void *RST1DW(void *threadarg) { struct RST1DA *args = (struct RST1DA *) threadarg; int m = args->m; int chunksize = m / args->nthds + 1; int nstart = args->thread_id * chunksize; if (nstart >= m) return NULL; int nend = nstart + chunksize; if (nend > m) nend = m; for (int j = 0; j < m; j++) { const T* aa = args->a + j * (args->n * 2 + K * 2 - 3); T* bb = args->b + j; for (int i = 0; i < args->n; i++) { if (K == 2) bb[0] = 0.5 * (aa[0] + 0.5 * (aa[1] + aa[-1])); else if (K == 4) bb[0] = 0.5 * (aa[0] + 0.5625 * (aa[1] + aa[-1]) + -0.0625 * (aa[3] + aa[-3])); else if (K == 6) bb[0] = 0.5 * (aa[0] + 0.58593750 * (aa[1] + aa[-1]) + -0.09765625 * (aa[3] + aa[-3]) + 0.01171875 * (aa[5] + aa[-5])); else bb[0] = 0.5 * (aa[0] + 0.59814453125 * (aa[1] + aa[-1]) + -0.11962890625 * (aa[3] + aa[-3]) + 0.02392578125 * (aa[5] + aa[-5]) + -0.00244140625 * (aa[7] + aa[-7])); aa += 2; bb += m; } } return NULL; } void RST1D(const T* a, int n, int m, T* b) { a += K - 1; int nthds = 1; #ifdef GPAW_OMP_MONLY if (getenv("OMP_NUM_THREADS") != NULL) nthds = atoi(getenv("OMP_NUM_THREADS")); #endif struct RST1DA *wargs = GPAW_MALLOC(struct RST1DA, nthds); pthread_t *thds = GPAW_MALLOC(pthread_t, nthds); for(int i=0; i < nthds; i++) { (wargs+i)->thread_id = i; (wargs+i)->nthds = nthds; (wargs+i)->a = a; (wargs+i)->n = n; (wargs+i)->m = m; (wargs+i)->b = b; } #ifdef GPAW_OMP_MONLY for(int i=1; i < nthds; i++) pthread_create(thds + i, NULL, RST1DW, (void*) (wargs+i)); #endif RST1DW(wargs); #ifdef GPAW_OMP_MONLY for(int i=1; i < nthds; i++) pthread_join(*(thds+i), NULL); #endif free(wargs); free(thds); } #else # define K 2 # define RST1D Z(bmgs_restrict1D2) # define RST1DA Z(bmgs_restrict1D2_args) # define RST1DW Z(bmgs_restrict1D2_worker) # include "restrict.c" # undef RST1D # undef RST1DA # undef RST1DW # undef K # define K 4 # define RST1D Z(bmgs_restrict1D4) # define RST1DA Z(bmgs_restrict1D4_args) # define RST1DW Z(bmgs_restrict1D4_worker) # include "restrict.c" # undef RST1D # undef RST1DA # undef RST1DW # undef K # define K 6 # define RST1D Z(bmgs_restrict1D6) # define RST1DA Z(bmgs_restrict1D6_args) # define RST1DW Z(bmgs_restrict1D6_worker) # include "restrict.c" # undef RST1D # undef RST1DA # undef RST1DW # undef K # define K 8 # define RST1D Z(bmgs_restrict1D8) # define RST1DA Z(bmgs_restrict1D8_args) # define RST1DW Z(bmgs_restrict1D8_worker) # include "restrict.c" # undef RST1D # undef RST1DA # undef RST1DW # undef K void Z(bmgs_restrict)(int k, T* a, const int n[3], T* b, T* w) { void (*plg)(const T*, int, int, T*); if (k == 2) plg = Z(bmgs_restrict1D2); else if (k == 4) plg = Z(bmgs_restrict1D4); else if (k == 6) plg = Z(bmgs_restrict1D6); else plg = Z(bmgs_restrict1D8); int e = k * 2 - 3; plg(a, (n[2] - e) / 2, n[0] * n[1], w); plg(w, (n[1] - e) / 2, n[0] * (n[2] - e) / 2, a); plg(a, (n[0] - e) / 2, (n[1] - e) * (n[2] - e) / 4, b); } #endif gpaw-0.11.0.13004/c/bmgs/zero.c0000664000175000017500000000067612553643466015767 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Please see the accompanying LICENSE file for further information. */ #include #include "bmgs.h" void Z(bmgs_zero)(T* a, const int n[3], const int c[3], const int s[3]) { a += c[2] + (c[1] + c[0] * n[1]) * n[2]; for (int i0 = 0; i0 < s[0]; i0++) { for (int i1 = 0; i1 < s[1]; i1++) { memset(a, 0, s[2] * sizeof(T)); a += n[2]; } a += n[2] * (n[1] - s[1]); } } gpaw-0.11.0.13004/c/bmgs/relax.c0000664000175000017500000000356712553643466016125 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2005 CSC - IT Center for Science Ltd. * Please see the accompanying LICENSE file for further information. */ #include "bmgs.h" void bmgs_relax(const int relax_method, const bmgsstencil* s, double* a, double* b, const double* src, const double w) { if (relax_method == 1) { /* Weighted Gauss-Seidel relaxation for the equation "operator" b = src a contains the temporary array holding also the boundary values. */ // Coefficient needed multiple times later const double coef = 1.0/s->coefs[0]; // The number of steps in each direction long nstep[3] = {s->n[0], s->n[1], s->n[2]}; a += (s->j[0] + s->j[1] + s->j[2]) / 2; for (int i0 = 0; i0 < nstep[0]; i0++) { for (int i1 = 0; i1 < nstep[1]; i1++) { for (int i2 = 0; i2 < nstep[2]; i2++) { double x = 0.0; for (int c = 1; c < s->ncoefs; c++) x += a[s->offsets[c]] * s->coefs[c]; x = (*src - x) * coef; *b++ = x; *a++ = x; src++; } a += s->j[2]; } a += s->j[1]; } } else { /* Weighted Jacobi relaxation for the equation "operator" b = src a contains the temporariry array holding also the boundary values. */ double temp; a += (s->j[0] + s->j[1] + s->j[2]) / 2; for (int i0 = 0; i0 < s->n[0]; i0++) { for (int i1 = 0; i1 < s->n[1]; i1++) { for (int i2 = 0; i2 < s->n[2]; i2++) { double x = 0.0; for (int c = 1; c < s->ncoefs; c++) x += a[s->offsets[c]] * s->coefs[c]; temp = (1.0 - w) * *b + w * (*src - x)/s->coefs[0]; *b++ = temp; a++; src++; } a += s->j[2]; } a += s->j[1]; } } } gpaw-0.11.0.13004/c/bmgs/interpolate.c0000664000175000017500000001011112553643466017317 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Please see the accompanying LICENSE file for further information. */ #include "bmgs.h" #include #include "../extensions.h" #ifdef K struct IP1DA{ int thread_id; int nthds; const T* a; int n; int m; T* b; int *skip; }; void *IP1DW(void *threadarg) { struct IP1DA *args = (struct IP1DA *) threadarg; int m = args->m; int chunksize = m / args->nthds + 1; int nstart = args->thread_id * chunksize; if (nstart >= m) return NULL; int nend = nstart + chunksize; if (nend > m) nend = m; for (int j = nstart; j < nend; j++) { const T* aa = args->a + j * (K - 1 - args->skip[1] + args->n); T* bb = args->b + j; for (int i = 0; i < args->n; i++) { if (i == 0 && args->skip[0]) bb -= m; else bb[0] = aa[0]; if (i == args->n - 1 && args->skip[1]) bb -= m; else { if (K == 2) bb[m] = 0.5 * (aa[0] + aa[1]); else if (K == 4) bb[m] = ( 0.5625 * (aa[ 0] + aa[1]) + -0.0625 * (aa[-1] + aa[2])); else if (K == 6) bb[m] = ( 0.58593750 * (aa[ 0] + aa[1]) + -0.09765625 * (aa[-1] + aa[2]) + 0.01171875 * (aa[-2] + aa[3])); else bb[m] = ( 0.59814453125 * (aa[ 0] + aa[1]) + -0.11962890625 * (aa[-1] + aa[2]) + 0.02392578125 * (aa[-2] + aa[3]) + -0.00244140625 * (aa[-3] + aa[4])); } aa++; bb += 2 * m; } } return NULL; } void IP1D(const T* a, int n, int m, T* b, int skip[2]) { a += K / 2 - 1; int nthds = 1; #ifdef GPAW_OMP_MONLY if (getenv("OMP_NUM_THREADS") != NULL) nthds = atoi(getenv("OMP_NUM_THREADS")); #endif struct IP1DA *wargs = GPAW_MALLOC(struct IP1DA, nthds); pthread_t *thds = GPAW_MALLOC(pthread_t, nthds); for(int i=0; i < nthds; i++) { (wargs+i)->thread_id = i; (wargs+i)->nthds = nthds; (wargs+i)->a = a; (wargs+i)->n = n; (wargs+i)->m = m; (wargs+i)->b = b; (wargs+i)->skip = skip; } #ifdef GPAW_OMP_MONLY for(int i=1; i < nthds; i++) pthread_create(thds + i, NULL, IP1DW, (void*) (wargs+i)); #endif IP1DW(wargs); #ifdef GPAW_OMP_MONLY for(int i=1; i < nthds; i++) pthread_join(*(thds+i), NULL); #endif free(wargs); free(thds); } #else # define K 2 # define IP1D Z(bmgs_interpolate1D2) # define IP1DA Z(bmgs_interpolate1D2_args) # define IP1DW Z(bmgs_interpolate1D2_worker) # include "interpolate.c" # undef IP1D # undef IP1DA # undef IP1DW # undef K # define K 4 # define IP1D Z(bmgs_interpolate1D4) # define IP1DA Z(bmgs_interpolate1D4_args) # define IP1DW Z(bmgs_interpolate1D4_worker) # include "interpolate.c" # undef IP1D # undef IP1DA # undef IP1DW # undef K # define K 6 # define IP1D Z(bmgs_interpolate1D6) # define IP1DA Z(bmgs_interpolate1D6_args) # define IP1DW Z(bmgs_interpolate1D6_worker) # include "interpolate.c" # undef IP1D # undef IP1DA # undef IP1DW # undef K # define K 8 # define IP1D Z(bmgs_interpolate1D8) # define IP1DA Z(bmgs_interpolate1D8_args) # define IP1DW Z(bmgs_interpolate1D8_worker) # include "interpolate.c" # undef IP1D # undef IP1DA # undef IP1DW # undef K void Z(bmgs_interpolate)(int k, int skip[3][2], const T* a, const int size[3], T* b, T* w) { void (*ip)(const T*, int, int, T*, int[2]); if (k == 2) ip = Z(bmgs_interpolate1D2); else if (k == 4) ip = Z(bmgs_interpolate1D4); else if (k == 6) ip = Z(bmgs_interpolate1D6); else ip = Z(bmgs_interpolate1D8); int e = k - 1; ip(a, size[2] - e + skip[2][1], size[0] * size[1], b, skip[2]); ip(b, size[1] - e + skip[1][1], size[0] * ((size[2] - e) * 2 - skip[2][0] + skip[2][1]), w, skip[1]); ip(w, size[0] - e + skip[0][1], ((size[1] - e) * 2 - skip[1][0] + skip[1][1]) * ((size[2] - e) * 2 - skip[2][0] + skip[2][1]), b, skip[0]); } #endif gpaw-0.11.0.13004/c/bmgs/cut.c0000664000175000017500000000175312553643466015600 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Please see the accompanying LICENSE file for further information. */ #include #include "bmgs.h" void Z(bmgs_cut)(const T* a, const int n[3], const int c[3], T* b, const int m[3]) { a += c[2] + (c[1] + c[0] * n[1]) * n[2]; for (int i0 = 0; i0 < m[0]; i0++) { for (int i1 = 0; i1 < m[1]; i1++) { memcpy(b, a, m[2] * sizeof(T)); a += n[2]; b += m[2]; } a += n[2] * (n[1] - m[1]); } } #ifdef BMGSCOMPLEX void bmgs_cutmz(const double_complex* a, const int sizea[3], const int start[3], double_complex* b, const int sizeb[3], double_complex p) { a += start[2] + (start[1] + start[0] * sizea[1]) * sizea[2]; for (int i0 = 0; i0 < sizeb[0]; i0++) { for (int i1 = 0; i1 < sizeb[1]; i1++) { for (int i2 = 0; i2 < sizeb[2]; i2++) b[i2] = p * a[i2]; a += sizea[2]; b += sizeb[2]; } a += sizea[2] * (sizea[1] - sizeb[1]); } } #endif gpaw-0.11.0.13004/c/bmgs/wfd.c0000664000175000017500000000557712553643466015575 0ustar jensjjensj00000000000000/* This file (wfd.c) is a modified copy of fd.c * with added support for nonlocal operator weights. * The original copyright note of fd.c follows: * Copyright (C) 2003-2007 CAMP * Please see the accompanying LICENSE file for further information. */ #include "bmgs.h" #include #include "../extensions.h" struct Z(wfds){ int thread_id; int nthds; int nweights; const bmgsstencil* s; const double** w; const T* a; T* b; }; void *Z(bmgs_wfd_worker)(void *threadarg) { struct Z(wfds) *args = (struct Z(wfds) *) threadarg; const T* a = args->a; T* b = args->b; const bmgsstencil* stencils = args->s; const int n0 = stencils[0].n[0]; const int n1 = stencils[0].n[1]; const int n2 = stencils[0].n[2]; const int j1 = stencils[0].j[1]; const int j2 = stencils[0].j[2]; const double** weights = (const double**) GPAW_MALLOC(double*, args->nweights); int chunksize = n0 / args->nthds + 1; int nstart = args->thread_id * chunksize; if (nstart >= n0) return NULL; int nend = nstart + chunksize; if (nend > n0) nend = n0; for (int i0 = nstart; i0 < nend; i0++) { const T* aa = a + i0 * (j1 + n1 * (j2 + n2)); T* bb = b + i0 * n1 * n2; for (int iw = 0; iw < args->nweights; iw++) weights[iw] = args->w[iw] + i0 * n1 * n2; for (int i1 = 0; i1 < n1; i1++) { for (int i2 = 0; i2 < n2; i2++) { T x = 0.0; for (int iw = 0; iw < args->nweights; iw++) { const bmgsstencil* s = &(stencils[iw]); T tmp = 0.0; for (int c = 0; c < s->ncoefs; c++) tmp += aa[s->offsets[c]] * s->coefs[c]; tmp *= weights[iw][0]; x += tmp; weights[iw]++; } *bb++ = x; aa++; } aa += j2; } } free(weights); return NULL; } void Z(bmgs_wfd)(int nweights, const bmgsstencil* stencils, const double** weights, const T* a, T* b) { a += (stencils[0].j[0] + stencils[0].j[1] + stencils[0].j[2]) / 2; int nthds = 1; #ifdef GPAW_OMP_MONLY if (getenv("OMP_NUM_THREADS") != NULL) nthds = atoi(getenv("OMP_NUM_THREADS")); #endif struct Z(wfds) *wargs = GPAW_MALLOC(struct Z(wfds), nthds); pthread_t *thds = GPAW_MALLOC(pthread_t, nthds); for(int i=0; i < nthds; i++) { (wargs+i)->thread_id = i; (wargs+i)->nthds = nthds; (wargs+i)->nweights = nweights; (wargs+i)->s = stencils; (wargs+i)->w = weights; (wargs+i)->a = a; (wargs+i)->b = b; } #ifdef GPAW_OMP_MONLY for(int i=1; i < nthds; i++) pthread_create(thds + i, NULL, Z(bmgs_wfd_worker), (void*) (wargs+i)); #endif Z(bmgs_wfd_worker)(wargs); #ifdef GPAW_OMP_MONLY for(int i=1; i < nthds; i++) pthread_join(*(thds+i), NULL); #endif free(wargs); free(thds); } gpaw-0.11.0.13004/c/cerf.c0000664000175000017500000001320112553643466014763 0ustar jensjjensj00000000000000#include #include "extensions.h" #include #include #define eps 1.e-15 double_complex itpp_erf(double_complex z); PyObject* cerf(PyObject *self, PyObject *args) { double complex z, res; if (!PyArg_ParseTuple(args, "D", &z)) return NULL; res = itpp_erf(z); return Py_BuildValue("D", &res); } /* taken from http://prdownloads.sourceforge.net/itpp/itpp-3.10.7.tar.bz2 and transformed to C */ /*! * \file * \brief Implementation of scalar functions * \author Tony Ottosson, Pal Frenger and Adam Piatyszek * * $Date: 2006-08-19 10:53:33 +0200 (sob, 19 sie 2006) $ * $Revision: 643 $ * * ------------------------------------------------------------------------- * * IT++ - C++ library of mathematical, signal processing, speech processing, * and communications classes and functions * * Copyright (C) 1995-2006 (see AUTHORS file for a list of contributors) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * ------------------------------------------------------------------------- */ double_complex itpp_cerf_series(double_complex z); double_complex itpp_cerfc_continued_fraction(double_complex z); double_complex itpp_cerf_continued_fraction(double_complex z); double_complex itpp_cerf_rybicki(double_complex z); double cabs(double_complex z) { return sqrt(creal(z) * creal(z) + cimag(z) * cimag(z)); } /* * This function calculates a well known error function erf(z) for * complex z. Three methods are implemented. Which one is used * depends on z. */ double_complex itpp_erf(double_complex z) { // Use the method appropriate to size of z - // there probably ought to be an extra option for NaN z, or infinite z if (cabs(z) < 2.0) return itpp_cerf_series(z); else { if (fabs(creal(z)) < 0.5) // XXX neither rybicki nor continued_fraction seem to work here // return itpp_cerf_rybicki(z); //return itpp_cerf_continued_fraction(z); return itpp_cerf_series(z); else return itpp_cerf_continued_fraction(z); } } /* * Abramawitz and Stegun: Eq. (7.1.5) gives a series for erf(z) good * for all z, but converges faster for smallish abs(z), say abs(z) < 2. */ double_complex itpp_cerf_series(double_complex z) { double_complex sum, term, z2, oldsum; double error; sum = 0.0; term = z; z2 = z * z; oldsum = 1.e32; for (int n = 0; 1; n++) { sum += term / (2. * n + 1); term *= -z2 / (1. * n + 1); error = cabs(sum / oldsum - 1.); if (error < eps) { return sum * (2.0 / sqrt(M_PI)); } oldsum = sum; } } /* * Abramowitz and Stegun: Eq. (7.1.14) gives this continued fraction * for erfc(z) * * erfc(z) = sqrt(pi).exp(-z^2). 1 1/2 1 3/2 2 5/2 * --- --- --- --- --- --- ... * z + z + z + z + z + z + * * This is evaluated using Lentz's method, as described in the * narative of Numerical Recipes in C. * * The continued fraction is true providing real(z) > 0. In practice * we like real(z) to be significantly greater than 0, say greater * than 0.5. */ double_complex itpp_cerfc_continued_fraction(double_complex z) { // first calculate z+ 1/2 1 // --- --- ... // z + z + double_complex f, C, D, delta; double a; // printf("itpp_cerfc_continued_fraction\n"); f = z; C = f; D = 0.0; a = 0.0; do { a += 0.5; D = z + a * D; C = z + a / C; if ((creal(D) == 0.0) && (cimag(D) == 0.0)) D = DBL_MIN; D = 1.0 / D; delta = C * D; f = f * delta; } while (cabs(1.0 - delta) > eps); // Do the first term of the continued fraction f = 1.0 / f; // and do the final scaling f = f * exp(-z * z) / sqrt(M_PI); return f; } double_complex itpp_cerf_continued_fraction(double_complex z) { if (creal(z) > 0) return 1.0 - itpp_cerfc_continued_fraction(z); else return -1.0 + itpp_cerfc_continued_fraction(-z); } /* * Numerical Recipes quotes a formula due to Rybicki for evaluating * Dawson's Integral: * * exp(-x^2) integral exp(t^2).dt = 1/sqrt(pi) lim sum exp(-(z-n.h)^2) / n * 0 to x h->0 n odd * * This can be adapted to erf(z). */ double_complex itpp_cerf_rybicki(double_complex z) { double h = 0.2; // numerical experiment suggests this is small enough printf("itpp_cerf_rybicki"); // choose an even n0, and then shift z->z-n0.h and n->n-h. // n0 is chosen so that real((z-n0.h)^2) is as small as possible. int n0 = 2 * ((int)(cimag(z) / (2 * h) + 0.5)); double_complex z0 = I * n0 * h; double_complex zp = z - z0; double_complex sum = 0.0; // limits of sum chosen so that the end sums of the sum are // fairly small. In this case exp(-(35.h)^2)=5e-22 for (int np = -35; np <= 35; np += 2) { double_complex t = creal(zp) + I * (cimag(zp) - np * h); double_complex b = (exp(t * t) / ((double)(np + n0))); sum += b; } sum *= 2.0 * exp(-z * z) / M_PI; sum = - cimag(sum) + creal(sum) * I; return sum; } gpaw-0.11.0.13004/c/lcao.c0000664000175000017500000001323612553643466014772 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2009 CAMd * Please see the accompanying LICENSE file for further information. */ #include #include "localized_functions.h" #include "extensions.h" #include "bmgs/bmgs.h" #ifdef GPAW_NO_UNDERSCORE_BLAS # define dgemv_ dgemv # define dgemm_ dgemm #endif int dgemv_(char *trans, int *m, int * n, double *alpha, double *a, int *lda, double *x, int *incx, double *beta, double *y, int *incy); int dgemm_(char *transa, char *transb, int *m, int * n, int *k, const double *alpha, double *a, int *lda, double *b, int *ldb, double *beta, double *c, int *ldc); // +-----------n // +----m +----m | +----c+m | // | | | | | | | | // | b | = | v | * | | a | | // | | | | | | | | // 0----+ 0----+ | c----+ | // | | // 0-----------+ void cut(const double* a, const int n[3], const int c[3], const double* v, double* b, const int m[3]) { a += c[2] + (c[1] + c[0] * n[1]) * n[2]; for (int i0 = 0; i0 < m[0]; i0++) { for (int i1 = 0; i1 < m[1]; i1++) { for (int i2 = 0; i2 < m[2]; i2++) b[i2] = v[i2] * a[i2]; a += n[2]; b += m[2]; v += m[2]; } a += n[2] * (n[1] - m[1]); } } PyObject * overlap(PyObject* self, PyObject *args) { PyObject* lfs_b_obj; PyArrayObject* m_b_obj; PyArrayObject* phase_bk_obj; PyArrayObject* vt_sG_obj; PyArrayObject* Vt_skmm_obj; if (!PyArg_ParseTuple(args, "OOOOO", &lfs_b_obj, &m_b_obj, &phase_bk_obj, &vt_sG_obj, &Vt_skmm_obj)) return NULL; int nk = PyArray_DIMS(phase_bk_obj)[1]; int nm = PyArray_DIMS(Vt_skmm_obj)[2]; int nspins = PyArray_DIMS(vt_sG_obj)[0]; const long *m_b = LONGP(m_b_obj); const double complex *phase_bk = COMPLEXP(phase_bk_obj); const double *vt_sG = DOUBLEP(vt_sG_obj); double *Vt_smm = 0; double complex *Vt_skmm = 0; if (nk == 0) Vt_smm = DOUBLEP(Vt_skmm_obj); else Vt_skmm = COMPLEXP(Vt_skmm_obj); int nb = PyList_Size(lfs_b_obj); int nmem = 0; double* a1 = 0; for (int b1 = 0; b1 < nb; b1++) { const LocalizedFunctionsObject* lf1 = (const LocalizedFunctionsObject*)PyList_GetItem(lfs_b_obj, b1); int m1 = m_b[b1]; int nao1 = lf1->nf; double* f1 = lf1->f; double* vt1 = GPAW_MALLOC(double, lf1->ng0 * nspins); for (int s = 0; s < nspins; s++) bmgs_cut(vt_sG + s * lf1->ng, lf1->size, lf1->start, vt1 + s * lf1->ng0, lf1->size0); for (int b2 = b1; b2 < nb; b2++) { const LocalizedFunctionsObject* lf2 = (const LocalizedFunctionsObject*)PyList_GetItem(lfs_b_obj, b2); int beg[3]; int end[3]; int size[3]; int beg1[3]; int beg2[3]; bool overlap = true; for (int c = 0; c < 3; c++) { beg[c] = MAX(lf1->start[c], lf2->start[c]); end[c] = MIN(lf1->start[c] + lf1->size0[c], lf2->start[c] + lf2->size0[c]); size[c] = end[c] - beg[c]; if (size[c] <= 0) { overlap = false; continue; } beg1[c] = beg[c] - lf1->start[c]; beg2[c] = beg[c] - lf2->start[c]; } int nao2 = lf2->nf; if (overlap) { int ng = size[0] * size[1] * size[2]; int n = ng * (nao1 + nao2) + nao1 * nao2; if (n > nmem) { if (nmem != 0) free(a1); nmem = n; a1 = GPAW_MALLOC(double, nmem); } double* a2 = a1 + ng * nao1; double* H = a2 + ng * nao2; double* f2 = lf2->f; double* vt2 = lf2->w; double dv = lf1->dv; int m2 = m_b[b2]; if (b2 > b1) for (int i = 0; i < nao2; i++) bmgs_cut(f2 + i * lf2->ng0, lf2->size0, beg2, a2 + i * ng, size); else a2 = f2; for (int s = 0; s < nspins; s++) { if (b2 > b1) { bmgs_cut(vt1 + s * lf1->ng0, lf1->size0, beg1, vt2, size); for (int i = 0; i < nao1; i++) cut(f1 + i * lf1->ng0, lf1->size0, beg1, vt2, a1 + i * ng, size); } else { for (int i1 = 0; i1 < nao1; i1++) for (int g = 0; g < ng; g++) a1[i1 * ng + g] = (vt1[g + s * lf1->ng0] * f1[i1 * ng + g]); } double zero = 0.0; dgemm_("t", "n", &nao2, &nao1, &ng, &dv, a2, &ng, a1, &ng, &zero, H, &nao2); if (nk == 0) { double* Vt_mm = (Vt_smm + s * nm * nm + m1 + m2 * nm); if (b2 == b1) for (int i1 = 0; i1 < nao1; i1++) for (int i2 = i1; i2 < nao2; i2++) Vt_mm[i1 + i2 * nm] += H[i2 + i1 * nao2]; else if (m1 == m2) for (int i1 = 0; i1 < nao1; i1++) for (int i2 = i1; i2 < nao2; i2++) Vt_mm[i1 + i2 * nm] += (H[i2 + i1 * nao2] + H[i1 + i2 * nao2]); else for (int ii = 0, i1 = 0; i1 < nao1; i1++) for (int i2 = 0; i2 < nao2; i2++, ii++) Vt_mm[i1 + i2 * nm] += H[ii]; } else for (int k = 0; k < nk; k++) { double complex* Vt_mm = (Vt_skmm + (s * nk + k) * nm * nm + m1 + m2 * nm); if (b2 == b1) for (int i1 = 0; i1 < nao1; i1++) for (int i2 = i1; i2 < nao2; i2++) Vt_mm[i1 + i2 * nm] += H[i2 + i1 * nao2]; else { double complex phase = \ (phase_bk[b1 * nk + k] * conj(phase_bk[b2 * nk + k])); if (m1 == m2) for (int i1 = 0; i1 < nao1; i1++) for (int i2 = i1; i2 < nao2; i2++) Vt_mm[i1 + i2 * nm] += \ (phase * H[i2 + i1 * nao2] + conj(phase) * H[i1 + i2 * nao2]); else for (int ii = 0, i1 = 0; i1 < nao1; i1++) for (int i2 = 0; i2 < nao2; i2++, ii++) Vt_mm[i1 + i2 * nm] += phase * H[ii]; } } } } } free(vt1); } if (nmem != 0) free(a1); Py_RETURN_NONE; } gpaw-0.11.0.13004/c/mpi.c0000664000175000017500000010663612553643466014650 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2009 CAMd * Copyright (C) 2005-2009 CSC - IT Center for Science Ltd. * Please see the accompanying LICENSE file for further information. */ #include #ifdef PARALLEL #define PY_ARRAY_UNIQUE_SYMBOL GPAW_ARRAY_API #define NO_IMPORT_ARRAY #include #include #include "extensions.h" #include #include "mympi.h" #ifdef __bgp__ #include #endif // Check that array is well-behaved and contains data that can be sent. #define CHK_ARRAY(a) if ((a) == NULL || !PyArray_Check(a) \ || !PyArray_ISCARRAY(a) || !PyArray_ISNUMBER(a)) { \ PyErr_SetString(PyExc_TypeError, \ "Not a proper NumPy array for MPI communication."); \ return NULL; } // Check that two arrays have the same type, and the size of the // second is a given multiple of the size of the first #define CHK_ARRAYS(a,b,n) \ if ((PyArray_TYPE(a) != PyArray_TYPE(b)) \ || (PyArray_SIZE(b) != PyArray_SIZE(a) * n)) { \ PyErr_SetString(PyExc_ValueError, \ "Incompatible array types or sizes."); \ return NULL; } // Check that a processor number is valid #define CHK_PROC(n) if (n < 0 || n >= self->size) {\ PyErr_SetString(PyExc_ValueError, "Invalid processor number."); \ return NULL; } // Check that a processor number is valid or is -1 #define CHK_PROC_DEF(n) if (n < -1 || n >= self->size) {\ PyErr_SetString(PyExc_ValueError, "Invalid processor number."); \ return NULL; } // Check that a processor number is valid and is not this processor #define CHK_OTHER_PROC(n) if (n < 0 || n >= self->size || n == self->rank) { \ PyErr_SetString(PyExc_ValueError, "Invalid processor number."); \ return NULL; } // MPI request object, so we can store a reference to the buffer, // preventing its early deallocation. typedef struct { PyObject_HEAD MPI_Request rq; PyObject *buffer; int status; } GPAW_MPI_Request; static PyObject *mpi_request_wait(GPAW_MPI_Request *self, PyObject *noargs) { if (self->status == 0) { // Calling wait multiple times is allowed but meaningless (as in the MPI standard) Py_RETURN_NONE; } #ifndef GPAW_MPI_DEBUG MPI_Wait(&(self->rq), MPI_STATUS_IGNORE); #else int ret = MPI_Wait(&(self->rq), MPI_STATUS_IGNORE); if (ret != MPI_SUCCESS) { PyErr_SetString(PyExc_RuntimeError, "MPI_Wait error occured."); return NULL; } #endif Py_DECREF(self->buffer); self->status = 0; Py_RETURN_NONE; } static PyObject *mpi_request_test(GPAW_MPI_Request *self, PyObject *noargs) { if (self->status == 0) { Py_RETURN_TRUE; // Already completed } int flag; #ifndef GPAW_MPI_DEBUG MPI_Test(&(self->rq), &flag, MPI_STATUS_IGNORE); // Can this change the Python string? #else int ret = MPI_Test(&(self->rq), &flag, MPI_STATUS_IGNORE); // Can this change the Python string? if (ret != MPI_SUCCESS) { PyErr_SetString(PyExc_RuntimeError, "MPI_Test error occured."); return NULL; } #endif if (flag) { Py_DECREF(self->buffer); self->status = 0; Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } static void mpi_request_dealloc(GPAW_MPI_Request *self) { if (self->status) { PyObject *none = mpi_request_wait(self, NULL); Py_DECREF(none); } PyObject_Del(self); } static PyMemberDef mpi_request_members[] = { {"status", T_INT, offsetof(GPAW_MPI_Request, status), READONLY, "status of the request, non-zero if communication is pending."}, {NULL} }; static PyMethodDef mpi_request_methods[] = { {"wait", (PyCFunction) mpi_request_wait, METH_NOARGS, "Wait for the communication to complete." }, {"test", (PyCFunction) mpi_request_test, METH_NOARGS, "Test if the communication has completed." }, {NULL} }; PyTypeObject GPAW_MPI_Request_type = { PyVarObject_HEAD_INIT(NULL, 0) "MPI_Request", /*tp_name*/ sizeof(GPAW_MPI_Request), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)mpi_request_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash */ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ "MPI request object", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ mpi_request_methods, /* tp_methods */ mpi_request_members, 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ }; static GPAW_MPI_Request *NewMPIRequest(void) { GPAW_MPI_Request *self; self = PyObject_NEW(GPAW_MPI_Request, &GPAW_MPI_Request_type); if (self == NULL) return NULL; memset(&(self->rq), 0, sizeof(MPI_Request)); self->buffer = NULL; self->status = 1; // Active return self; } static void mpi_dealloc(MPIObject *obj) { if (obj->comm == MPI_COMM_WORLD) { # ifndef GPAW_INTERPRETER MPI_Finalize(); # endif } else MPI_Comm_free(&(obj->comm)); Py_XDECREF(obj->parent); free(obj->members); PyObject_DEL(obj); } static PyObject * mpi_sendreceive(MPIObject *self, PyObject *args, PyObject *kwargs) { PyArrayObject* a; PyArrayObject* b; int dest, src; int sendtag = 123; int recvtag = 123; static char *kwlist[] = {"a", "dest", "b", "src", "sendtag", "recvtag", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OiOi|ii:sendreceive", kwlist, &a, &dest, &b, &src, &sendtag, &recvtag)) return NULL; CHK_ARRAY(a); CHK_OTHER_PROC(dest); CHK_ARRAY(b); CHK_OTHER_PROC(src); int nsend = PyArray_DESCR(a)->elsize; for (int d = 0; d < PyArray_NDIM(a); d++) nsend *= PyArray_DIM(a,d); int nrecv = PyArray_DESCR(b)->elsize; for (int d = 0; d < PyArray_NDIM(b); d++) nrecv *= PyArray_DIM(b,d); #ifndef GPAW_MPI_DEBUG MPI_Sendrecv(PyArray_BYTES(a), nsend, MPI_BYTE, dest, sendtag, PyArray_BYTES(b), nrecv, MPI_BYTE, src, recvtag, self->comm, MPI_STATUS_IGNORE); #else int ret = MPI_Sendrecv(PyArray_BYTES(a), nsend, MPI_BYTE, dest, sendtag, PyArray_BYTES(b), nrecv, MPI_BYTE, src, recvtag, self->comm, MPI_STATUS_IGNORE); if (ret != MPI_SUCCESS) { PyErr_SetString(PyExc_RuntimeError, "MPI_Sendrecv error occured."); return NULL; } #endif Py_RETURN_NONE; } static PyObject * mpi_receive(MPIObject *self, PyObject *args, PyObject *kwargs) { PyArrayObject* a; int src; int tag = 123; int block = 1; static char *kwlist[] = {"a", "src", "tag", "block", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|ii:receive", kwlist, &a, &src, &tag, &block)) return NULL; CHK_ARRAY(a); CHK_OTHER_PROC(src); int n = PyArray_DESCR(a)->elsize; for (int d = 0; d < PyArray_NDIM(a); d++) n *= PyArray_DIM(a, d); if (block) { #ifndef GPAW_MPI_DEBUG MPI_Recv(PyArray_BYTES(a), n, MPI_BYTE, src, tag, self->comm, MPI_STATUS_IGNORE); #else int ret = MPI_Recv(PyArray_BYTES(a), n, MPI_BYTE, src, tag, self->comm, MPI_STATUS_IGNORE); if (ret != MPI_SUCCESS) { PyErr_SetString(PyExc_RuntimeError, "MPI_Recv error occured."); return NULL; } #endif Py_RETURN_NONE; } else { GPAW_MPI_Request *req = NewMPIRequest(); if (req == NULL) return NULL; req->buffer = (PyObject*)a; Py_INCREF(req->buffer); #ifndef GPAW_MPI_DEBUG MPI_Irecv(PyArray_BYTES(a), n, MPI_BYTE, src, tag, self->comm, &(req->rq)); #else int ret = MPI_Irecv(PyArray_BYTES(a), n, MPI_BYTE, src, tag, self->comm, &(req->rq)); if (ret != MPI_SUCCESS) { PyErr_SetString(PyExc_RuntimeError, "MPI_Irecv error occured."); return NULL; } #endif return (PyObject *) req; } } static PyObject * mpi_send(MPIObject *self, PyObject *args, PyObject *kwargs) { PyArrayObject* a; int dest; int tag = 123; int block = 1; static char *kwlist[] = {"a", "dest", "tag", "block", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|ii:send", kwlist, &a, &dest, &tag, &block)) return NULL; CHK_ARRAY(a); CHK_OTHER_PROC(dest); int n = PyArray_DESCR(a)->elsize; for (int d = 0; d < PyArray_NDIM(a); d++) n *= PyArray_DIM(a,d); if (block) { #ifndef GPAW_MPI_DEBUG MPI_Send(PyArray_BYTES(a), n, MPI_BYTE, dest, tag, self->comm); #else int ret = MPI_Send(PyArray_BYTES(a), n, MPI_BYTE, dest, tag, self->comm); if (ret != MPI_SUCCESS) { PyErr_SetString(PyExc_RuntimeError, "MPI_Send error occured."); return NULL; } #endif Py_RETURN_NONE; } else { GPAW_MPI_Request *req = NewMPIRequest(); req->buffer = (PyObject*)a; Py_INCREF(a); #ifndef GPAW_MPI_DEBUG MPI_Isend(PyArray_BYTES(a), n, MPI_BYTE, dest, tag, self->comm, &(req->rq)); #else int ret = MPI_Isend(PyArray_BYTES(a), n, MPI_BYTE, dest, tag, self->comm, &(req->rq)); if (ret != MPI_SUCCESS) { PyErr_SetString(PyExc_RuntimeError, "MPI_Isend error occured."); return NULL; } #endif return (PyObject *)req; } } static PyObject * mpi_ssend(MPIObject *self, PyObject *args, PyObject *kwargs) { PyArrayObject* a; int dest; int tag = 123; static char *kwlist[] = {"a", "dest", "tag", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|i:send", kwlist, &a, &dest, &tag)) return NULL; CHK_ARRAY(a); CHK_OTHER_PROC(dest); int n = PyArray_DESCR(a)->elsize; for (int d = 0; d < PyArray_NDIM(a); d++) n *= PyArray_DIM(a,d); MPI_Ssend(PyArray_BYTES(a), n, MPI_BYTE, dest, tag, self->comm); Py_RETURN_NONE; } static PyObject * mpi_name(MPIObject *self, PyObject *noargs) { char name[MPI_MAX_PROCESSOR_NAME]; int resultlen; MPI_Get_processor_name(name, &resultlen); return Py_BuildValue("s#", name, resultlen); } static PyObject * mpi_abort(MPIObject *self, PyObject *args) { int errcode; if (!PyArg_ParseTuple(args, "i:abort", &errcode)) return NULL; MPI_Abort(self->comm, errcode); Py_RETURN_NONE; } static PyObject * mpi_barrier(MPIObject *self) { MPI_Barrier(self->comm); Py_RETURN_NONE; } static PyObject * mpi_test(MPIObject *self, PyObject *args) { GPAW_MPI_Request* s; if (!PyArg_ParseTuple(args, "O!:wait", &GPAW_MPI_Request_type, &s)) return NULL; return mpi_request_test(s, NULL); } static PyObject * mpi_testall(MPIObject *self, PyObject *requests) { int n; // Number of requests MPI_Request *rqs = NULL; int flag = 0; if (!PySequence_Check(requests)) { PyErr_SetString(PyExc_TypeError, "mpi.testall: argument must be a sequence"); return NULL; } // Extract the request objects n = PySequence_Size(requests); assert(n >= 0); // This cannot fail. rqs = GPAW_MALLOC(MPI_Request, n); assert(rqs != NULL); for (int i = 0; i < n; i++) { PyObject *o = PySequence_GetItem(requests, i); if (o == NULL) return NULL; if (Py_TYPE(o) != &GPAW_MPI_Request_type) { Py_DECREF(o); free(rqs); PyErr_SetString(PyExc_TypeError, "mpi.testall: argument must be a sequence of MPI requests"); return NULL; } GPAW_MPI_Request *s = (GPAW_MPI_Request *)o; rqs[i] = s->rq; Py_DECREF(o); } // Do the actual test. #ifndef GPAW_MPI_DEBUG MPI_Testall(n, rqs, &flag, MPI_STATUSES_IGNORE); #else int ret = MPI_Testall(n, rqs, &flag, MPI_STATUSES_IGNORE); if (ret != MPI_SUCCESS) { // We do not dare to release the buffers now! PyErr_SetString(PyExc_RuntimeError, "MPI_Testall error occured."); return NULL; } #endif // Unlike MPI_Test, if flag outcome is non-zero, MPI_Testall will deallocate // all requests which were allocated by nonblocking communication calls, so // we must free these buffers. Otherwise, none of the requests are modified. if (flag != 0) { // Release the buffers used by the MPI communication for (int i = 0; i < n; i++) { GPAW_MPI_Request *o = (GPAW_MPI_Request *) PySequence_GetItem(requests, i); if (o->status) { assert(o->buffer != NULL); Py_DECREF(o->buffer); } o->status = 0; Py_DECREF(o); } } // Release internal data and return. free(rqs); return Py_BuildValue("i", flag); } static PyObject * mpi_wait(MPIObject *self, PyObject *args) { GPAW_MPI_Request* s; if (!PyArg_ParseTuple(args, "O!:wait", &GPAW_MPI_Request_type, &s)) return NULL; return mpi_request_wait(s, NULL); } static PyObject * mpi_waitall(MPIObject *self, PyObject *requests) { int n; // Number of requests MPI_Request *rqs = NULL; if (!PySequence_Check(requests)) { PyErr_SetString(PyExc_TypeError, "mpi.waitall: argument must be a sequence"); return NULL; } // Extract the request objects n = PySequence_Size(requests); assert(n >= 0); // This cannot fail. rqs = GPAW_MALLOC(MPI_Request, n); for (int i = 0; i < n; i++) { PyObject *o = PySequence_GetItem(requests, i); if (o == NULL) return NULL; if (Py_TYPE(o) != &GPAW_MPI_Request_type) { Py_DECREF(o); free(rqs); PyErr_SetString(PyExc_TypeError, "mpi.waitall: argument must be a sequence of MPI requests"); return NULL; } GPAW_MPI_Request *s = (GPAW_MPI_Request *)o; rqs[i] = s->rq; Py_DECREF(o); } // Do the actual wait. #ifndef GPAW_MPI_DEBUG MPI_Waitall(n, rqs, MPI_STATUSES_IGNORE); #else int ret = MPI_Waitall(n, rqs, MPI_STATUSES_IGNORE); if (ret != MPI_SUCCESS) { // We do not dare to release the buffers now! PyErr_SetString(PyExc_RuntimeError, "MPI_Waitall error occured."); return NULL; } #endif // Release the buffers used by the MPI communication for (int i = 0; i < n; i++) { GPAW_MPI_Request *o = (GPAW_MPI_Request *) PySequence_GetItem(requests, i); if (o->status) { assert(o->buffer != NULL); Py_DECREF(o->buffer); } o->status = 0; Py_DECREF(o); } // Release internal data and return. free(rqs); Py_RETURN_NONE; } static MPI_Datatype get_mpi_datatype(PyArrayObject *a) { int n = PyArray_DESCR(a)->elsize; if (PyArray_ISCOMPLEX(a)) n = n / 2; switch(PyArray_TYPE(a)) { // Floating point numbers including complex numbers case NPY_DOUBLE: case NPY_CDOUBLE: assert(sizeof(double) == n); return MPI_DOUBLE; case NPY_FLOAT: case NPY_CFLOAT: assert(sizeof(float) == n); return MPI_FLOAT; case NPY_LONGDOUBLE: case NPY_CLONGDOUBLE: assert(sizeof(long double) == n); return MPI_LONG_DOUBLE; // Signed integer types case NPY_BYTE: assert(sizeof(char) == n); return MPI_CHAR; case NPY_SHORT: assert(sizeof(short) == n); return MPI_SHORT; case NPY_INT: assert(sizeof(int) == n); return MPI_INT; case NPY_LONG: assert(sizeof(long) == n); return MPI_LONG; // Unsigned integer types case NPY_BOOL: case NPY_UBYTE: assert(sizeof(unsigned char) == n); return MPI_UNSIGNED_CHAR; case NPY_USHORT: assert(sizeof(unsigned short) == n); return MPI_UNSIGNED_SHORT; case NPY_UINT: assert(sizeof(unsigned) == n); return MPI_UNSIGNED; case NPY_ULONG: assert(sizeof(unsigned long) == n); return MPI_UNSIGNED_LONG; } // If we reach this point none of the cases worked out. PyErr_SetString(PyExc_ValueError, "Cannot communicate data of this type."); return 0; } #if PY_MAJOR_VERSION >= 3 #define PyInt_FromLong PyLong_FromLong #define PyInt_Check PyLong_Check #define PyInt_AS_LONG PyLong_AS_LONG #endif static PyObject * mpi_reduce(MPIObject *self, PyObject *args, PyObject *kwargs, MPI_Op operation, int allowcomplex) { #ifdef GPAW_MPI_DEBUG MPI_Barrier(self->comm); #endif PyObject* obj; int root = -1; static char *kwlist[] = {"a", "root", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:reduce", kwlist, &obj, &root)) return NULL; CHK_PROC_DEF(root); if (PyFloat_Check(obj)) { double din = PyFloat_AS_DOUBLE(obj); double dout; if (root == -1) MPI_Allreduce(&din, &dout, 1, MPI_DOUBLE, operation, self->comm); else MPI_Reduce(&din, &dout, 1, MPI_DOUBLE, operation, root, self->comm); return PyFloat_FromDouble(dout); } if (PyInt_Check(obj)) { long din = PyInt_AS_LONG(obj); long dout; if (root == -1) MPI_Allreduce(&din, &dout, 1, MPI_LONG, operation, self->comm); else MPI_Reduce(&din, &dout, 1, MPI_LONG, operation, root, self->comm); return PyInt_FromLong(dout); } else if (PyComplex_Check(obj) && allowcomplex) { double din[2]; double dout[2]; din[0] = PyComplex_RealAsDouble(obj); din[1] = PyComplex_ImagAsDouble(obj); if (root == -1) MPI_Allreduce(&din, &dout, 2, MPI_DOUBLE, MPI_SUM, self->comm); else MPI_Reduce(&din, &dout, 2, MPI_DOUBLE, MPI_SUM, root, self->comm); return PyComplex_FromDoubles(dout[0], dout[1]); } else if (PyComplex_Check(obj)) { PyErr_SetString(PyExc_ValueError, "Operation not allowed on complex numbers"); return NULL; } else // It should be an array { int n; int elemsize; MPI_Datatype datatype; PyArrayObject* aobj = (PyArrayObject*)obj; CHK_ARRAY(aobj); datatype = get_mpi_datatype(aobj); if (datatype == 0) return NULL; n = PyArray_SIZE(aobj); elemsize = PyArray_DESCR(aobj)->elsize; if (PyArray_ISCOMPLEX(aobj)) { if (allowcomplex) { n *= 2; elemsize /= 2; } else { PyErr_SetString(PyExc_ValueError, "Operation not allowed on complex numbers"); return NULL; } } if (root == -1) { #ifdef GPAW_MPI2 MPI_Allreduce(MPI_IN_PLACE, PyArray_BYTES(aobj), n, datatype, operation, self->comm); #else char* b = GPAW_MALLOC(char, n * elemsize); MPI_Allreduce(PyArray_BYTES(aobj), b, n, datatype, operation, self->comm); assert(PyArray_NBYTES(aobj) == n * elemsize); memcpy(PyArray_BYTES(aobj), b, n * elemsize); free(b); #endif } else { int rank; MPI_Comm_rank(self->comm, &rank); char* b = 0; if (rank == root) { #ifdef GPAW_MPI2 MPI_Reduce(MPI_IN_PLACE, PyArray_BYTES(aobj), n, datatype, operation, root, self->comm); #else b = GPAW_MALLOC(char, n * elemsize); MPI_Reduce(PyArray_BYTES(aobj), b, n, datatype, operation, root, self->comm); assert(PyArray_NBYTES(aobj) == n * elemsize); memcpy(PyArray_BYTES(aobj), b, n * elemsize); free(b); #endif } else { MPI_Reduce(PyArray_BYTES(aobj), b, n, datatype, operation, root, self->comm); } } Py_RETURN_NONE; } } static PyObject * mpi_sum(MPIObject *self, PyObject *args, PyObject *kwargs) { return mpi_reduce(self, args, kwargs, MPI_SUM, 1); } static PyObject * mpi_product(MPIObject *self, PyObject *args, PyObject *kwargs) { // No complex numbers as that would give separate products of // real and imaginary parts. return mpi_reduce(self, args, kwargs, MPI_PROD, 0); } static PyObject * mpi_max(MPIObject *self, PyObject *args, PyObject *kwargs) { return mpi_reduce(self, args, kwargs, MPI_MAX, 0); } static PyObject * mpi_min(MPIObject *self, PyObject *args, PyObject *kwargs) { return mpi_reduce(self, args, kwargs, MPI_MIN, 0); } static PyObject * mpi_scatter(MPIObject *self, PyObject *args) { PyArrayObject* sendobj; PyArrayObject* recvobj; int root; if (!PyArg_ParseTuple(args, "OOi:scatter", &sendobj, &recvobj, &root)) return NULL; CHK_ARRAY(recvobj); CHK_PROC(root); char* source = 0; if (self->rank == root) { CHK_ARRAY(sendobj); CHK_ARRAYS(recvobj, sendobj, self->size); // size(send) = size(recv)*Ncpu source = PyArray_BYTES(sendobj); } int n = PyArray_DESCR(recvobj)->elsize; for (int d = 0; d < PyArray_NDIM(recvobj); d++) n *= PyArray_DIM(recvobj,d); MPI_Scatter(source, n, MPI_BYTE, PyArray_BYTES(recvobj), n, MPI_BYTE, root, self->comm); Py_RETURN_NONE; } static PyObject * mpi_allgather(MPIObject *self, PyObject *args) { PyArrayObject* a; PyArrayObject* b; if (!PyArg_ParseTuple(args, "OO:allgather", &a, &b)) return NULL; CHK_ARRAY(a); CHK_ARRAY(b); CHK_ARRAYS(a, b, self->size); int n = PyArray_DESCR(a)->elsize; for (int d = 0; d < PyArray_NDIM(a); d++) n *= PyArray_DIM(a,d); // What about endianness???? MPI_Allgather(PyArray_BYTES(a), n, MPI_BYTE, PyArray_BYTES(b), n, MPI_BYTE, self->comm); Py_RETURN_NONE; } static PyObject * mpi_gather(MPIObject *self, PyObject *args) { PyArrayObject* a; int root; PyArrayObject* b = 0; if (!PyArg_ParseTuple(args, "Oi|O", &a, &root, &b)) return NULL; CHK_ARRAY(a); CHK_PROC(root); if (root == self->rank) { CHK_ARRAY(b); CHK_ARRAYS(a, b, self->size); } else if ((PyObject*)b != Py_None && b != NULL) { fprintf(stderr, "******** Root=%d\n", root); PyErr_SetString(PyExc_ValueError, "mpi_gather: b array should not be given on non-root processors."); return NULL; } int n = PyArray_DESCR(a)->elsize; for (int d = 0; d < PyArray_NDIM(a); d++) n *= PyArray_DIM(a,d); if (root != self->rank) MPI_Gather(PyArray_BYTES(a), n, MPI_BYTE, 0, n, MPI_BYTE, root, self->comm); else MPI_Gather(PyArray_BYTES(a), n, MPI_BYTE, PyArray_BYTES(b), n, MPI_BYTE, root, self->comm); Py_RETURN_NONE; } static PyObject * mpi_broadcast(MPIObject *self, PyObject *args) { #ifdef GPAW_MPI_DEBUG MPI_Barrier(self->comm); #endif PyArrayObject* buf; int root; if (!PyArg_ParseTuple(args, "Oi:broadcast", &buf, &root)) return NULL; CHK_ARRAY(buf); CHK_PROC(root); int n = PyArray_DESCR(buf)->elsize; for (int d = 0; d < PyArray_NDIM(buf); d++) n *= PyArray_DIM(buf,d); MPI_Bcast(PyArray_BYTES(buf), n, MPI_BYTE, root, self->comm); Py_RETURN_NONE; } static PyObject * mpi_alltoallv(MPIObject *self, PyObject *args) { PyArrayObject* send_obj; PyArrayObject* send_cnts; PyArrayObject* send_displs; PyArrayObject* recv_obj; PyArrayObject* recv_cnts; PyArrayObject* recv_displs; if (!PyArg_ParseTuple(args, "OOOOOO:alltoallv", &send_obj, &send_cnts, &send_displs, &recv_obj, &recv_cnts, &recv_displs)) return NULL; CHK_ARRAY(send_obj); CHK_ARRAY(send_cnts); CHK_ARRAY(send_displs); CHK_ARRAY(recv_obj); CHK_ARRAY(recv_cnts); CHK_ARRAY(recv_displs); int *s_cnts = GPAW_MALLOC(int, self->size); int *s_displs = GPAW_MALLOC(int, self->size); int *r_cnts = GPAW_MALLOC(int, self->size); int *r_displs = GPAW_MALLOC(int, self->size); /* Create count and displacement arrays in units of bytes */ int elem_size = PyArray_DESCR(send_obj)->elsize; long* tmp1 = PyArray_DATA(send_cnts); long* tmp2 = PyArray_DATA(send_displs); long* tmp3 = PyArray_DATA(recv_cnts); long* tmp4 = PyArray_DATA(recv_displs); for (int i=0; i < self->size; i++) { s_cnts[i] = tmp1[i] * elem_size; s_displs[i] = tmp2[i] * elem_size; r_cnts[i] = tmp3[i] * elem_size; r_displs[i] = tmp4[i] * elem_size; } MPI_Alltoallv(PyArray_BYTES(send_obj), s_cnts, s_displs, MPI_BYTE, PyArray_BYTES(recv_obj), r_cnts, r_displs, MPI_BYTE, self->comm); Py_RETURN_NONE; } static PyObject * get_members(MPIObject *self, PyObject *args) { PyArrayObject *ranks; npy_intp ranks_dims[1] = {self->size}; ranks = (PyArrayObject *) PyArray_SimpleNew(1, ranks_dims, NPY_INT); if (ranks == NULL) return NULL; memcpy(INTP(ranks), self->members, self->size*sizeof(int)); PyObject* values = Py_BuildValue("O", ranks); Py_DECREF(ranks); return values; } // See the documentation for corresponding function in debug wrapper // for the purpose of this function (gpaw/mpi/__init__.py) static PyObject * get_c_object(MPIObject *self, PyObject *args) { return Py_BuildValue("O", self); } // Forward declaration of MPI_Communicator because it needs MPIType // that needs MPI_getattr that needs MPI_Methods that need // MPI_Communicator that need ... static PyObject * MPICommunicator(MPIObject *self, PyObject *args); static PyMethodDef mpi_methods[] = { {"sendreceive", (PyCFunction)mpi_sendreceive, METH_VARARGS|METH_KEYWORDS, "sendreceive(a, dest, b, src, desttag=123, srctag=123) sends an array a to dest and receives an array b from src."}, {"receive", (PyCFunction)mpi_receive, METH_VARARGS|METH_KEYWORDS, "receive(a, src, tag=123, block=1) receives array a from src."}, {"send", (PyCFunction)mpi_send, METH_VARARGS|METH_KEYWORDS, "send(a, dest, tag=123, block=1) sends array a to dest."}, {"ssend", (PyCFunction)mpi_ssend, METH_VARARGS|METH_KEYWORDS, "ssend(a, dest, tag=123) synchronously sends array a to dest."}, {"abort", (PyCFunction)mpi_abort, METH_VARARGS, "abort(errcode) aborts all MPI tasks."}, {"name", (PyCFunction)mpi_name, METH_NOARGS, "name() returns the name of the processor node."}, {"barrier", (PyCFunction)mpi_barrier, METH_VARARGS, "barrier() synchronizes all MPI tasks"}, {"test", (PyCFunction)mpi_test, METH_VARARGS, "test(request) tests if a nonblocking communication is complete."}, {"testall", (PyCFunction)mpi_testall, METH_O, "testall(list_of_rqs) tests if multiple nonblocking communications are complete."}, {"wait", (PyCFunction)mpi_wait, METH_VARARGS, "wait(request) waits for a nonblocking communication to complete."}, {"waitall", (PyCFunction)mpi_waitall, METH_O, "waitall(list_of_rqs) waits for multiple nonblocking communications to complete."}, {"sum", (PyCFunction)mpi_sum, METH_VARARGS|METH_KEYWORDS, "sum(a, root=-1) sums arrays, result on all tasks unless root is given."}, {"product", (PyCFunction)mpi_product, METH_VARARGS|METH_KEYWORDS, "product(a, root=-1) multiplies arrays, result on all tasks unless root is given."}, {"max", (PyCFunction)mpi_max, METH_VARARGS|METH_KEYWORDS, "max(a, root=-1) maximum of arrays, result on all tasks unless root is given."}, {"min", (PyCFunction)mpi_min, METH_VARARGS|METH_KEYWORDS, "min(a, root=-1) minimum of arrays, result on all tasks unless root is given."}, {"scatter", (PyCFunction)mpi_scatter, METH_VARARGS, "scatter(src, target, root) distributes array from root task."}, {"gather", (PyCFunction)mpi_gather, METH_VARARGS, "gather(src, root, target=None) gathers data from all tasks on root task."}, {"all_gather", (PyCFunction)mpi_allgather, METH_VARARGS, "all_gather(src, target) gathers data from all tasks on all tasks."}, {"alltoallv", (PyCFunction)mpi_alltoallv, METH_VARARGS, "alltoallv(sbuf, scnt, sdispl, rbuf, ...) send data from all tasks to all tasks."}, {"broadcast", (PyCFunction)mpi_broadcast, METH_VARARGS, "broadcast(buffer, root) Broadcast data in-place from root task."}, {"get_members", (PyCFunction)get_members, METH_VARARGS, 0}, {"get_c_object", (PyCFunction)get_c_object, METH_VARARGS, 0}, {"new_communicator", (PyCFunction)MPICommunicator, METH_VARARGS, "new_communicator(ranks) creates a new communicator."}, {0, 0, 0, 0} }; static PyMemberDef mpi_members[] = { {"size", T_INT, offsetof(MPIObject, size), 0, "Number of processors"}, {"rank", T_INT, offsetof(MPIObject, rank), 0, "Number of this processor"}, {"parent", T_OBJECT_EX, offsetof(MPIObject, parent), 0, "Parent communicator"}, {0, 0, 0, 0, 0} /* Sentinel */ }; // __new__ static PyObject *NewMPIObject(PyTypeObject* type, PyObject *args, PyObject *kwds) { static char *kwlist[] = {NULL}; MPIObject* self; if (! PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) return NULL; self = (MPIObject *) type->tp_alloc(type, 0); if (self == NULL) return NULL; # ifndef GPAW_INTERPRETER MPI_Init(NULL, NULL); # endif MPI_Comm_size(MPI_COMM_WORLD, &(self->size)); MPI_Comm_rank(MPI_COMM_WORLD, &(self->rank)); self->comm = MPI_COMM_WORLD; Py_INCREF(Py_None); self->parent = Py_None; self->members = (int*) malloc(self->size*sizeof(int)); if (self->members == NULL) return NULL; for (int i=0; isize; i++) self->members[i] = i; return (PyObject *) self; } // __init__ does nothing. static int InitMPIObject(MPIObject* self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {NULL}; if (! PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) return -1; return 0; } PyTypeObject MPIType = { PyVarObject_HEAD_INIT(NULL, 0) "MPI", /*tp_name*/ sizeof(MPIObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)mpi_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ "MPI object", /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ mpi_methods, /*tp_methods*/ mpi_members, /*tp_members*/ 0, /*tp_getset*/ 0, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ 0, /*tp_dictoffset*/ (initproc)InitMPIObject, /*tp_init*/ 0, /*tp_alloc*/ NewMPIObject, /*tp_new*/ }; static PyObject * MPICommunicator(MPIObject *self, PyObject *args) { PyObject* orig_ranks; if (!PyArg_ParseTuple(args, "O", &orig_ranks)) return NULL; // NB: int32 is NPY_LONG on 32-bit Linux and NPY_INT on 64-bit Linux! // First convert to NumPy array of NPY_LONG, then cast to NPY_INT, to // allow both 32 and 64 bit integers in the argument (except 64 on 32). PyArrayObject *ranks = (PyArrayObject*)PyArray_ContiguousFromAny( orig_ranks, NPY_LONG, 1, 1); if (ranks == NULL) return NULL; PyArrayObject *iranks; int n = PyArray_DIM(ranks, 0); iranks = (PyArrayObject*)PyArray_Cast((PyArrayObject*) ranks, NPY_INT); Py_DECREF(ranks); if (iranks == NULL) return NULL; // Check that all ranks make sense for (int i = 0; i < n; i++) { int *x = PyArray_GETPTR1(iranks, i); if (*x < 0 || *x >= self->size) { Py_DECREF(iranks); PyErr_SetString(PyExc_ValueError, "invalid rank"); return NULL; } for (int j = 0; j < i; j++) { int *y = PyArray_GETPTR1(iranks, j); if (*y == *x) { Py_DECREF(iranks); PyErr_SetString(PyExc_ValueError, "duplicate rank"); return NULL; } } } MPI_Group group; MPI_Comm_group(self->comm, &group); MPI_Group newgroup; MPI_Group_incl(group, n, (int *) PyArray_BYTES(iranks), &newgroup); MPI_Comm comm; MPI_Comm_create(self->comm, newgroup, &comm); // has a memory leak! #ifdef GPAW_MPI_DEBUG if (comm != MPI_COMM_NULL) { // Default Errhandler is MPI_ERRORS_ARE_FATAL MPI_Errhandler_set(comm, MPI_ERRORS_RETURN); #ifdef __bgp__ int result; int rank; MPI_Comm_rank(comm, &rank); MPIX_Get_property(comm, MPIDO_RECT_COMM, &result); if (rank == 0) { if(result) fprintf(stderr, "Get_property: comm is rectangular. \n"); } #endif } #endif // GPAW_MPI_DEBUG MPI_Group_free(&newgroup); MPI_Group_free(&group); if (comm == MPI_COMM_NULL) { Py_DECREF(iranks); Py_RETURN_NONE; } else { MPIObject *obj = PyObject_NEW(MPIObject, &MPIType); if (obj == NULL) return NULL; MPI_Comm_size(comm, &(obj->size)); MPI_Comm_rank(comm, &(obj->rank)); obj->comm = comm; if (obj->parent == Py_None) Py_DECREF(obj->parent); obj->members = (int*) malloc(obj->size*sizeof(int)); if (obj->members == NULL) return NULL; memcpy(obj->members, (int *) PyArray_BYTES(iranks), obj->size*sizeof(int)); Py_DECREF(iranks); // Make sure that MPI_COMM_WORLD is kept alive till the end (we // don't want MPI_Finalize to be called before MPI_Comm_free): Py_INCREF(self); obj->parent = (PyObject*)self; return (PyObject*)obj; } } #endif // PARALLEL gpaw-0.11.0.13004/c/bc.h0000664000175000017500000000265312553643466014446 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2005 CSC - IT Center for Science Ltd. * Please see the accompanying LICENSE file for further information. */ #include "bmgs/bmgs.h" #ifdef PARALLEL #include #else typedef int* MPI_Request; // !!!!!!!??????????? typedef int* MPI_Comm; #define MPI_COMM_NULL 0 #define MPI_Comm_rank(comm, rank) *(rank) = 0 #endif typedef struct { int size1[3]; int size2[3]; int sendstart[3][2][3]; int sendsize[3][2][3]; int recvstart[3][2][3]; int recvsize[3][2][3]; int sendproc[3][2]; int recvproc[3][2]; int nsend[3][2]; int nrecv[3][2]; int maxsend; int maxrecv; int padding[3]; bool sjoin[3]; bool rjoin[3]; int ndouble; bool cfd; MPI_Comm comm; } boundary_conditions; static const int COPY_DATA = -2; static const int DO_NOTHING = -3; // ?????????? boundary_conditions* bc_init(const long size1[3], const long padding[3][2], const long npadding[3][2], const long neighbors[3][2], MPI_Comm comm, bool real, bool cfd); void bc_unpack1(const boundary_conditions* bc, const double* input, double* output, int i, MPI_Request recvreq[2], MPI_Request sendreq[2], double* rbuf, double* sbuf, const double_complex phases[2], int thd, int nin); void bc_unpack2(const boundary_conditions* bc, double* a2, int i, MPI_Request recvreq[2], MPI_Request sendreq[2], double* rbuf, int nin); gpaw-0.11.0.13004/c/lfc.c0000664000175000017500000015650212553643466014624 0ustar jensjjensj00000000000000/* Copyright (C) 2003-2007 CAMP * Copyright (C) 2007-2009 CAMd * Please see the accompanying LICENSE file for further information. */ #include #define PY_ARRAY_UNIQUE_SYMBOL GPAW_ARRAY_API #define NO_IMPORT_ARRAY #include #include "spline.h" #include "lfc.h" #include "bmgs/spherical_harmonics.h" #include "bmgs/bmgs.h" #ifdef GPAW_NO_UNDERSCORE_BLAS # define zgemm_ zgemm #endif void zgemm_(char *transa, char *transb, int *m, int * n, int *k, void *alpha, void *a, int *lda, const void *b, int *ldb, void *beta, void *c, int *ldc); static void lfc_dealloc(LFCObject *self) { if (self->bloch_boundary_conditions) free(self->phase_i); free(self->volume_i); free(self->work_gm); free(self->ngm_W); free(self->i_W); free(self->volume_W); PyObject_DEL(self); } PyObject* calculate_potential_matrix(LFCObject *self, PyObject *args); PyObject* calculate_potential_matrices(LFCObject *self, PyObject *args); PyObject* lfcintegrate(LFCObject *self, PyObject *args); PyObject* derivative(LFCObject *self, PyObject *args); PyObject* normalized_derivative(LFCObject *self, PyObject *args); PyObject* construct_density(LFCObject *self, PyObject *args); PyObject* construct_density1(LFCObject *self, PyObject *args); PyObject* ae_valence_density_correction(LFCObject *self, PyObject *args); PyObject* ae_core_density_correction(LFCObject *self, PyObject *args); PyObject* lcao_to_grid(LFCObject *self, PyObject *args); PyObject* lcao_to_grid_k(LFCObject *self, PyObject *args); PyObject* add(LFCObject *self, PyObject *args); PyObject* calculate_potential_matrix_derivative(LFCObject *self, PyObject *args); PyObject* calculate_potential_matrix_force_contribution(LFCObject *self, PyObject *args); PyObject* second_derivative(LFCObject *self, PyObject *args); PyObject* add_derivative(LFCObject *self, PyObject *args); static PyMethodDef lfc_methods[] = { {"calculate_potential_matrix", (PyCFunction)calculate_potential_matrix, METH_VARARGS, 0}, {"calculate_potential_matrices", (PyCFunction)calculate_potential_matrices, METH_VARARGS, 0}, {"integrate", (PyCFunction)lfcintegrate, METH_VARARGS, 0}, {"derivative", (PyCFunction)derivative, METH_VARARGS, 0}, {"normalized_derivative", (PyCFunction)normalized_derivative, METH_VARARGS, 0}, {"construct_density", (PyCFunction)construct_density, METH_VARARGS, 0}, {"construct_density1", (PyCFunction)construct_density1, METH_VARARGS, 0}, {"ae_valence_density_correction", (PyCFunction)ae_valence_density_correction, METH_VARARGS, 0}, {"ae_core_density_correction", (PyCFunction)ae_core_density_correction, METH_VARARGS, 0}, {"lcao_to_grid", (PyCFunction)lcao_to_grid, METH_VARARGS, 0}, {"lcao_to_grid_k", (PyCFunction)lcao_to_grid_k, METH_VARARGS, 0}, {"add", (PyCFunction)add, METH_VARARGS, 0}, {"calculate_potential_matrix_derivative", (PyCFunction)calculate_potential_matrix_derivative, METH_VARARGS, 0}, {"calculate_potential_matrix_force_contribution", (PyCFunction)calculate_potential_matrix_force_contribution, METH_VARARGS, 0}, {"second_derivative", (PyCFunction)second_derivative, METH_VARARGS, 0}, {"add_derivative", (PyCFunction)add_derivative, METH_VARARGS, 0}, {NULL, NULL, 0, NULL} }; PyTypeObject LFCType = { PyVarObject_HEAD_INIT(NULL, 0) "LocalizedFunctionsCollection", sizeof(LFCObject), 0, (destructor)lfc_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, "LFC object", 0, 0, 0, 0, 0, 0, lfc_methods }; PyObject * NewLFCObject(PyObject *obj, PyObject *args) { PyObject* A_Wgm_obj; PyArrayObject* M_W_obj; PyArrayObject* G_B_obj; PyArrayObject* W_B_obj; double dv; PyArrayObject* phase_kW_obj; if (!PyArg_ParseTuple(args, "OOOOdO", &A_Wgm_obj, &M_W_obj, &G_B_obj, &W_B_obj, &dv, &phase_kW_obj)) return NULL; LFCObject *self = PyObject_NEW(LFCObject, &LFCType); if (self == NULL) return NULL; self->dv = dv; const int* M_W = (const int*)PyArray_DATA(M_W_obj); self->G_B = (int*)PyArray_DATA(G_B_obj); self->W_B = (int*)PyArray_DATA(W_B_obj); if (PyArray_DIMS(phase_kW_obj)[0] > 0) { self->bloch_boundary_conditions = true; self->phase_kW = (double complex*)PyArray_DATA(phase_kW_obj); } else { self->bloch_boundary_conditions = false; } int nB = PyArray_DIMS(G_B_obj)[0]; int nW = PyList_Size(A_Wgm_obj); self->nW = nW; self->nB = nB; int nimax = 0; int ngmax = 0; int ni = 0; int Ga = 0; for (int B = 0; B < nB; B++) { int Gb = self->G_B[B]; int nG = Gb - Ga; if (ni > 0 && nG > ngmax) ngmax = nG; if (self->W_B[B] >= 0) ni += 1; else { if (ni > nimax) nimax = ni; ni--; } Ga = Gb; } assert(ni == 0); self->volume_W = GPAW_MALLOC(LFVolume, nW); self->i_W = GPAW_MALLOC(int, nW); self->ngm_W = GPAW_MALLOC(int, nW); int nmmax = 0; for (int W = 0; W < nW; W++) { PyArrayObject* A_gm_obj = (PyArrayObject*)PyList_GetItem(A_Wgm_obj, W); LFVolume* volume = &self->volume_W[W]; volume->A_gm = (const double*)PyArray_DATA(A_gm_obj); self->ngm_W[W] = PyArray_DIMS(A_gm_obj)[0] * PyArray_DIMS(A_gm_obj)[1]; volume->nm = PyArray_DIMS(A_gm_obj)[1]; volume->M = M_W[W]; volume->W = W; if (volume->nm > nmmax) nmmax = volume->nm; } self->work_gm = GPAW_MALLOC(double, ngmax * nmmax); self->volume_i = GPAW_MALLOC(LFVolume, nimax); if (self->bloch_boundary_conditions) self->phase_i = GPAW_MALLOC(complex double, nimax); return (PyObject*)self; } PyObject* calculate_potential_matrix(LFCObject *lfc, PyObject *args) { PyArrayObject* vt_G_obj; PyArrayObject* Vt_MM_obj; int k; int Mstart; int Mstop; if (!PyArg_ParseTuple(args, "OOiii", &vt_G_obj, &Vt_MM_obj, &k, &Mstart, &Mstop)) return NULL; const double* vt_G = (const double*)PyArray_DATA(vt_G_obj); int nM = PyArray_DIMS(Vt_MM_obj)[1]; double dv = lfc->dv; double* work_gm = lfc->work_gm; if (!lfc->bloch_boundary_conditions) { double* Vt_MM = (double*)PyArray_DATA(Vt_MM_obj); GRID_LOOP_START(lfc, -1) { // ORDINARY/GAMMA-POINT for (int i1 = 0; i1 < ni; i1++) { LFVolume* v1 = volume_i + i1; int M1 = v1->M; int nm1 = v1->nm; int M1p = MAX(M1, Mstart); int nm1p = MIN(M1 + nm1, Mstop) - M1p; if (nm1p <= 0) continue; int gm = M1p - M1; int gm1 = 0; const double* A1_gm = v1->A_gm; for (int G = Ga; G < Gb; G++, gm += nm1 - nm1p) { double vtdv = vt_G[G] * dv; for (int m1 = 0; m1 < nm1p; m1++, gm1++, gm++) work_gm[gm1] = vtdv * A1_gm[gm]; } for (int i2 = 0; i2 < ni; i2++) { LFVolume* v2 = volume_i + i2; int M2 = v2->M; if (M1 >= M2) { int nm2 = v2->nm; const double* A2_gm = v2->A_gm; double* Vt_mm = Vt_MM + (M1p - Mstart) * nM + M2; for (int g = 0; g < nG; g++){ int gnm1 = g * nm1p; int gnm2 = g * nm2; for (int m1 = 0; m1 < nm1p; m1++) { int m1nM = m1 * nM; for (int m2 = 0; m2 < nm2; m2++) Vt_mm[m2 + m1nM] += A2_gm[gnm2 + m2] * work_gm[gnm1 + m1]; } } } } } } GRID_LOOP_STOP(lfc, -1); } else { complex double* Vt_MM = (complex double*)PyArray_DATA(Vt_MM_obj); GRID_LOOP_START(lfc, k) { // KPOINT CALC POT MATRIX for (int i1 = 0; i1 < ni; i1++) { LFVolume* v1 = volume_i + i1; double complex conjphase1 = conj(phase_i[i1]); int M1 = v1->M; int nm1 = v1->nm; int M1p = MAX(M1, Mstart); int nm1p = MIN(M1 + nm1, Mstop) - M1p; if (nm1p <= 0) continue; int gm = M1p - M1; int gm1 = 0; const double* A1_gm = v1->A_gm; for (int G = Ga; G < Gb; G++, gm += nm1 - nm1p) { double vtdv = vt_G[G] * dv; for (int m1 = 0; m1 < nm1p; m1++, gm1++, gm++) work_gm[gm1] = vtdv * A1_gm[gm]; } for (int i2 = 0; i2 < ni; i2++) { LFVolume* v2 = volume_i + i2; const double* A2_gm = v2->A_gm; int M2 = v2->M; if (M1 >= M2) { int nm2 = v2->nm; double complex phase = conjphase1 * phase_i[i2]; double complex* Vt_mm = Vt_MM + (M1p - Mstart) * nM + M2; for (int g = 0; g < nG; g++) { int gnm1 = g * nm1p; int gnm2 = g * nm2; int m1nM = 0; for (int m1 = 0; m1 < nm1p; m1++, m1nM += nM) { complex double wphase = work_gm[gnm1 + m1] * phase; for (int m2 = 0; m2 < nm2; m2++) { Vt_mm[m1nM + m2] += A2_gm[gnm2 + m2] * wphase; } } } } } } } GRID_LOOP_STOP(lfc, k); } Py_RETURN_NONE; } PyObject* calculate_potential_matrices(LFCObject *lfc, PyObject *args) { PyArrayObject* vt_G_obj; PyArrayObject* Vt_xMM_obj; PyArrayObject* x_W_obj; int Mstart; int Mstop; if (!PyArg_ParseTuple(args, "OOOii", &vt_G_obj, &Vt_xMM_obj, &x_W_obj, &Mstart, &Mstop)) return NULL; const double* vt_G = (const double*)PyArray_DATA(vt_G_obj); int nM = PyArray_DIMS(Vt_xMM_obj)[2]; double dv = lfc->dv; double* work_gm = lfc->work_gm; double* Vt_xMM = (double*)PyArray_DATA(Vt_xMM_obj); int* x_W = (int*)PyArray_DATA(x_W_obj); GRID_LOOP_START(lfc, -1) { for (int i1 = 0; i1 < ni; i1++) { LFVolume* v1 = volume_i + i1; int M1 = v1->M; int nm1 = v1->nm; int M1p = MAX(M1, Mstart); int nm1p = MIN(M1 + nm1, Mstop) - M1p; if (nm1p <= 0) continue; int x1 = x_W[v1->W]; int gm = M1p - M1; int gm1 = 0; const double* A1_gm = v1->A_gm; for (int G = Ga; G < Gb; G++, gm += nm1 - nm1p) { double vtdv = vt_G[G] * dv; for (int m1 = 0; m1 < nm1p; m1++, gm1++, gm++) work_gm[gm1] = vtdv * A1_gm[gm]; } for (int i2 = 0; i2 < ni; i2++) { LFVolume* v2 = volume_i + i2; int x = x_W[v2->W] - x1; if (x >= 0) { int M2 = v2->M; int nm2 = v2->nm; const double* A2_gm = v2->A_gm; double* Vt_mm = (Vt_xMM + (M1p - Mstart) * nM + M2 + x * (Mstop - Mstart) * nM); for (int g = 0; g < nG; g++) { int gnm1 = g * nm1p; int gnm2 = g * nm2; for (int m1 = 0; m1 < nm1p; m1++) { int m1nM = m1 * nM; for (int m2 = 0; m2 < nm2; m2++) Vt_mm[m2 + m1nM] += (A2_gm[gnm2 + m2] * work_gm[gnm1 + m1]); } } } } } } GRID_LOOP_STOP(lfc, -1); Py_RETURN_NONE; } PyObject* lfcintegrate(LFCObject *lfc, PyObject *args) { PyArrayObject* a_xG_obj; PyArrayObject* c_xM_obj; int q; if (!PyArg_ParseTuple(args, "OOi", &a_xG_obj, &c_xM_obj, &q)) return NULL; int nd = PyArray_NDIM(a_xG_obj); npy_intp* dims = PyArray_DIMS(a_xG_obj); int nx = PyArray_MultiplyList(dims, nd - 3); int nG = PyArray_MultiplyList(dims + nd - 3, 3); int nM = PyArray_DIMS(c_xM_obj)[PyArray_NDIM(c_xM_obj) - 1]; double dv = lfc->dv; if (!lfc->bloch_boundary_conditions) { const double* a_G = (const double*)PyArray_DATA(a_xG_obj); double* c_M = (double*)PyArray_DATA(c_xM_obj); for (int x = 0; x < nx; x++) { GRID_LOOP_START(lfc, -1) { for (int i = 0; i < ni; i++) { LFVolume* v = volume_i + i; const double* A_gm = v->A_gm; int nm = v->nm; double* c_M1 = c_M + v->M; for (int gm = 0, G = Ga; G < Gb; G++){ double av = a_G[G] * dv; for (int m = 0; m < nm; m++, gm++){ c_M1[m] += av * A_gm[gm]; } } } } GRID_LOOP_STOP(lfc, -1); c_M += nM; a_G += nG; } } else { const complex double* a_G = (const complex double*)PyArray_DATA(a_xG_obj); complex double* c_M = (complex double*)PyArray_DATA(c_xM_obj); for (int x = 0; x < nx; x++) { GRID_LOOP_START(lfc, q) { for (int i = 0; i < ni; i++) { LFVolume* v = volume_i + i; int nm = v->nm; complex double* c_M1 = c_M + v->M; const double* A_gm = v->A_gm; double complex vphase = phase_i[i] * dv; for (int gm = 0, G = Ga; G < Gb; G++){ double complex avphase = a_G[G] * vphase; for (int m = 0; m < nm; m++, gm++){ c_M1[m] += avphase * A_gm[gm]; } } } } GRID_LOOP_STOP(lfc, q); c_M += nM; a_G += nG; } } Py_RETURN_NONE; } PyObject* construct_density(LFCObject *lfc, PyObject *args) { PyArrayObject* rho_MM_obj; PyArrayObject* nt_G_obj; int k; int Mstart, Mstop; if (!PyArg_ParseTuple(args, "OOiii", &rho_MM_obj, &nt_G_obj, &k, &Mstart, &Mstop)) return NULL; double* nt_G = (double*)PyArray_DATA(nt_G_obj); int nM = PyArray_DIMS(rho_MM_obj)[1]; double* work_gm = lfc->work_gm; if (!lfc->bloch_boundary_conditions) { const double* rho_MM = (const double*)PyArray_DATA(rho_MM_obj); GRID_LOOP_START(lfc, -1) { for (int i1 = 0; i1 < ni; i1++) { LFVolume* v1 = volume_i + i1; int M1 = v1->M; int nm1 = v1->nm; int M1p = MAX(M1, Mstart); int nm1p = MIN(M1 + nm1, Mstop) - M1p; if (nm1p <= 0) continue; memset(work_gm, 0, nG * nm1 * sizeof(double)); double factor = 1.0; int m1end = MIN(nm1, Mstop - M1); int m1start = MAX(0, Mstart - M1); for (int i2 = i1; i2 < ni; i2++) { LFVolume* v2 = volume_i + i2; int M2 = v2->M; int nm2 = v2->nm; const double* rho_mm = rho_MM + (M1p - Mstart) * nM + M2; //assert(M1 - Mstart + m1start >= 0); for (int g = 0; g < nG; g++) { for (int m1 = m1start, m1p = 0; m1 < m1end; m1++, m1p++) { for (int m2 = 0; m2 < nm2; m2++) { work_gm[g * nm1 + m1] += (v2->A_gm[g * nm2 + m2] * rho_mm[m1p * nM + m2] * factor); } } } factor = 2.0; } int gm1 = 0; for (int G = Ga; G < Gb; G++) { double nt = 0.0; for (int m1 = 0; m1 < nm1; m1++, gm1++) { nt += v1->A_gm[gm1] * work_gm[gm1]; } nt_G[G] += nt; } } } GRID_LOOP_STOP(lfc, -1); } else { const double complex* rho_MM = (const double complex*)PyArray_DATA(rho_MM_obj); GRID_LOOP_START(lfc, k) { for (int i1 = 0; i1 < ni; i1++) { LFVolume* v1 = volume_i + i1; int M1 = v1->M; int nm1 = v1->nm; int M1p = MAX(M1, Mstart); int nm1p = MIN(M1 + nm1, Mstop) - M1p; if (nm1p <= 0) continue; memset(work_gm, 0, nG * nm1 * sizeof(double)); double complex factor = 1.0; int m1end = MIN(nm1, Mstop - M1); int m1start = MAX(0, Mstart - M1); for (int i2 = i1; i2 < ni; i2++) { if (i2 > i1) factor = 2.0 * phase_i[i1] * conj(phase_i[i2]); double rfactor = creal(factor); double ifactor = cimag(factor); LFVolume* v2 = volume_i + i2; const double* A2_gm = v2->A_gm; int M2 = v2->M; int nm2 = v2->nm; const double complex* rho_mm = rho_MM + (M1p - Mstart) * nM + M2; double rrho, irho, rwork, iwork; complex double rho; for (int g = 0; g < nG; g++) { int gnm1 = g * nm1; int gnm2 = g * nm2; int m1pnM = 0; for (int m1 = m1start, m1p=0; m1 < m1end; m1++, m1p++) { m1pnM = m1p * nM; iwork = 0; rwork = 0; for (int m2 = 0; m2 < nm2; m2++) { rho = rho_mm[m1pnM + m2]; rrho = creal(rho); irho = cimag(rho); rwork += A2_gm[gnm2 + m2] * rrho; iwork += A2_gm[gnm2 + m2] * irho; // We could save one of those multiplications if the buffer // were twice as large //work += A2_gm[gnm2 + m2] * (rfactor * rrho - ifactor * irho); } //work_gm[m1 + gnm1] += work; work_gm[m1 + gnm1] += rwork * rfactor - iwork * ifactor; } } } int gm1 = 0; const double* A1_gm = v1->A_gm; for (int G = Ga; G < Gb; G++) { double nt = 0.0; for (int m1 = 0; m1 < nm1; m1++, gm1++) { nt += A1_gm[gm1] * work_gm[gm1]; } nt_G[G] += nt; } } } GRID_LOOP_STOP(lfc, k); } Py_RETURN_NONE; } PyObject* construct_density1(LFCObject *lfc, PyObject *args) { PyArrayObject* f_M_obj; PyArrayObject* nt_G_obj; if (!PyArg_ParseTuple(args, "OO", &f_M_obj, &nt_G_obj)) return NULL; const double* f_M = (const double*)PyArray_DATA(f_M_obj); double* nt_G = (double*)PyArray_DATA(nt_G_obj); GRID_LOOP_START(lfc, -1) { for (int i = 0; i < ni; i++) { LFVolume* v = volume_i + i; for (int gm = 0, G = Ga; G < Gb; G++) { for (int m = 0; m < v->nm; m++, gm++) { nt_G[G] += v->A_gm[gm] * v->A_gm[gm] * f_M[v->M + m]; } } } } GRID_LOOP_STOP(lfc, -1); Py_RETURN_NONE; } PyObject* lcao_to_grid(LFCObject *lfc, PyObject *args) { PyArrayObject* c_M_obj; PyArrayObject* psit_G_obj; int k; if (!PyArg_ParseTuple(args, "OOi", &c_M_obj, &psit_G_obj, &k)) return NULL; if (!lfc->bloch_boundary_conditions) { if (PyArray_DESCR(c_M_obj)->type_num == NPY_DOUBLE) { const double* c_M = (const double*)PyArray_DATA(c_M_obj); double* psit_G = (double*)PyArray_DATA(psit_G_obj); GRID_LOOP_START(lfc, -1) { for (int i = 0; i < ni; i++) { LFVolume* v = volume_i + i; for (int gm = 0, G = Ga; G < Gb; G++) { for (int m = 0; m < v->nm; m++, gm++) { psit_G[G] += v->A_gm[gm] * c_M[v->M + m]; } } } } GRID_LOOP_STOP(lfc, -1); } else { const double complex* c_M = (const double complex*)PyArray_DATA(c_M_obj); double complex* psit_G = (double complex*)PyArray_DATA(psit_G_obj); GRID_LOOP_START(lfc, -1) { for (int i = 0; i < ni; i++) { LFVolume* v = volume_i + i; for (int gm = 0, G = Ga; G < Gb; G++) { for (int m = 0; m < v->nm; m++, gm++) { psit_G[G] += v->A_gm[gm] * c_M[v->M + m]; } } } } GRID_LOOP_STOP(lfc, -1); } } else { const double complex* c_M = (const double complex*)PyArray_DATA(c_M_obj); double complex* psit_G = (double complex*)PyArray_DATA(psit_G_obj); GRID_LOOP_START(lfc, k) { for (int i = 0; i < ni; i++) { LFVolume* v = volume_i + i; double complex conjphase = conj(phase_i[i]); const double* A_gm = v->A_gm; const double complex* c_M1 = c_M + v->M; for (int gm = 0, G = Ga; G < Gb; G++) { double complex psit = 0.0; for (int m = 0; m < v->nm; m++, gm++) { psit += A_gm[gm] * c_M1[m]; } psit_G[G] += psit * conjphase; } } } GRID_LOOP_STOP(lfc, k); } Py_RETURN_NONE; } // Faster implementation of lcao_to_grid() function specialized // for k-points PyObject* lcao_to_grid_k(LFCObject *lfc, PyObject *args) { PyArrayObject* c_xM_obj; PyArrayObject* psit_xG_obj; int k; int Mblock; if (!PyArg_ParseTuple(args, "OOii", &c_xM_obj, &psit_xG_obj, &k, &Mblock)) return NULL; const double complex* c_xM = (const double complex*)PyArray_DATA(c_xM_obj); double complex* psit_xG = (double complex*)PyArray_DATA(psit_xG_obj); int nd = PyArray_NDIM(psit_xG_obj); npy_intp* dims = PyArray_DIMS(psit_xG_obj); int nx = PyArray_MultiplyList(dims, nd - 3); int Gmax = PyArray_MultiplyList(dims + nd - 3, 3); int Mmax = PyArray_DIMS(c_xM_obj)[PyArray_NDIM(c_xM_obj) - 1]; double complex* tmp_GM = 0; for (int Mstart = 0; Mstart < Mmax; Mstart += Mblock) { int Mstop = Mstart + Mblock; if (Mstop > Mmax) { Mstop = Mmax; Mblock = Mstop - Mstart; } if (tmp_GM == 0) tmp_GM = GPAW_MALLOC(double complex, Mblock * Gmax); for (int GM = 0; GM < Gmax * Mblock; GM++) tmp_GM[GM] = 0.0; GRID_LOOP_START(lfc, k) { for (int i = 0; i < ni; i++) { LFVolume* v = volume_i + i; int M1 = v->M; if (M1 >= Mstop) continue; int nm = v->nm; int M2 = M1 + nm; if (M2 <= Mstart) continue; int M1p = MAX(M1, Mstart); int M2p = MIN(M2, Mstop); if (M1p == M2p) continue; double complex phase = phase_i[i]; const double* A_gm = v->A_gm; for (int G = Ga; G < Gb; G++) for (int M = M1p; M < M2p; M++) tmp_GM[G * Mblock + M - Mstart] += \ A_gm[(G - Ga) * nm + M - M1] * phase; } } GRID_LOOP_STOP(lfc, k); double complex one = 1.0; zgemm_("C", "N", &Gmax, &nx, &Mblock, &one, tmp_GM, &Mblock, c_xM + Mstart, &Mmax, &one, psit_xG, &Gmax); } free(tmp_GM); Py_RETURN_NONE; } PyObject* add(LFCObject *lfc, PyObject *args) { PyArrayObject* c_xM_obj; PyArrayObject* a_xG_obj; int q; if (!PyArg_ParseTuple(args, "OOi", &c_xM_obj, &a_xG_obj, &q)) return NULL; int nd = PyArray_NDIM(a_xG_obj); npy_intp* dims = PyArray_DIMS(a_xG_obj); int nx = PyArray_MultiplyList(dims, nd - 3); int nG = PyArray_MultiplyList(dims + nd - 3, 3); int nM = PyArray_DIMS(c_xM_obj)[PyArray_NDIM(c_xM_obj) - 1]; if (!lfc->bloch_boundary_conditions) { const double* c_M = (const double*)PyArray_DATA(c_xM_obj); double* a_G = (double*)PyArray_DATA(a_xG_obj); for (int x = 0; x < nx; x++) { GRID_LOOP_START(lfc, -1) { for (int i = 0; i < ni; i++) { LFVolume* v = volume_i + i; for (int gm = 0, G = Ga; G < Gb; G++) { for (int m = 0; m < v->nm; m++, gm++) { a_G[G] += v->A_gm[gm] * c_M[v->M + m]; } } } } GRID_LOOP_STOP(lfc, -1); c_M += nM; a_G += nG; } } else { const double complex* c_M = (const double complex*)PyArray_DATA(c_xM_obj); double complex* a_G = (double complex*)PyArray_DATA(a_xG_obj); for (int x = 0; x < nx; x++) { GRID_LOOP_START(lfc, q) { for (int i = 0; i < ni; i++) { double complex conjphase = conj(phase_i[i]); LFVolume* v = volume_i + i; const double complex* c_M1 = c_M + v->M; const double* A_gm = v->A_gm; for (int gm = 0, G = Ga; G < Gb; G++) { double complex a = 0.0; for (int m = 0; m < v->nm; m++, gm++) { a += A_gm[gm] * c_M1[m]; } a_G[G] += a * conjphase; } } } GRID_LOOP_STOP(lfc, q); c_M += nM; a_G += nG; } } Py_RETURN_NONE; } PyObject* spline_to_grid(PyObject *self, PyObject *args) { SplineObject* spline_obj; PyArrayObject* beg_c_obj; PyArrayObject* end_c_obj; PyArrayObject* pos_v_obj; PyArrayObject* h_cv_obj; PyArrayObject* n_c_obj; PyArrayObject* gdcorner_c_obj; if (!PyArg_ParseTuple(args, "OOOOOOO", &spline_obj, &beg_c_obj, &end_c_obj, &pos_v_obj, &h_cv_obj, &n_c_obj, &gdcorner_c_obj)) return NULL; const bmgsspline* spline = (const bmgsspline*)(&(spline_obj->spline)); long* beg_c = LONGP(beg_c_obj); long* end_c = LONGP(end_c_obj); double* pos_v = DOUBLEP(pos_v_obj); double* h_cv = DOUBLEP(h_cv_obj); long* n_c = LONGP(n_c_obj); long* gdcorner_c = LONGP(gdcorner_c_obj); int l = spline_obj->spline.l; int nm = 2 * l + 1; double rcut = spline->dr * spline->nbins; int ngmax = ((end_c[0] - beg_c[0]) * (end_c[1] - beg_c[1]) * (end_c[2] - beg_c[2])); double* A_gm = GPAW_MALLOC(double, ngmax * nm); int nBmax = ((end_c[0] - beg_c[0]) * (end_c[1] - beg_c[1])); int* G_B = GPAW_MALLOC(int, 2 * nBmax); int nB = 0; int ngm = 0; int G = -gdcorner_c[2] + n_c[2] * (beg_c[1] - gdcorner_c[1] + n_c[1] * (beg_c[0] - gdcorner_c[0])); for (int g0 = beg_c[0]; g0 < end_c[0]; g0++) { for (int g1 = beg_c[1]; g1 < end_c[1]; g1++) { int g2_beg = -1; // function boundary coordinates int g2_end = -1; for (int g2 = beg_c[2]; g2 < end_c[2]; g2++) { double x = h_cv[0] * g0 + h_cv[3] * g1 + h_cv[6] * g2 - pos_v[0]; double y = h_cv[1] * g0 + h_cv[4] * g1 + h_cv[7] * g2 - pos_v[1]; double z = h_cv[2] * g0 + h_cv[5] * g1 + h_cv[8] * g2 - pos_v[2]; double r2 = x * x + y * y + z * z; double r = sqrt(r2); if (r < rcut) { if (g2_beg < 0) g2_beg = g2; // found boundary g2_end = g2; double A = bmgs_splinevalue(spline, r); double* p = A_gm + ngm; spherical_harmonics(l, A, x, y, z, r2, p); ngm += nm; } } if (g2_end >= 0) { g2_end++; G_B[nB++] = G + g2_beg; G_B[nB++] = G + g2_end; } G += n_c[2]; } G += n_c[2] * (n_c[1] - end_c[1] + beg_c[1]); } npy_intp gm_dims[2] = {ngm / (2 * l + 1), 2 * l + 1}; PyArrayObject* A_gm_obj = (PyArrayObject*)PyArray_SimpleNew(2, gm_dims, NPY_DOUBLE); memcpy(PyArray_DATA(A_gm_obj), A_gm, ngm * sizeof(double)); free(A_gm); npy_intp B_dims[1] = {nB}; PyArrayObject* G_B_obj = (PyArrayObject*)PyArray_SimpleNew(1, B_dims, NPY_INT); memcpy(PyArray_DATA(G_B_obj), G_B, nB * sizeof(int)); free(G_B); // PyObjects created in the C code will be initialized with a refcount // of 1, for which reason we'll have to decref them when done here PyObject* values = Py_BuildValue("(OO)", A_gm_obj, G_B_obj); Py_DECREF(A_gm_obj); Py_DECREF(G_B_obj); return values; } // Horrible copy-paste of calculate_potential_matrix // Surely it must be possible to find a way to actually reuse code // Maybe some kind of preprocessor thing PyObject* calculate_potential_matrix_derivative(LFCObject *lfc, PyObject *args) { PyArrayObject* vt_G_obj; PyArrayObject* DVt_MM_obj; PyArrayObject* h_cv_obj; PyArrayObject* n_c_obj; int k, c; PyArrayObject* spline_obj_M_obj; PyArrayObject* beg_c_obj; PyArrayObject* pos_Wc_obj; int Mstart, Mstop; if (!PyArg_ParseTuple(args, "OOOOiiOOOii", &vt_G_obj, &DVt_MM_obj, &h_cv_obj, &n_c_obj, &k, &c, &spline_obj_M_obj, &beg_c_obj, &pos_Wc_obj, &Mstart, &Mstop)) return NULL; const double* vt_G = (const double*)PyArray_DATA(vt_G_obj); const double* h_cv = (const double*)PyArray_DATA(h_cv_obj); const long* n_c = (const long*)PyArray_DATA(n_c_obj); const SplineObject** spline_obj_M = \ (const SplineObject**)PyArray_DATA(spline_obj_M_obj); const double (*pos_Wc)[3] = (const double (*)[3])PyArray_DATA(pos_Wc_obj); long* beg_c = LONGP(beg_c_obj); int nM = PyArray_DIMS(DVt_MM_obj)[1]; double* work_gm = lfc->work_gm; double dv = lfc->dv; if (!lfc->bloch_boundary_conditions) { double* DVt_MM = (double*)PyArray_DATA(DVt_MM_obj); { GRID_LOOP_START(lfc, -1) { // In one grid loop iteration, only z changes. int iza = Ga % n_c[2] + beg_c[2]; int iy = (Ga / n_c[2]) % n_c[1] + beg_c[1]; int ix = Ga / (n_c[2] * n_c[1]) + beg_c[0]; int iz = iza; //assert(Ga == ((ix - beg_c[0]) * n_c[1] + (iy - beg_c[1])) // * n_c[2] + iza - beg_c[2]); for (int i1 = 0; i1 < ni; i1++) { iz = iza; LFVolume* v1 = volume_i + i1; int M1 = v1->M; const SplineObject* spline_obj = spline_obj_M[M1]; const bmgsspline* spline = \ (const bmgsspline*)(&(spline_obj->spline)); int nm1 = v1->nm; int M1p = MAX(M1, Mstart); int nm1p = MIN(M1 + nm1, Mstop) - M1p; if (nm1p <= 0) continue; double fdYdc_m[nm1]; double rlYdfdr_m[nm1]; double f, dfdr; int l = (nm1 - 1) / 2; const double* pos_c = pos_Wc[v1->W]; //assert(2 * l + 1 == nm1); //assert(spline_obj->spline.l == l); int gm1 = 0; for (int G = Ga; G < Gb; G++, iz++) { double x = h_cv[0] * ix + h_cv[3] * iy + h_cv[6] * iz - pos_c[0]; double y = h_cv[1] * ix + h_cv[4] * iy + h_cv[7] * iz - pos_c[1]; double z = h_cv[2] * ix + h_cv[5] * iy + h_cv[8] * iz - pos_c[2]; double vtdv = vt_G[G] * dv; double R_c[] = {x, y, z}; double r2 = x * x + y * y + z * z; double r = sqrt(r2); double Rcinvr = r > 1e-15 ? R_c[c] / r : 0.0; //assert(G == ((ix - beg_c[0]) * n_c[1] + // (iy - beg_c[1])) * n_c[2] + iz - beg_c[2]); bmgs_get_value_and_derivative(spline, r, &f, &dfdr); //assert (r <= spline->dr * spline->nbins); // important switch(c) { case 0: spherical_harmonics_derivative_x(l, f, x, y, z, r2, fdYdc_m); break; case 1: spherical_harmonics_derivative_y(l, f, x, y, z, r2, fdYdc_m); break; case 2: spherical_harmonics_derivative_z(l, f, x, y, z, r2, fdYdc_m); break; } spherical_harmonics(l, dfdr * Rcinvr, x, y, z, r2, rlYdfdr_m); int m1start = M1 < Mstart ? nm1 - nm1p : 0; for (int m1 = 0; m1 < nm1p; m1++, gm1++) { work_gm[gm1] = vtdv * (fdYdc_m[m1 + m1start] + rlYdfdr_m[m1 + m1start]); } } // end loop over G for (int i2 = 0; i2 < ni; i2++) { LFVolume* v2 = volume_i + i2; int M2 = v2->M; const double* A2_start_gm = v2->A_gm; const double* A2_gm; int nm2 = v2->nm; double* DVt_start_mm = DVt_MM + (M1p - Mstart) * nM + M2; double* DVt_mm; double work; for (int g = 0; g < nG; g++) { A2_gm = A2_start_gm + g * nm2; for (int m1 = 0; m1 < nm1p; m1++) { work = work_gm[g * nm1p + m1]; DVt_mm = DVt_start_mm + m1 * nM; for (int m2 = 0; m2 < nm2; m2++) { DVt_mm[m2] += A2_gm[m2] * work; } } } } // i2 loop } // G loop } // i1 loop GRID_LOOP_STOP(lfc, -1); } // c loop } else { complex double* DVt_MM = (complex double*)PyArray_DATA(DVt_MM_obj); { GRID_LOOP_START(lfc, k) { // In one grid loop iteration, only z changes. int iza = Ga % n_c[2] + beg_c[2]; int iy = (Ga / n_c[2]) % n_c[1] + beg_c[1]; int ix = Ga / (n_c[2] * n_c[1]) + beg_c[0]; int iz = iza; for (int i1 = 0; i1 < ni; i1++) { iz = iza; LFVolume* v1 = volume_i + i1; int M1 = v1->M; const SplineObject* spline_obj = spline_obj_M[M1]; const bmgsspline* spline = \ (const bmgsspline*)(&(spline_obj->spline)); int nm1 = v1->nm; int M1p = MAX(M1, Mstart); int nm1p = MIN(M1 + nm1, Mstop) - M1p; if (nm1p <= 0) continue; double fdYdc_m[nm1]; double rlYdfdr_m[nm1]; double f, dfdr; int l = (nm1 - 1) / 2; //assert(2 * l + 1 == nm1); //assert(spline_obj->spline.l == l); const double* pos_c = pos_Wc[v1->W]; int gm1 = 0; for (int G = Ga; G < Gb; G++, iz++) { double x = h_cv[0] * ix + h_cv[3] * iy + h_cv[6] * iz - pos_c[0]; double y = h_cv[1] * ix + h_cv[4] * iy + h_cv[7] * iz - pos_c[1]; double z = h_cv[2] * ix + h_cv[5] * iy + h_cv[8] * iz - pos_c[2]; double vtdv = vt_G[G] * dv; double R_c[] = {x, y, z}; double r2 = x * x + y * y + z * z; double r = sqrt(r2); double Rc_over_r = r > 1e-15 ? R_c[c] / r : 0.0; bmgs_get_value_and_derivative(spline, r, &f, &dfdr); //assert (r <= spline->dr * spline->nbins); switch(c) { case 0: spherical_harmonics_derivative_x(l, f, x, y, z, r2, fdYdc_m); break; case 1: spherical_harmonics_derivative_y(l, f, x, y, z, r2, fdYdc_m); break; case 2: spherical_harmonics_derivative_z(l, f, x, y, z, r2, fdYdc_m); break; } spherical_harmonics(l, dfdr * Rc_over_r, x, y, z, r2, rlYdfdr_m); int m1start = M1 < Mstart ? nm1 - nm1p : 0; for (int m1 = 0; m1 < nm1p; m1++, gm1++) { work_gm[gm1] = vtdv * (fdYdc_m[m1 + m1start] + rlYdfdr_m[m1 + m1start]); } } // end loop over G for (int i2 = 0; i2 < ni; i2++) { LFVolume* v2 = volume_i + i2; int M2 = v2->M; const double* A2_start_gm = v2->A_gm; const double* A2_gm; double complex* DVt_start_mm = DVt_MM + (M1p - Mstart) * nM + M2; double complex* DVt_mm; double complex work; int nm2 = v2->nm; double complex phase = conj(phase_i[i1]) * phase_i[i2]; for (int g = 0; g < nG; g++) { A2_gm = A2_start_gm + g * nm2; for (int m1 = 0; m1 < nm1p; m1++) { work = work_gm[g * nm1p + m1] * phase; DVt_mm = DVt_start_mm + m1 * nM; for (int m2 = 0; m2 < nm2; m2++) { DVt_mm[m2] += A2_gm[m2] * work; } } } } // i2 loop } // G loop } // i1 loop GRID_LOOP_STOP(lfc, k); } // c loop } Py_RETURN_NONE; } // Horrible copy-paste of calculate_potential_matrix // Surely it must be possible to find a way to actually reuse code // Maybe some kind of preprocessor thing PyObject* calculate_potential_matrix_force_contribution(LFCObject *lfc, PyObject *args) { PyArrayObject* vt_G_obj; PyArrayObject* rho_MM_obj; PyArrayObject* F_M_obj; PyArrayObject* h_cv_obj; PyArrayObject* n_c_obj; int k, c; PyArrayObject* spline_obj_M_obj; PyArrayObject* beg_c_obj; PyArrayObject* pos_Wc_obj; int Mstart, Mstop; if (!PyArg_ParseTuple(args, "OOOOOiiOOOii", &vt_G_obj, &rho_MM_obj, &F_M_obj, &h_cv_obj, &n_c_obj, &k, &c, &spline_obj_M_obj, &beg_c_obj, &pos_Wc_obj, &Mstart, &Mstop)) return NULL; const double* vt_G = (const double*)PyArray_DATA(vt_G_obj); const double* h_cv = (const double*)PyArray_DATA(h_cv_obj); const long* n_c = (const long*)PyArray_DATA(n_c_obj); const SplineObject** spline_obj_M = \ (const SplineObject**)PyArray_DATA(spline_obj_M_obj); const double (*pos_Wc)[3] = (const double (*)[3])PyArray_DATA(pos_Wc_obj); double* F_M = (double*)PyArray_DATA(F_M_obj); long* beg_c = LONGP(beg_c_obj); int nM = PyArray_DIMS(rho_MM_obj)[1]; double* work_gm = lfc->work_gm; double dv = lfc->dv; if (!lfc->bloch_boundary_conditions) { double* rho_MM = (double*)PyArray_DATA(rho_MM_obj); { GRID_LOOP_START(lfc, -1) { // In one grid loop iteration, only z changes. int iza = Ga % n_c[2] + beg_c[2]; int iy = (Ga / n_c[2]) % n_c[1] + beg_c[1]; int ix = Ga / (n_c[2] * n_c[1]) + beg_c[0]; int iz = iza; //assert(Ga == ((ix - beg_c[0]) * n_c[1] + (iy - beg_c[1])) // * n_c[2] + iza - beg_c[2]); for (int i1 = 0; i1 < ni; i1++) { iz = iza; LFVolume* v1 = volume_i + i1; int M1 = v1->M; const SplineObject* spline_obj = spline_obj_M[M1]; const bmgsspline* spline = \ (const bmgsspline*)(&(spline_obj->spline)); int nm1 = v1->nm; int M1p = MAX(M1, Mstart); int nm1p = MIN(M1 + nm1, Mstop) - M1p; if (nm1p <= 0) continue; int m1start = M1 < Mstart ? nm1 - nm1p : 0; double fdYdc_m[nm1]; double rlYdfdr_m[nm1]; double f, dfdr; int l = (nm1 - 1) / 2; const double* pos_c = pos_Wc[v1->W]; //assert(2 * l + 1 == nm1); //assert(spline_obj->spline.l == l); int gm1 = 0; for (int G = Ga; G < Gb; G++, iz++) { double x = h_cv[0] * ix + h_cv[3] * iy + h_cv[6] * iz - pos_c[0]; double y = h_cv[1] * ix + h_cv[4] * iy + h_cv[7] * iz - pos_c[1]; double z = h_cv[2] * ix + h_cv[5] * iy + h_cv[8] * iz - pos_c[2]; double vtdv = vt_G[G] * dv; double R_c[] = {x, y, z}; double r2 = x * x + y * y + z * z; double r = sqrt(r2); double Rcinvr = r > 1e-15 ? R_c[c] / r : 0.0; //assert(G == ((ix - beg_c[0]) * n_c[1] + // (iy - beg_c[1])) * n_c[2] + iz - beg_c[2]); bmgs_get_value_and_derivative(spline, r, &f, &dfdr); //assert (r <= spline->dr * spline->nbins); // important switch(c) { case 0: spherical_harmonics_derivative_x(l, f, x, y, z, r2, fdYdc_m); break; case 1: spherical_harmonics_derivative_y(l, f, x, y, z, r2, fdYdc_m); break; case 2: spherical_harmonics_derivative_z(l, f, x, y, z, r2, fdYdc_m); break; } spherical_harmonics(l, dfdr * Rcinvr, x, y, z, r2, rlYdfdr_m); for (int m1 = 0; m1 < nm1p; m1++, gm1++) { work_gm[gm1] = vtdv * (fdYdc_m[m1 + m1start] + rlYdfdr_m[m1 + m1start]); } } // end loop over G for (int i2 = 0; i2 < ni; i2++) { LFVolume* v2 = volume_i + i2; int M2 = v2->M; const double* A2_start_gm = v2->A_gm; const double* A2_gm; int nm2 = v2->nm; double* rho_start_mm = rho_MM + (M1p - Mstart) * nM + M2; double* rho_mm; double work; for (int g = 0; g < nG; g++) { A2_gm = A2_start_gm + g * nm2; for (int m1 = 0; m1 < nm1p; m1++) { rho_mm = rho_start_mm + m1 * nM; work = 0.0; for (int m2 = 0; m2 < nm2; m2++) { work += A2_gm[m2] * rho_mm[m2]; } F_M[M1p - Mstart + m1] += work * work_gm[g * nm1p + m1]; } } } // i2 loop } // G loop } // i1 loop GRID_LOOP_STOP(lfc, -1); } // c loop } else { complex double* rho_MM = (complex double*)PyArray_DATA(rho_MM_obj); { GRID_LOOP_START(lfc, k) { // In one grid loop iteration, only z changes. int iza = Ga % n_c[2] + beg_c[2]; int iy = (Ga / n_c[2]) % n_c[1] + beg_c[1]; int ix = Ga / (n_c[2] * n_c[1]) + beg_c[0]; int iz = iza; for (int i1 = 0; i1 < ni; i1++) { iz = iza; LFVolume* v1 = volume_i + i1; int M1 = v1->M; const SplineObject* spline_obj = spline_obj_M[M1]; const bmgsspline* spline = \ (const bmgsspline*)(&(spline_obj->spline)); int nm1 = v1->nm; int M1p = MAX(M1, Mstart); int nm1p = MIN(M1 + nm1, Mstop) - M1p; if (nm1p <= 0) continue; int m1start = M1 < Mstart ? nm1 - nm1p : 0; double fdYdc_m[nm1]; double rlYdfdr_m[nm1]; double f, dfdr; int l = (nm1 - 1) / 2; //assert(2 * l + 1 == nm1); //assert(spline_obj->spline.l == l); const double* pos_c = pos_Wc[v1->W]; int gm1 = 0; for (int G = Ga; G < Gb; G++, iz++) { double x = h_cv[0] * ix + h_cv[3] * iy + h_cv[6] * iz - pos_c[0]; double y = h_cv[1] * ix + h_cv[4] * iy + h_cv[7] * iz - pos_c[1]; double z = h_cv[2] * ix + h_cv[5] * iy + h_cv[8] * iz - pos_c[2]; double vtdv = vt_G[G] * dv; double R_c[] = {x, y, z}; double r2 = x * x + y * y + z * z; double r = sqrt(r2); double Rc_over_r = r > 1e-15 ? R_c[c] / r : 0.0; bmgs_get_value_and_derivative(spline, r, &f, &dfdr); //assert (r <= spline->dr * spline->nbins); switch(c) { case 0: spherical_harmonics_derivative_x(l, f, x, y, z, r2, fdYdc_m); break; case 1: spherical_harmonics_derivative_y(l, f, x, y, z, r2, fdYdc_m); break; case 2: spherical_harmonics_derivative_z(l, f, x, y, z, r2, fdYdc_m); break; } spherical_harmonics(l, dfdr * Rc_over_r, x, y, z, r2, rlYdfdr_m); for (int m1 = 0; m1 < nm1p; m1++, gm1++) { work_gm[gm1] = vtdv * (fdYdc_m[m1 + m1start] + rlYdfdr_m[m1 + m1start]); } } // end loop over G for (int i2 = 0; i2 < ni; i2++) { LFVolume* v2 = volume_i + i2; int M2 = v2->M; const double* A2_start_gm = v2->A_gm; const double* A2_gm; int nm2 = v2->nm; double complex* rho_start_mm = rho_MM + (M1p - Mstart) * nM + M2; double complex* rho_mm; double complex phase = conj(phase_i[i1]) * phase_i[i2]; double complex work; for (int g = 0; g < nG; g++) { A2_gm = A2_start_gm + g * nm2; for (int m1 = 0; m1 < nm1p; m1++) { rho_mm = rho_start_mm + m1 * nM; work = 0.0; for (int m2 = 0; m2 < nm2; m2++) { work += A2_gm[m2] * rho_mm[m2]; } F_M[M1p - Mstart + m1] += creal(work * work_gm[g * nm1p + m1] * phase); } } } // i2 loop } // G loop } // i1 loop GRID_LOOP_STOP(lfc, k); } // c loop } Py_RETURN_NONE; } PyObject* derivative(LFCObject *lfc, PyObject *args) { PyArrayObject* a_xG_obj; PyArrayObject* c_xMv_obj; PyArrayObject* h_cv_obj; PyArrayObject* n_c_obj; PyObject* spline_M_obj; PyArrayObject* beg_c_obj; PyArrayObject* pos_Wc_obj; int q; if (!PyArg_ParseTuple(args, "OOOOOOOi", &a_xG_obj, &c_xMv_obj, &h_cv_obj, &n_c_obj, &spline_M_obj, &beg_c_obj, &pos_Wc_obj, &q)) return NULL; int nd = PyArray_NDIM(a_xG_obj); npy_intp* dims = PyArray_DIMS(a_xG_obj); int nx = PyArray_MultiplyList(dims, nd - 3); int nG = PyArray_MultiplyList(dims + nd - 3, 3); int nM = PyArray_DIMS(c_xMv_obj)[PyArray_NDIM(c_xMv_obj) - 2]; const double* h_cv = (const double*)PyArray_DATA(h_cv_obj); const long* n_c = (const long*)PyArray_DATA(n_c_obj); const double (*pos_Wc)[3] = (const double (*)[3])PyArray_DATA(pos_Wc_obj); long* beg_c = LONGP(beg_c_obj); if (!lfc->bloch_boundary_conditions) { const double* a_G = (const double*)PyArray_DATA(a_xG_obj); double* c_Mv = (double*)PyArray_DATA(c_xMv_obj); for (int x = 0; x < nx; x++) { GRID_LOOP_START(lfc, -1) { // In one grid loop iteration, only i2 changes. int i2 = Ga % n_c[2] + beg_c[2]; int i1 = (Ga / n_c[2]) % n_c[1] + beg_c[1]; int i0 = Ga / (n_c[2] * n_c[1]) + beg_c[0]; double xG = h_cv[0] * i0 + h_cv[3] * i1 + h_cv[6] * i2; double yG = h_cv[1] * i0 + h_cv[4] * i1 + h_cv[7] * i2; double zG = h_cv[2] * i0 + h_cv[5] * i1 + h_cv[8] * i2; for (int G = Ga; G < Gb; G++) { for (int i = 0; i < ni; i++) { LFVolume* vol = volume_i + i; int M = vol->M; double* c_mv = c_Mv + 3 * M; const bmgsspline* spline = (const bmgsspline*) \ &((const SplineObject*)PyList_GetItem(spline_M_obj, M))->spline; int nm = vol->nm; int l = (nm - 1) / 2; double x = xG - pos_Wc[vol->W][0]; double y = yG - pos_Wc[vol->W][1]; double z = zG - pos_Wc[vol->W][2]; double R_c[] = {x, y, z}; double r2 = x * x + y * y + z * z; double r = sqrt(r2); double af; double dfdr; bmgs_get_value_and_derivative(spline, r, &af, &dfdr); af *= a_G[G] * lfc->dv; double afdrlYdx_m[nm]; // a * f * d(r^l * Y)/dx spherical_harmonics_derivative_x(l, af, x, y, z, r2, afdrlYdx_m); for (int m = 0; m < nm; m++) c_mv[3 * m] += afdrlYdx_m[m]; spherical_harmonics_derivative_y(l, af, x, y, z, r2, afdrlYdx_m); for (int m = 0; m < nm; m++) c_mv[3 * m + 1] += afdrlYdx_m[m]; spherical_harmonics_derivative_z(l, af, x, y, z, r2, afdrlYdx_m); for (int m = 0; m < nm; m++) c_mv[3 * m + 2] += afdrlYdx_m[m]; if (r > 1e-15) { double arlm1Ydfdr_m[nm]; // a * r^(l-1) * Y * df/dr double arm1dfdr = a_G[G] / r * dfdr * lfc->dv; spherical_harmonics(l, arm1dfdr, x, y, z, r2, arlm1Ydfdr_m); for (int m = 0; m < nm; m++) for (int v = 0; v < 3; v++) c_mv[m * 3 + v] += arlm1Ydfdr_m[m] * R_c[v]; } } xG += h_cv[6]; yG += h_cv[7]; zG += h_cv[8]; } } GRID_LOOP_STOP(lfc, -1); c_Mv += 3 * nM; a_G += nG; } } else { const complex double* a_G = (const complex double*)PyArray_DATA(a_xG_obj); complex double* c_Mv = (complex double*)PyArray_DATA(c_xMv_obj); for (int x = 0; x < nx; x++) { GRID_LOOP_START(lfc, q) { // In one grid loop iteration, only i2 changes. int i2 = Ga % n_c[2] + beg_c[2]; int i1 = (Ga / n_c[2]) % n_c[1] + beg_c[1]; int i0 = Ga / (n_c[2] * n_c[1]) + beg_c[0]; double xG = h_cv[0] * i0 + h_cv[3] * i1 + h_cv[6] * i2; double yG = h_cv[1] * i0 + h_cv[4] * i1 + h_cv[7] * i2; double zG = h_cv[2] * i0 + h_cv[5] * i1 + h_cv[8] * i2; for (int G = Ga; G < Gb; G++) { for (int i = 0; i < ni; i++) { LFVolume* vol = volume_i + i; int M = vol->M; complex double* c_mv = c_Mv + 3 * M; const bmgsspline* spline = (const bmgsspline*) \ &((const SplineObject*)PyList_GetItem(spline_M_obj, M))->spline; int nm = vol->nm; int l = (nm - 1) / 2; double x = xG - pos_Wc[vol->W][0]; double y = yG - pos_Wc[vol->W][1]; double z = zG - pos_Wc[vol->W][2]; double R_c[] = {x, y, z}; double r2 = x * x + y * y + z * z; double r = sqrt(r2); double f; double dfdr; bmgs_get_value_and_derivative(spline, r, &f, &dfdr); double fdrlYdx_m[nm]; // a * f * d(r^l * Y)/dx complex double ap = a_G[G] * phase_i[i] * lfc->dv; spherical_harmonics_derivative_x(l, f, x, y, z, r2, fdrlYdx_m); for (int m = 0; m < nm; m++) c_mv[3 * m ] += ap * fdrlYdx_m[m]; spherical_harmonics_derivative_y(l, f, x, y, z, r2, fdrlYdx_m); for (int m = 0; m < nm; m++) c_mv[3 * m + 1] += ap * fdrlYdx_m[m]; spherical_harmonics_derivative_z(l, f, x, y, z, r2, fdrlYdx_m); for (int m = 0; m < nm; m++) c_mv[3 * m + 2] += ap * fdrlYdx_m[m]; if (r > 1e-15) { double rlm1Ydfdr_m[nm]; // r^(l-1) * Y * df/dr double rm1dfdr = dfdr / r; spherical_harmonics(l, rm1dfdr, x, y, z, r2, rlm1Ydfdr_m); for (int m = 0; m < nm; m++) for (int v = 0; v < 3; v++) c_mv[m * 3 + v] += ap * rlm1Ydfdr_m[m] * R_c[v]; } } xG += h_cv[6]; yG += h_cv[7]; zG += h_cv[8]; } } GRID_LOOP_STOP(lfc, q); c_Mv += 3 * nM; a_G += nG; } } Py_RETURN_NONE; } PyObject* normalized_derivative(LFCObject *lfc, PyObject *args) { PyArrayObject* a_G_obj; PyArrayObject* c_Mv_obj; PyArrayObject* h_cv_obj; PyArrayObject* n_c_obj; PyObject* spline_M_obj; PyArrayObject* beg_c_obj; PyArrayObject* pos_Wc_obj; if (!PyArg_ParseTuple(args, "OOOOOOO", &a_G_obj, &c_Mv_obj, &h_cv_obj, &n_c_obj, &spline_M_obj, &beg_c_obj, &pos_Wc_obj)) return NULL; const double* h_cv = (const double*)PyArray_DATA(h_cv_obj); const long* n_c = (const long*)PyArray_DATA(n_c_obj); const double (*pos_Wc)[3] = (const double (*)[3])PyArray_DATA(pos_Wc_obj); long* beg_c = LONGP(beg_c_obj); const double* a_G = (const double*)PyArray_DATA(a_G_obj); double* c_Mv = (double*)PyArray_DATA(c_Mv_obj); GRID_LOOP_START(lfc, -1) { int i2 = Ga % n_c[2] + beg_c[2]; int i1 = (Ga / n_c[2]) % n_c[1] + beg_c[1]; int i0 = Ga / (n_c[2] * n_c[1]) + beg_c[0]; double xG = h_cv[0] * i0 + h_cv[3] * i1 + h_cv[6] * i2; double yG = h_cv[1] * i0 + h_cv[4] * i1 + h_cv[7] * i2; double zG = h_cv[2] * i0 + h_cv[5] * i1 + h_cv[8] * i2; for (int G = Ga; G < Gb; G++) { for (int i = 0; i < ni; i++) { LFVolume* vol = volume_i + i; int M = vol->M; double* c_mv = c_Mv + 7 * M; const bmgsspline* spline = (const bmgsspline*) \ &((const SplineObject*)PyList_GetItem(spline_M_obj, M))->spline; int nm = vol->nm; int l = (nm - 1) / 2; double x = xG - pos_Wc[vol->W][0]; double y = yG - pos_Wc[vol->W][1]; double z = zG - pos_Wc[vol->W][2]; double R_c[] = {x, y, z}; double r2 = x * x + y * y + z * z; double r = sqrt(r2); double f; double dfdr; bmgs_get_value_and_derivative(spline, r, &f, &dfdr); f *= lfc->dv; double a = a_G[G]; if (l == 0) c_mv[6] += 0.28209479177387814 * a * f; double fdrlYdx_m[nm]; // f * d(r^l * Y)/dx spherical_harmonics_derivative_x(l, f, x, y, z, r2, fdrlYdx_m); for (int m = 0; m < nm; m++) { c_mv[7 * m ] += a * fdrlYdx_m[m]; c_mv[7 * m + 3] += fdrlYdx_m[m]; } spherical_harmonics_derivative_y(l, f, x, y, z, r2, fdrlYdx_m); for (int m = 0; m < nm; m++) { c_mv[7 * m + 1] += a * fdrlYdx_m[m]; c_mv[7 * m + 4] += fdrlYdx_m[m]; } spherical_harmonics_derivative_z(l, f, x, y, z, r2, fdrlYdx_m); for (int m = 0; m < nm; m++) { c_mv[7 * m + 2] += a * fdrlYdx_m[m]; c_mv[7 * m + 5] += fdrlYdx_m[m]; } if (r > 1e-15) { double rlm1Ydfdr_m[nm]; // r^(l-1) * Y * df/dr double rm1dfdr = dfdr * lfc->dv / r; spherical_harmonics(l, rm1dfdr, x, y, z, r2, rlm1Ydfdr_m); for (int m = 0; m < nm; m++) for (int v = 0; v < 3; v++) { c_mv[m * 7 + v] += a * rlm1Ydfdr_m[m] * R_c[v]; c_mv[m * 7 + v + 3] += rlm1Ydfdr_m[m] * R_c[v]; } } } xG += h_cv[6]; yG += h_cv[7]; zG += h_cv[8]; } } GRID_LOOP_STOP(lfc, -1); Py_RETURN_NONE; } PyObject* ae_valence_density_correction(LFCObject *lfc, PyObject *args) { PyArrayObject* rho_MM_obj; PyArrayObject* n_G_obj; PyArrayObject* a_W_obj; PyArrayObject* I_a_obj; PyArrayObject* x_W_obj; if (!PyArg_ParseTuple(args, "OOOOO", &rho_MM_obj, &n_G_obj, &a_W_obj, &I_a_obj, &x_W_obj)) return NULL; double* n_G = (double*)PyArray_DATA(n_G_obj); int* a_W = (int*)PyArray_DATA(a_W_obj); double* I_a = (double*)PyArray_DATA(I_a_obj); const double* rho_MM = (const double*)PyArray_DATA(rho_MM_obj); int* x_W = (int*)PyArray_DATA(x_W_obj); int nM = PyArray_DIMS(rho_MM_obj)[0]; GRID_LOOP_START(lfc, -1) { for (int i1 = 0; i1 < ni; i1++) { LFVolume* v1 = volume_i + i1; int x1 = x_W[v1->W]; int a1 = a_W[v1->W]; int M1 = v1->M; int nm1 = v1->nm; double Ia = 0.0; for (int i2 = 0; i2 < ni; i2++) { LFVolume* v2 = volume_i + i2; int x2 = x_W[v2->W]; if (x1 != x2) continue; int a2 = a_W[v2->W]; if (a1 != a2) continue; int M2 = v2->M; int nm2 = v2->nm; const double* rho_mm = rho_MM + M1 * nM + M2; for (int g = 0; g < nG; g++) { double density = 0.0; for (int m2 = 0; m2 < nm2; m2++) for (int m1 = 0; m1 < nm1; m1++) density += (rho_mm[m2 + m1 * nM] * v1->A_gm[g * nm1 + m1] * v2->A_gm[g * nm2 + m2]); n_G[Ga + g] += density; Ia += density; } } I_a[a1] += Ia * lfc->dv; } } GRID_LOOP_STOP(lfc, -1); Py_RETURN_NONE; } PyObject* ae_core_density_correction(LFCObject *lfc, PyObject *args) { double scale; PyArrayObject* n_G_obj; PyArrayObject* a_W_obj; PyArrayObject* I_a_obj; if (!PyArg_ParseTuple(args, "dOOO", &scale, &n_G_obj, &a_W_obj, &I_a_obj)) return NULL; double* n_G = (double*)PyArray_DATA(n_G_obj); int* a_W = (int*)PyArray_DATA(a_W_obj); double* I_a = (double*)PyArray_DATA(I_a_obj); GRID_LOOP_START(lfc, -1) { for (int i = 0; i < ni; i++) { LFVolume* v = volume_i + i; double Ia = 0.0; for (int g = 0; g < nG; g++) { double density = scale * v->A_gm[g]; n_G[Ga + g] += density; Ia += density; } I_a[a_W[v->W]] += Ia * lfc->dv; } } GRID_LOOP_STOP(lfc, -1); Py_RETURN_NONE; } gpaw-0.11.0.13004/COPYING0000664000175000017500000010451312553643470014513 0ustar jensjjensj00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . gpaw-0.11.0.13004/README.txt0000664000175000017500000000165612553643470015162 0ustar jensjjensj00000000000000-------------------------------------- GPAW: a grid-based real-space PAW code -------------------------------------- Copyright (c) 2004 CAMP Installation ------------ For installation instructions, please see: http://wiki.fysik.dtu.dk/gpaw License ------- See LICENSE --------------- ------------------------------- File Description --------------- ------------------------------- README.txt This file LICENSE GPL-license summary COPYING GPL-license setup.py distutils script config.py Configuration stuff customize.py Help distutils find libraries MANIFEST.in distutils MANIFEST.in file --------------- ------------------------------- --------- --------------- Directory Description --------- --------------- c C-extensions doc Documentation gpaw The Python code gpaw/test Test suite tools Useful tools --------- --------------- gpaw-0.11.0.13004/customize.py0000664000175000017500000000407612553643470016057 0ustar jensjjensj00000000000000#User provided customizations for the gpaw setup #Here, one can override the default arguments, or append own #arguments to default ones #To override use the form # libraries = ['somelib','otherlib'] #To append use the form # libraries += ['somelib','otherlib'] import os if 'GPAW_MPI' in os.environ: # Build MPI-interface into _gpaw.so: compiler = 'mpicc' define_macros += [('PARALLEL', '1')] mpicompiler = None #compiler = 'mpcc' #libraries = [] #libraries += [] #library_dirs = [] #library_dirs += [] #include_dirs = [] #include_dirs += [] #extra_link_args = [] #extra_link_args += [] #extra_compile_args = [] #extra_compile_args += [] #runtime_library_dirs = [] #runtime_library_dirs += [] #extra_objects = [] #extra_objects += [] #define_macros = [] #define_macros += [] #mpicompiler = None #mpilinker = None #mpi_libraries = [] #mpi_libraries += [] #mpi_library_dirs = [] #mpi_library_dirs += [] #mpi_include_dirs = [] #mpi_include_dirs += [] #mpi_runtime_library_dirs = [] #mpi_runtime_library_dirs += [] #mpi_define_macros = [] #mpi_define_macros += [] #platform_id = '' #hdf5 = True # Valid values for scalapack are False, or True: # False (the default) - no ScaLapack compiled in # True - ScaLapack compiled in # Warning! At least scalapack 2.0.1 is required! # See https://trac.fysik.dtu.dk/projects/gpaw/ticket/230 scalapack = False if scalapack: libraries += ['scalapack'] library_dirs += [] define_macros += [('GPAW_NO_UNDERSCORE_CBLACS', '1')] define_macros += [('GPAW_NO_UNDERSCORE_CSCALAPACK', '1')] # In order to link libxc installed in a non-standard location # (e.g.: configure --prefix=/home/user/libxc-2.0.1-1), use: # - static linking: #include_dirs += ['/home/user/libxc-2.0.1-1/include'] #extra_link_args += ['/home/user/libxc-2.0.1-1/lib/libxc.a'] #if 'xc' in libraries: libraries.remove('xc') # - dynamic linking (requires also setting LD_LIBRARY_PATH at runtime): #include_dirs += ['/home/user/libxc-2.0.1-1/include'] #library_dirs += ['/home/user/libxc-2.0.1-1/lib'] #if 'xc' not in libraries: libraries.append('xc') gpaw-0.11.0.13004/tools/0000775000175000017500000000000012553644063014613 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/tools/gpaw-test0000775000175000017500000001335312553643466016467 0ustar jensjjensj00000000000000#!/usr/bin/env python import os import sys import tempfile import numpy as np from trace import Trace, pickle def err(msg): sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), msg)) def main(outfile, tests=None, testscript='test.py'): assert 'gpaw' not in sys.modules, 'GPAW must be unloaded first!' ignore_modules = [] ignore_dirs = filter(len, os.getenv('IGNOREPATHS', default='').split(':')) ignore_dirs.extend(np.__path__) # saves time try: # Trace module in Python 2.4 dislikes files without newline # at the end. Unfortunately SciPy lacks one in __config__.py import scipy ignore_dirs.extend(scipy.__path__) except ImportError: pass # Temporary file and directory for coverage results on this core coverfile = tempfile.mktemp(prefix='gpaw-coverfile-') coverdir = tempfile.mkdtemp(prefix='gpaw-coverdir-') trace = Trace(count=1, trace=0, countfuncs=False, countcallers=False, ignoremods=ignore_modules, ignoredirs=ignore_dirs, infile=None, outfile=coverfile) if tests is not None: sys.argv.extend(tests) try: trace.run('execfile(%r, {})' % (testscript,)) except IOError as e: err('Could not run test script %r because: %s' % (testscript, e)) sys.exit(1) except SystemExit: pass coverage = trace.results() coverage.write_results(summary=False, coverdir=coverdir) # temporary file # NB: Do not import from gpaw before trace has been run! from gpaw import mpi from gpaw.version import version mycounts = pickle.load(open(coverfile, 'rb'))[0] if mpi.world.rank == 0: _key = ('',-1,) # entries with filename are ignored _value = np.fromstring(version, sep='.', dtype=int) _v = lambda v, sep='.': sep.join(map(str,v)) if os.path.isfile(outfile): print('Resuming existing coverage file ...') counts, calledfuncs, callers = pickle.load(open(outfile, 'rb')) assert not calledfuncs and not callers # should both be empty try: assert np.all(counts[_key]==_value), (_v(counts[_key]),version) except KeyError: err('Coverage file has no version. %s was assumed.' % version) counts[_key] = _value except AssertionError as e: if e[0] > e[1]: # trying to overwrite newer should fail err('Coverage file version %s (> %s). Aborting.' % e[:]) sys.exit(1) err('Coverage file version %s (< %s). Data discarded.' % e[:]) counts = {_key: _value} else: print('Initiating new coverage file ...') counts = {_key: _value} if mpi.world.size == 1: # Merge generated cover file with existing (if any) for filename,line in mycounts.keys(): counts[(filename,line)] = mycounts.pop((filename,line)) \ + counts.get((filename,line), 0) else: # Find largest line number detected for each locally executed file myfiles = {} for filename,line in mycounts.keys(): assert '\n' not in filename myfiles[filename] = max(myfiles.get(filename,0), line) # Agree on which files have been executed on at least one core filenames = myfiles.keys() if mpi.world.rank == 0: for rank in range(1, mpi.world.size): filenames.extend(mpi.receive_string(rank).split('\n')) filenames = np.unique(filenames).tolist() tmp = '\n'.join(filenames) else: mpi.send_string('\n'.join(filenames), 0) tmp = None filenames = mpi.broadcast_string(tmp).split('\n') # Map out largest line number detected for each globally executed file filesizes = np.array([myfiles.get(filename,0) for filename in filenames]) mpi.world.max(filesizes) # Merge global totals of generated cover files with existing (if any) # NB: Techically, line numbers are one-indexed but empty files may # lead to entries at (filename,0) due to a Python 2.4 quirk. for filename,lines in zip(filenames,filesizes): numexecs = np.zeros(lines+1, dtype=int) for line in range(lines+1): if (filename,line) in mycounts: numexecs[line] = mycounts.pop((filename,line)) mpi.world.sum(numexecs, 0) if mpi.world.rank == 0: for line in np.argwhere(numexecs).ravel(): counts[(filename,line)] = numexecs[line] \ + counts.get((filename,line), 0) # Store as 3-tuple of dicts in a new pickle (i.e. same format + versions) if mpi.world.rank == 0: pickle.dump((counts,{},{}), open(outfile, 'wb'), 1) mpi.world.barrier() del version, mpi, sys.modules['gpaw'] # unload gpaw module references assert not mycounts, 'Not all entries were processed: %s' % mycounts.keys() os.system('rm -rf ' + coverfile + ' ' + coverdir) if '--coverage' in sys.argv: i = sys.argv.index('--coverage') sys.argv.pop(i) outfile = sys.argv.pop(i) # Get full path of test script without importing GPAW ourself import subprocess poi = subprocess.Popen('python -c "import gpaw; print gpaw.__path__[0]"', \ shell=True, stdout=subprocess.PIPE) testscript = poi.stdout.read().strip() + '/test/test.py' if poi.wait() != 0 or not os.path.isfile(testscript): raise RuntimeError('Could not locate test script (%s).' % testscript) # Perform coverage test main(outfile, tests=[], testscript=testscript) else: import sys from gpaw.test.test import run nfailed = run() gpaw-0.11.0.13004/tools/gpaw-setup0000775000175000017500000000015412553643466016643 0ustar jensjjensj00000000000000#!/usr/bin/env python # Emacs: treat this as -*- python -*- from gpaw.atom.gpaw_setup import main main() gpaw-0.11.0.13004/tools/gpaw-basis0000775000175000017500000000015312553643466016603 0ustar jensjjensj00000000000000#!/usr/bin/env python # Emacs: treat this as -*- python -*- from gpaw.atom.gpaw_basis import main main() gpaw-0.11.0.13004/tools/gpaw-runscript0000775000175000017500000007626412553643466017553 0ustar jensjjensj00000000000000#!/bin/env python # Emacs: treat this as -*- python -*- import os import stat import sys import re from optparse import OptionParser defaults = { 'err' : None, 'mail' : None, 'mem' : None, 'name' : None, 'depth' : 1, 'cores' : 2, 'out' : None, 'arch' : 'pbs', 'script': 'run.py', 'time' : 86400, # one day in seconds 'wd' : None, 'queue' : None, 'smt' : False, } hosts = { 'batman' : 'pbs_batman', 'c551' : 'murska', 'c552' : 'murska', 'c553' : 'murska', 'c554' : 'murska', 'louhi' : 'louhi', 'opaali.phys.jyu.fi' : 'sge', 'sepeli.csc.fi' : 'sepeli', 'bwui.bfg.uni-freiburg.de' : 'bwg', 'globus.bfg.uni-freiburg.de' : 'bwg', 'globus' : 'bwg', 'ui.bfg.uni' : 'pbs_bfg', r'xc2(.*)' : 'xc2', 'jureca' : 'jureca', 'juropatest' : 'juropatest', r'joe*' : 'joe', r'uc1n99*' : 'bwUniCluster', } platforms = { 'aix5' : 'loadleveler' } env = {'PATH' : None, 'PYTHONPATH' : None, 'GPAW_PYTHON' : None, 'GPAW_SETUP_PATH' : None, 'GPAW_MAIL' : None, 'LD_LIBRARY_PATH' : None, } set = defaults #...................................................... # functions def dhms(secs): """return days,hours,minutes and seconds""" dhms = [0, 0, 0, 0] dhms[0] = int(secs // 86400) s = secs % 86400 dhms[1] = int(s // 3600) s = secs % 3600 dhms[2] = int(s // 60) s = secs % 60 dhms[3] = int(s+.5) return dhms def hms(secs): """return hours,minutes and seconds""" hms = [0,0,0] hms[0] = int(secs // 3600) s = secs % 3600 hms[1] = int(s // 60) s = secs % 60 hms[2] = int(s+.5) return hms def hms_string(secs): """return hours,minutes and seconds string, e.g. 02:00:45""" l = hms(secs) def extend10(n): if n<10: return '0' + str(n) else: return str(n) return extend10(l[0]) + ':' + extend10(l[1]) + ':' + extend10(l[2]) def s_from_dhms(time): """return seconds from dhms""" dhms_s = { 's' : 1, 'm' : 60, 'h' : 3600, 'd' : 86400 } time = time.lower() word_list = re.findall('\d*[^\d]*',time) seconds=0 for word in word_list: if word != '': sec = 1 for t in dhms_s.keys(): nw = word.replace(t,'') if nw != word: sec = dhms_s[t] word = nw break try: seconds += int(word) * sec except: raise RuntimeError, 'unknown format in timestring ' + time return seconds def minutes(secs): return int(secs // 60) def list_systems(obj): print "Allowed names are:" p = re.compile('__') for host in dir(obj): if not p.match(host): print '', host def unique_name(name): import string letters = list(string.letters) n = name while os.path.exists(n): n = name + letters.pop(0) return n class RunScript: def __init__(self, set, env, name=None): if not hasattr(self,set['arch']): print "unkown system >" + set['arch'] + "<" list_systems(self) sys.exit() if name is None: name = 'run.' + set['arch'] if set['arch'] == 'xc2': name = unique_name(name) self.name = name f = open(name, 'w') call = "self." + set['arch'] + "(f,set,env)" eval(call) if not f.closed: f.close() print name, 'written' def loadleveler(self, f, set, env): print >> f,"#!/bin/bash" if set['cores'] > 1: print >> f, "# @ job_type=parallel" else: print >> f, "# @ job_type=serial" # ibm nodes contain 32 cpus nodes = int(set['cores'] / 32) if nodes == 0: print >> f, '# @ node = 1' else: if nodes * 32 != int(set['cores']): raise RuntimeError("! use a multiple of 32 cpus !") print >> f, '# @ node =', nodes print >> f, '# @ total_tasks =', set['cores'] print >> f, '# @ wall_clock_limit =', hms_string(set['time']) ## print >> f, "#PBS -N", set['name'] print >> f, '# @ output = ', (set['out'] + '.$(jobid).$(stepid)') print >> f, '# @ error = ', (set['err'] + '.$(jobid).$(stepid)') if set['mail'] is not None: print >> f, '# @ notify_user =', set['mail'] print >> f, '# @ queue' print >> f print >> f, "export GPAW_SETUP_PATH=" + str(env['GPAW_SETUP_PATH']) print >> f, "export PYTHONPATH=$PYTHONPATH:"+env['PYTHONPATH'] print >> f, "export GPAW_PYTHON=" + str(env['GPAW_PYTHON']) print >> f print >> f, 'cd', set['wd'] print >> f, 'poe $GPAW_PYTHON', set['script'] def louhi(self,f,set,env): size = set['cores'] print >> f, '#!/bin/csh' # louhi PBS does not like names longer than 16 characters print >> f, '#PBS -N', set['name'][:15] print >> f, '#PBS -l mppwidth=%d' % size hs = dhms(set['time']) print >> f, '#PBS -l walltime=' + ( str(24 * hs[0] + hs[1]) + ':' + str(hs[2]) + ':' + str(hs[3]) ) if set['mem']: print >> f, '#PBS -l mppmem=1900M' if set['mail'] is not None: print >> f, '#PBS -m be' print >> f, '#PBS -M', set['mail'] print >> f print >> f, 'module load python' print >> f, 'module load acml' print >> f, 'setenv MPICH_PTL_UNEX_EVENTS 60000' print >> f, 'setenv MPICH_UNEX_BUFFER_SIZE 400M' print >> f, 'setenv GPAW_SETUP_PATH', env['GPAW_SETUP_PATH'] print >> f, 'setenv PYTHONPATH ${PYTHONPATH}:' + env['PYTHONPATH'] print >> f, 'setenv GPAW_PYTHON', env['GPAW_PYTHON'] print >> f print >> f, 'cd', set['wd'] print >> f, 'aprun -n %d' % size, if set['mem']: print >> f, '-m 1900M', print >> f, '$GPAW_PYTHON', set['script'] def louhi_deisa(self,f,set,env): size = set['cores'] print >> f,"#!/bin/csh" print >> f,"#PBS -N",set['name'] print >> f,"#PBS -l mppwidth=%d" % size hs = dhms(set['time']) print >> f,'#PBS -l walltime=' + ( str(24 * hs[0] + hs[1]) + ':' + str(hs[2]) + ':' + str(hs[3]) ) if set['mem']: print >> f, '#PBS -l mppmem=1900M' if set['mail'] is not None: print >> f,"#PBS -M",set['mail'] print >> f print >> f, 'source /opt/deisa/modules/ch_modules.csh' print >> f, 'module load python' print >> f, 'module load acml' print >> f, 'setenv MPICH_PTL_UNEX_EVENTS 60000' print >> f, 'setenv MPICH_UNEX_BUFFER_SIZE 400M' print >> f, 'setenv GPAW_SETUP_PATH', env['GPAW_SETUP_PATH'] print >> f, 'setenv PYTHONPATH ${PYTHONPATH}:' + env['PYTHONPATH'] print >> f, 'setenv GPAW_PYTHON', env['GPAW_PYTHON'] print >> f print >> f, 'cd', set['wd'] print >> f, 'aprun -n %d' % size, if set['mem']: print >> f, '-m 1900M', print >> f, '$GPAW_PYTHON', set['script'] def louhi_pre(self, f, set, env): size = set['cores'] print >> f,"#!/bin/csh" print >> f,"#PBS -N",set['name'] print >> f,"#PBS -l mppwidth=%d" % size hs = dhms(set['time']) print >> f,'#PBS -l walltime=' + ( str(24 * hs[0] + hs[1]) + ':' + str(hs[2]) + ':' + str(hs[3]) ) if set['mem']: print >> f, '#PBS -l mppmem=1900M' print >> f, 'module load python' print >> f, 'module load ASE/3.0' print >> f, 'module load gpaw' print >> f, 'cd', set['wd'] print >> f, 'aprun -n %d' % size, if set['mem']: print >> f, '-m 1900M', print >> f, '$GPAW_PYTHON', set['script'] def murska(self, f, set, env): print >> f, '#!/bin/csh' print >> f, '#BSUB -n%d' % set['cores'] hs = dhms(set['time']) print >> f, '#BSUB -W %d:%d' % (hs[0]*24+hs[1],hs[2]) print >> f, '#BSUB -J', set['name'] if set['mail'] is not None: print >> f, '#BSUB -N' print >> f, '#BSUB -u', set['mail'] print >> f, '#BSUB -e ', set['err'] + '_%J' print >> f, '#BSUB -o ', set['out'] + '_%J' if set['mem']: print >> f, '#BSUB -ext "SLURM[constraint=mediummem|bigmem]"' print >> f,"module load ASE" print >> f,"setenv GPAW_SETUP_PATH",env['GPAW_SETUP_PATH'] print >> f,"setenv PYTHONPATH ${PYTHONPATH}:"+env['PYTHONPATH'] print >> f,"setenv GPAW_PYTHON",env['GPAW_PYTHON'] print >> f,"mpirun -srun $GPAW_PYTHON",set['script'] def murska_pre(self, f, set, env): """Pre-installed version on murska.""" print >> f,"#!/bin/csh" print >> f,"#BSUB -n%d" % set['cores'] hs = dhms(set['time']) print >> f,"#BSUB -W %d:%d" % (hs[0]*24+hs[1],hs[2]) print >> f,"#BSUB -J",set['name'] if set['mail'] is not None: print >> f,"#BSUB -u",set['mail'] print >> f,"#BSUB -e ",set['err']+'_%J' print >> f,"#BSUB -o ",set['out']+'_%J' if set['mem']: print >> f, '#BSUB -ext "SLURM[constraint=mediummem|bigmem]"' print >> f, 'module load ASE' print >> f, 'module load ASE/3.0' print >> f, 'module load gpaw' print >> f,"mpirun -srun $GPAW_PYTHON",set['script'] def pbs_batman(self, f, set, env): print >> f,"#PBS -N "+set['name'] print >> f,"#PBS -l ncpus="+str(set['cores']) print >> f,"#PBS -l walltime="""+str(set['time']) print >> f,"#PBS -m bea" if set['mail'] is not None: print >> f,"#PBS -M",set['mail'] print >> f,"#PBS -o", set['out']+'_$PBS_JOBID' print >> f,"#PBS -e", set['err']+'_$PBS_JOBID' print >> f,""" # change to the directory where you submitted the job cd""", set['wd'] print >> f,"echo \"vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\"" print >> f,"echo \"Current working directory is `pwd`\"" print >> f,"echo \"Running on `hostname`\"" print >> f,"export PYTHONPATH=$PYTHONPATH:" + env['PYTHONPATH'] print >> f,""" # we need to use openmpi instead of SGI's MPI library export LD_LIBRARY_PATH=/cxfs/sandbox/funano/openmpi/lib:$LD_LIBRARY_PATH export PATH=/cxfs/sandbox/funano/openmpi/bin:$PATH #include the full path to the name of your MPI program . /usr/share/modules/init/bash module add mkl unset CC CFLAGS LDFLAGS # With the upgrade of the queue system, one problem arised and this # requires everyone to add one line in the run scripts: # unset PBS_NODEFILE """ print >> f,"date" print >> f,"export GPAW_PYTHON=~/gridpaw/build/bin.linux-ia64-2.4/gpaw-python" print >> f,"mpirun -np", set['cores'], "$GPAW_PYTHON", set['script'] print >> f, 'date' print >> f, 'echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"' print >> f, 'exit 0' def pbs_bfg(self, f, set, env): print >> f, '#!/bin/bash' print >> f, '#PBS -N '+set['name'] # bfg nodes contain 8 cores cores = set['cores'] nodes = int((cores + 7) / 8) ppn = int((cores + nodes - 1) / nodes) if cores != nodes * ppn: print 'Note:', nodes * ppn, 'cores reserved but only', cores, 'cores used.' print ' Consider to use multiples of 8 processors for best performance.' print >> f, '#PBS -l nodes=' + str(nodes) + ':ppn=' + str(ppn) print >> f, '#PBS -l cput=' + hms_string(set['time']) print >> f, '#PBS -l walltime=' + hms_string(set['time']) print >> f, '#PBS -m bea' if set['mail'] is not None: print >> f, '#PBS -M',set['mail'] print >> f, 'export PATH=/usr/lib/openmpi/1.2.5-gcc/bin:$PATH' print >> f, 'cd', set['wd'] print >> f, 'export PYTHONPATH=$PYTHONPATH:' + env['PYTHONPATH'] print >> f, 'export GPAW_SETUP_PATH='+env['GPAW_SETUP_PATH'] print >> f, 'export GPAW_PYTHON='+env['GPAW_PYTHON'] print >> f, 'mpirun -np', cores, '$GPAW_PYTHON', set['script'], print >> f, '>', set['out']+'_$PBS_JOBID', print >> f, '2>', set['err']+'_$PBS_JOBID' def bwg(self, f, set, env): modules_to_load = [ 'devel/python/2.7.2', 'compiler/intel/12.0', 'mpi/impi/4.0.2-intel-12.0', 'numlib/mkl/10.3.5', 'numlib/python_numpy/1.6.1-python-2.7.2', ] print >> f, '#!/bin/bash' print >> f, '#PBS -N '+set['name'] # bwg nodes contain 8 cores cores = set['cores'] nodes = int((cores + 7) / 8) ppn = int((cores + nodes - 1) / nodes) if cores != nodes * ppn: print 'Note:', nodes * ppn, 'cores reserved but only', cores, 'cores used.' print ' Consider to use multiples of 8 processors for best performance.' print >> f, '#PBS -l nodes=' + str(nodes) + ':ppn=' + str(ppn) print >> f, '#PBS -l walltime=' + hms_string(set['time']) print >> f, '#PBS -m bea' if set['mail'] is not None: print >> f, '#PBS -M', set['mail'] for module in modules_to_load: print >> f, 'module load ' + module print >> f, 'cd', set['wd'] print >> f, 'export PYTHONPATH=$PYTHONPATH:' + env['PYTHONPATH'] print >> f, 'export GPAW_SETUP_PATH='+env['GPAW_SETUP_PATH'] print >> f, 'export GPAW_PYTHON='+env['GPAW_PYTHON'] try: LD_LIBRARY_PATH = os.environ['LD_LIBRARY_PATH'] + ':' except: LD_LIBRARY_PATH = '' print >> f, ('export LD_LIBRARY_PATH=' + LD_LIBRARY_PATH + '$LD_LIBRARY_PATH') print >> f, 'mpirun -np', cores, '$GPAW_PYTHON', set['script'], if 'parameters' in set: print >> f, set['parameters'], print >> f, '>', set['out']+'_$PBS_JOBID', print >> f, '2>', set['err']+'_$PBS_JOBID' def joe(self, f, set, env): queue_pe_cores = { # queue pe min.cores 'short' : ['openmpi_64', 64], 'medium': ['openmpi_8', 8], 'long' : ['openmpi', 1], } modules_to_load = [] print >> f, '#!/bin/bash' print >> f, '#$ -N ' + set['name'] print >> f, '#$ -cwd' print >> f, '#$ -S /bin/bash' print >> f, '#$ -j y # join stdout and stderr' print >> f, '#$ -o', set['out'] + '_$JOB_ID' cores = set['cores'] pe = 'openmpi' if set['queue']: queue = set['queue'] if queue in queue_pe_cores: pe, nodesize = queue_pe_cores[queue] qcores = (cores // nodesize) * nodesize if cores > qcores: qcores += nodesize print 'allocating', qcores, print 'cores in queue', queue else: queue = None qcores = cores print >> f, '#$ -pe', pe, qcores if queue: print >> f, '#$ -q', queue print >> f, '#$ -l h_rt=' + hms_string(set['time']) if set['mail'] is not None: print >> f, '#$ -M',set['mail'] print >> f print >> f, 'cd', set['wd'] print >> f print >> f, 'export OMP_NUM_THREADS="1"' print >> f, 'export PATH=$PATH:' + env['PATH'] print >> f, 'export PYTHONPATH=$PYTHONPATH:' + env['PYTHONPATH'] print >> f, 'export GPAW_SETUP_PATH='+env['GPAW_SETUP_PATH'] print >> f, 'export GPAW_PYTHON='+env['GPAW_PYTHON'] try: LD_LIBRARY_PATH = os.environ['LD_LIBRARY_PATH'] + ':' except: LD_LIBRARY_PATH = '' print >> f, ('export LD_LIBRARY_PATH=' + LD_LIBRARY_PATH + '$LD_LIBRARY_PATH') print >> f print >> f, 'mpirun -np', cores, '$GPAW_PYTHON', set['script'], if 'parameters' in set: print >> f, set['parameters'], def juropa(self, f, set, env): print >> f, '#!/bin/bash' print >> f, '#MSUB -N '+set['name'] # nodes contain 8 cores cores = set['cores'] cores_per_node = 8 if set['smt']: cores_per_node = 16 nodes = int((cores + (cores_per_node - 1)) / cores_per_node) ppn = int((cores + nodes - 1) / nodes) if cores != nodes * ppn: print 'Note:', nodes * ppn, 'cores reserved but only', cores, 'core\ s used.' print ' Consider to use multiples of 8 processors for best perf\ ormance.' print >> f, '#MSUB -l nodes=' + str(nodes) + ':ppn=' + str(ppn) print >> f, '#MSUB -l cput=' + hms_string(set['time']) print >> f, '#MSUB -l walltime=' + hms_string(set['time']) print >> f, '#MSUB -m bea' if set['mail'] is not None: print >> f, '#MSUB -M', set['mail'] # print >> f, 'export PATH=/usr/lib/openmpi/1.2.5-gcc/bin:$PATH' print >> f, 'cd', set['wd'] print >> f, ('export LD_LIBRARY_PATH=' + env['LD_LIBRARY_PATH'] + ':$LD_LIBRARY_PATH') print >> f, 'export PYTHONPATH=' + env['PYTHONPATH'] + ':$PYTHONPATH' print >> f, 'export GPAW_SETUP_PATH=' + env['GPAW_SETUP_PATH'] print >> f, 'export GPAW_PYTHON=' + env['GPAW_PYTHON'] print >> f, 'export PSP_ONDEMAND=1' print >> f, 'mpiexec -np', cores, '-x', print >> f, '$GPAW_PYTHON', set['script'], if 'parameters' in set: print >> f, set['parameters'], print >> f, '>', set['out']+'_$PBS_JOBID', print >> f, '2>', set['err']+'_$PBS_JOBID' def juropatest(self, f, set, env): print >> f, '#!/bin/bash -x' print >> f, '#SBATCH --job-name=' + set['name'].replace('+', '') # nodes contain 14 cores cores = set['cores'] cores_per_node = 28 if set['smt']: cores_per_node = 28 nodes = int((cores + (cores_per_node - 1)) / cores_per_node) ppn = int((cores + nodes - 1) / nodes) if cores != nodes * ppn: print 'Note:', nodes * ppn, 'cores reserved but only', cores, 'core\ s used.' print ' Consider to use multiples of', cores_per_node, print 'processors for best performance.' print >> f, '#SBATCH --nodes=' + str(nodes) print >> f, '#SBATCH --ntasks-per-node=' + str(ppn) print >> f, '#SBATCH --time=' + hms_string(set['time']) if set['mail'] is not None: print >> f, '#SBATCH --mail-user=' + set['mail'] print >> f, '#SBATCH --mail-type=ALL' print >> f, 'cd', set['wd'] print >> f, ('export LD_LIBRARY_PATH=' + env['LD_LIBRARY_PATH'] + ':$LD_LIBRARY_PATH') print >> f, 'export PYTHONPATH=' + env['PYTHONPATH'] + ':$PYTHONPATH' print >> f, 'export GPAW_SETUP_PATH=' + env['GPAW_SETUP_PATH'] print >> f, 'export GPAW_PYTHON=' + env['GPAW_PYTHON'] print >> f, 'srun $GPAW_PYTHON', set['script'], if 'parameters' in set: print >> f, set['parameters'], print >> f, '>', set['out']+'_$SLURM_JOBID', print >> f, '2>', set['err']+'_$SLURM_JOBID' def jureca(self, f, set, env): print >> f, '#!/bin/bash -x' print >> f, '#SBATCH --job-name=' + set['name'].replace('+', '') # nodes contain 2x12 cores cores = set['cores'] cores_per_node = 24 if set['smt']: cores_per_node = 48 nodes = int((cores + (cores_per_node - 1)) / cores_per_node) ppn = int((cores + nodes - 1) / nodes) if cores != nodes * ppn: print 'Note:', nodes * ppn, 'cores reserved but only', cores, 'core\ s used.' print ' Consider to use multiples of', cores_per_node, print 'processors for best performance.' print >> f, '#SBATCH --nodes=' + str(nodes) print >> f, '#SBATCH --ntasks-per-node=' + str(ppn) print >> f, '#SBATCH --time=' + hms_string(set['time']) if set['mail'] is not None: print >> f, '#SBATCH --mail-user=' + set['mail'] print >> f, '#SBATCH --mail-type=ALL' print >> f, 'cd', set['wd'] print >> f, ('export LD_LIBRARY_PATH=' + env['LD_LIBRARY_PATH'] + ':$LD_LIBRARY_PATH') print >> f, 'export PYTHONPATH=' + env['PYTHONPATH'] + ':$PYTHONPATH' print >> f, 'export GPAW_SETUP_PATH=' + env['GPAW_SETUP_PATH'] print >> f, 'export GPAW_PYTHON=' + env['GPAW_PYTHON'] print >> f, 'srun $GPAW_PYTHON', set['script'], if 'parameters' in set: print >> f, set['parameters'], print >> f, '>', set['out']+'_$SLURM_JOBID', print >> f, '2>', set['err']+'_$SLURM_JOBID' def bwUniCluster(self, f, set, env): print >> f, '#!/bin/bash' print >> f, '#MSUB -N '+set['name'] # nodes contain 8 cores cores = set['cores'] cores_per_node = 8 if set['smt']: cores_per_node = 16 nodes = int((cores + (cores_per_node - 1)) / cores_per_node) ppn = int((cores + nodes - 1) / nodes) if cores != nodes * ppn: print 'Note:', nodes * ppn, 'cores reserved but only', cores, 'core\ s used.' print ' Consider to use multiples of 8 processors for best perf\ ormance.' print >> f, '#MSUB -l nodes=' + str(nodes) + ':ppn=' + str(ppn) print >> f, '#MSUB -l cput=' + hms_string(set['time']) print >> f, '#MSUB -l walltime=' + hms_string(set['time']) print >> f, '#MSUB -m bea' if set['mail'] is not None: print >> f, '#MSUB -M', set['mail'] print >> f, 'module load mpi' # print >> f, 'export PATH=/usr/lib/openmpi/1.2.5-gcc/bin:$PATH' print >> f, 'cd', set['wd'] print >> f, ('export LD_LIBRARY_PATH=' + env['LD_LIBRARY_PATH'] + ':$LD_LIBRARY_PATH') print >> f, 'export PYTHONPATH=' + env['PYTHONPATH'] + ':$PYTHONPATH' print >> f, 'export GPAW_SETUP_PATH=' + env['GPAW_SETUP_PATH'] print >> f, 'export GPAW_PYTHON=' + env['GPAW_PYTHON'] print >> f, 'export PSP_ONDEMAND=1' print >> f, 'mpirun -n', cores, print >> f, '$GPAW_PYTHON', set['script'], if 'parameters' in set: print >> f, set['parameters'], print >> f, '>', set['out']+'_$MOAB_JOBID', print >> f, '2>', set['err']+'_$MOAB_JOBID' def sepeli(self, f, set, env): print >> f,"#$ -N",set['name'] print >> f,"#$ -cwd" print >> f,"#$ -j y" print >> f,"#$ -pe mvapich-gnu64",set['cores'] print >> f,"#$ -S /bin/csh" print >> f,"#$ -R y" print >> f,"#$ -V" print >> f,"#$ -l h_rt=23:48:00" print >> f,"#$ -l s_rt=23:45:00" print >> f,"#$ -e",set['err']+'_$JOB_ID' print >> f,"setenv out",'"'+set['out']+'_$JOB_ID"' print >> f,""" cat $TMPDIR/machines > $out use ASE setenv GPAW_SETUP_PATH \"/mnt/nas2/wrk/walter/gridpaw/setups/generate:/mnt/nas2/wrk/walter/gridpaw/setups/gpaw-setups-0.3\" setenv PYTHONPATH \"/mnt/nas2/wrk/walter/gridpaw/trunk:/home/u2/univ2/jyy/walter/gridpaw/trunk:${PYTHONPATH}\" setenv GPAW_MPI_COMMAND \"mpirun -np 4 %(job)s &\" setenv GPAW_PYTHON /mnt/nas2/wrk/walter/gridpaw/trunk/build/bin.linux-x86_64-2.4/gpaw-python """ print >> f,"mpirun -np",set['cores'],"$GPAW_PYTHON",set['script'],\ ">> $out" def sge(self,f,set,env): print >> f,"#!/bin/bash" print >> f,"#$ -S /bin/bash" print >> f,"#$ -N",set['name'] print >> f,"#$ -cwd" print >> f,"#$ -o",set['out']+'_$JOB_ID' print >> f,"#$ -e",set['err']+'_$JOB_ID' if set['mail'] is not None: print >> f,"#$ -M", set['mail'] print >> f,"#$ -m be" print >> f,"#$ -pe mpich",set['cores'] if set['mem']: print >> f, '#$ -q new8G' print >> f,"cd",set['wd'] print >> f,""" echo \"vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\" echo \"We've got $NSLOTS processor(s) on compute nodes: \"; echo "MPICH machines file: ${TMPDIR}/machines"; echo; cat $TMPDIR/machines; echo # initialize environment . /opt/ASE/ASE.sh # source /opt/openmpi/openmpi-path64.sh # does not exist anymore export MPIHOME=/opt/openmpi/path64 export PATH=$MPIHOME/bin/:$PATH export LD_LIBRARY_PATH=$MPIHOME/lib64:$MPIHOME/lib:$LD_LIBRARY_PATH """ print >> f, 'export GPAW_SETUP_PATH='+env['GPAW_SETUP_PATH'] print >> f, 'export GPAW_PYTHON='+env['GPAW_PYTHON'] print >> f, 'export PYTHONPATH=$PYTHONPATH:'+env['PYTHONPATH'] print >> f, 'date' print >> f,"mpirun -np",set['cores'], '$GPAW_PYTHON',\ set['script'] print >> f,"""date echo \"vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\" """ def xc2(self, f, set, env): print >> f, '#!/bin/bash' print >> f, 'cd', set['wd'] print >> f, 'export PYTHONPATH=$PYTHONPATH:' + env['PYTHONPATH'] print >> f, 'export GPAW_SETUP_PATH='+env['GPAW_SETUP_PATH'] print >> f, 'export GPAW_PYTHON='+env['GPAW_PYTHON'] print >> f, 'mpirun $GPAW_PYTHON', set['script'], if 'parameters' in set: print >> f, set['parameters'] else: print >> f f.close() os.chmod(f.name, 0755) if set['cores'] > 16 or set['mem'] or minutes(set['time']) > 60: jobclass = 'p' else: jobclass = 'd' if set['mem']: mem = 5000 else: mem = 2000 msg = 'use: job_submit -t ' + str(minutes(set['time'])) +\ ' -m ' + str(mem) +' -p' + str(set['cores']) +\ ' -c ' + jobclass + ' ' + self.name if set['mail'] is not None: msg += ' -Nbc:' + str(set['mail']) print msg # ............................................................ # program # handle command line options parser = OptionParser(usage='%prog [options] [script ncores]') parser.add_option("-m", "--mail", dest='mail', help='Where to send an email about starting/ending of the job (def: read from environment variable GPAW_MAIL)') parser.add_option("-M", "--Memory", action='count', default=None, help='request large memory cores (host specific)') parser.add_option("-n", "--name", dest='name', help='Name of the job (def: name of parent directory)') parser.add_option("-d", "--depth", dest='depth', help='depth of directories for naming (def: 1)') parser.add_option("-o", "--outfile", dest='outfile', help='Name of the output file (def: script.out)') parser.add_option("-p", "--parameters", dest='parameters', help='Parameters to give to the script (def: empty)') parser.add_option("-a", "--arch", dest='arch', help='architecture (def: try to guess)') parser.add_option("-t", "--time", dest='time', help='Time (def: 86400=1140m=24h=1d=one day)') parser.add_option("-q", "--queue", dest='queue', help='queue to use (host specific)') parser.add_option("-s", "--smt", dest='smt', action='count', help='Simultaneous Multi-Threading (host specific)') opt, args = parser.parse_args() ##print "opt=",opt ##print "args=",args if opt.mail: set['mail'] = str(opt.mail) if opt.Memory is not None: set['mem'] = True if opt.name: set['name'] = str(opt.name) if opt.depth: set['depth'] = int(opt.depth) if opt.outfile: set['out'] = str(opt.outfile) if opt.parameters: set['parameters'] = str(opt.parameters) if opt.time: set['time'] = s_from_dhms(opt.time) if opt.smt: set['smt'] = True if opt.queue: set['queue'] = str(opt.queue) if len(args): set['script'] = args[0] if len(args) > 1: try: set['cores'] = int(args[1]) except ValueError: raise ValueError('Number of cores must be integer. ' + 'See gpaw-runscript -h') # ............................................................ # try to determine the system if opt.arch: set['arch']=opt.arch else: host = None if os.path.isfile('/etc/FZJ/systemname'): with open ('/etc/FZJ/systemname', "r") as f: host = f.read().strip() elif 'HOSTNAME' in os.environ.keys(): host = os.environ['HOSTNAME'] else: try: import socket host = socket.gethostname().split('-')[0] except: dummy, hostname = os.popen4('hostname -s') host = hostname.readline().split() def has_key_regexp(dictionary, expression): for key in dictionary: if re.match(key, expression): return dictionary[key] return False if has_key_regexp(hosts, host): set['arch'] = has_key_regexp(hosts, host) print 'hostname', host, 'found,', elif platforms.has_key(sys.platform): set['arch'] = platforms[sys.platform] print 'platform', sys.platform, 'found,', else: print "Host " + str(host) + " unknown, try -a option." list_systems(RunScript) sys.exit() print 'using', set['arch'] # ............................................................ # check necessary environment variables helptxt = { 'GPAW_PYTHON': 'to the parallel custom interpreter (gpaw-python)' } for variable in helptxt.keys(): if not (variable in os.environ): raise RuntimeError('Please set the environment variable ' + variable + ' ' + helptxt[variable] + ' !') # ............................................................ # get environment variables for key in env: if key in os.environ.keys(): env[key] = os.environ[key] ##print "env=",env # ............................................................ if set['mail'] is None and os.environ.has_key('GPAW_MAIL'): set['mail'] = str(os.environ['GPAW_MAIL']) parameter_ext = '' if 'parameters' in set: parameter_ext += '_' + set['parameters'].replace(' ','_') # set output files if set['out'] is None: set['out'] = set['script'] + parameter_ext + ".out" if set['err'] is None: set['err'] = set['script'] + parameter_ext + ".err" # get the name from current working directory if set['wd'] is None: set['wd'] = os.getcwd() if set['name'] is None: nl = os.getcwd().split('/')[-set['depth']:] name = nl[0] for string in nl[1:]: name += '_' + string # avoid beginning with a number if name[0].isdigit(): name = 'j' + name set['name'] = name + parameter_ext RunScript(set,env) gpaw-0.11.0.13004/tools/gpaw-mpisim0000775000175000017500000001662212553643466017010 0ustar jensjjensj00000000000000#!/usr/bin/env python import sys import numpy as np class DummyCommunicator: def __init__(self, rank, size, ranks=None): self.rank = rank self.size = size self.ranks = ranks self.txt = '' def new_communicator(self, ranks): # The process with rank i in new group is the # process with rank ranks[i] in the old group my_subcomm_rank = np.argwhere(ranks==self.rank).ravel() return DummyCommunicator(rank=my_subcomm_rank.item(), size=len(ranks), ranks=ranks) def simulate_kpt_comm(self, nspins, nibzkpts): # From gpaw/wavefunctions.py lines 76-83 rev. 3893 mynks = nspins*nibzkpts // self.size self.txt += ', mynks=%d' % mynks ks0 = self.rank * mynks kpt_u = [] for ks in range(ks0, ks0 + mynks): s, k = divmod(ks, nibzkpts) kpt_u.append('%d%s' % (k, s==0 and '^' or 'v')) self.txt += ', kpt_u=[' + ','.join(kpt_u) + ']' self.output('kpt_comm') def simulate_band_comm(self, bd): self.txt += ', mynbands=%d' % bd.mynbands self.txt += ', mybands=%s' % bd.get_band_indices() self.output('band_comm') def output(self, name='world'): if name is not 'world': name = ' ' + name.ljust(12) print '%s: rank=%d, ranks=%s' % (name, self.rank, self.ranks) + self.txt # ------------------------------------------------------------------- def simulate(world_size, parsize_c, parsize_bands, parstride_bands, nspins, nibzkpts, nbands, show_kpt=True, show_band=True, show_domain=True): # We haven't imported GPAW until now because it messes with sys.argv from gpaw import mpi print '' print 'Simulating: world.size = %d' % world_size print ' parsize_c =', parsize_c print ' parsize_bands =', parsize_bands print ' parstride_bands =', parstride_bands print ' nspins =', nspins print ' nibzkpts =', nibzkpts print ' nbands =', nbands print '' for rank in range(world_size): world = DummyCommunicator(rank, world_size) world.output() (domain_comm, kpt_comm, band_comm) = mpi.distribute_cpus(parsize_c, \ parsize_bands, nspins, nibzkpts, world) if show_kpt: kpt_comm.simulate_kpt_comm(nspins, nibzkpts) if show_band: from gpaw.band_descriptor import BandDescriptor bd = BandDescriptor(nbands, band_comm, parstride_bands) band_comm.simulate_band_comm(bd) if show_domain: domain_comm.output('domain_comm') #TODO N_c parts! # ------------------------------------------------------------------- from optparse import Option, OptionValueError def check_int3(option, opt, value): try: x,y,z = value.split(',') return (int(x), int(y), int(z),) except ValueError: raise OptionValueError('option %s: invalid int3 value: %r' \ % (opt, value)) class CustomOption(Option): TYPES = Option.TYPES + ('int3',) TYPE_CHECKER = Option.TYPE_CHECKER.copy() TYPE_CHECKER['int3'] = check_int3 if __name__ in ['__main__', '__builtin__']: from optparse import OptionParser, OptionGroup usage = '%prog [options]' version = '%prog 0.1' description = 'Simulate MPI parallelization of a GPAW calculation.' parser = OptionParser(usage=usage, version=version, description=description, option_class=CustomOption) output_options = OptionGroup(parser, 'Output-specific options') output_options.add_option('-v', '--verbose', action='store_true', \ default=None, dest='show_all', help='Simulate all communicators') output_options.add_option('-0', '--kpoint-communicators', action='store_true', \ default=False, dest='show_kpoint', help='Simulate kpoint communicators') output_options.add_option('-1', '--band-communicators', action='store_true', \ default=False, dest='show_band', help='Simulate band communicators') output_options.add_option('-2', '--domain-communicators', action='store_true', \ default=False, dest='show_domain', help='Simulate domain communicators') parser.add_option_group(output_options) mpi_options = OptionGroup(parser, 'MPI-specific options') mpi_options.add_option('-w', '--dry-run', default=0, type='int', dest='world_size', metavar='', \ help='Number of processes in parallelization [default: %default]') mpi_options.add_option('-c', '--domain-decomposition', default=None, \ type='int3', dest='parsize_c', metavar='', \ help='Domain decomposition along three axes [default: %default]') mpi_options.add_option('-b', '--state-parallelization', default=1, type='int', \ dest='parsize_bands', metavar='', \ help='Divide bands into this many blocks [default: %default]') mpi_options.add_option('-x', '--strided-bandgroups', action='store_true', \ default=None, dest='parstride_bands',\ help='Simulate strided band grouping (instead of blocked)') parser.add_option_group(mpi_options) gpaw_options = OptionGroup(parser, 'GPAW-specific options') gpaw_options.add_option('-s', '--spins', default=1, type='int', dest='nspins', \ metavar='', help='Number of spins [default: %default]') gpaw_options.add_option('-k', '--kpoints', default=1, type='int', \ dest='nibzkpts', metavar='', \ help='Number of irreducible k-points [default: %default]') gpaw_options.add_option('-n', '--bands', default=1, type='int', dest='nbands', \ metavar='', help='Number of bands [default: %default]') parser.add_option_group(gpaw_options) #parser.add_option('-g', '--grid-size', default=None, type='int3', \ # dest='N_c', metavar='', \ # help='Size of the grid along three axes [default: %default]') opts, args = parser.parse_args() if opts.show_all is not None: opts.show_kpoint = True opts.show_band = True opts.show_domain = True if not opts.world_size > 0: sys.stderr.write('ERROR: MPI world size is unspecified or invalid.\n') parser.print_help() raise SystemExit(-1) if opts.parsize_c is not None and (len(opts.parsize_c) != 3 or (np.array(opts.parsize_c)<1).any()): sys.stderr.write('ERROR: Domain decomposition is invalid.\n') parser.print_help() raise SystemExit(-1) if not opts.parsize_bands > 0: sys.stderr.write('ERROR: State-parallelization size is invalid.\n') parser.print_help() raise SystemExit(-1) if not opts.nspins in [1,2]: sys.stderr.write('ERROR: Invalid number of spins.\n') parser.print_help() raise SystemExit(-1) if not opts.nibzkpts > 0: sys.stderr.write('ERROR: Invalid number of irreducible k-points.\n') parser.print_help() raise SystemExit(-1) if not opts.nbands > 0: sys.stderr.write('ERROR: Invalid number of bands.\n') parser.print_help() raise SystemExit(-1) simulate(opts.world_size, opts.parsize_c, opts.parsize_bands, opts.parstride_bands, opts.nspins, opts.nibzkpts, opts.nbands, opts.show_kpoint, opts.show_band, opts.show_domain) gpaw-0.11.0.13004/tools/gpaw-install-setups0000775000175000017500000002201612553643466020473 0ustar jensjjensj00000000000000#!/usr/bin/env python from __future__ import print_function import os import fnmatch import urllib2 from StringIO import StringIO import tarfile from optparse import OptionParser, OptionGroup import re usage = '%prog [OPTION]\n or: %prog [OPTION] INSTALLDIR' description = ('In first form, show available setups and GPAW setup paths. ' 'In second form, download and install gpaw-setups into ' 'INSTALLDIR/[setups-package-name-and-version].') sources = [('gpaw', 'official GPAW setups releases [default]'), ('sg15', 'SG15 pseudopotentials'), ('basis', 'basis sets for LCAO mode'), ('test', 'small file for testing this script'), ] names = [r for r, d in sources] p = OptionParser(usage=usage, description=description) p.add_option('--version', metavar='VERSION', help='download VERSION of package. ' 'Run without arguments to display a list of versions. ' 'VERSION can be the full URL or a part such as ' '\'0.8\' or \'0.6.6300\'') p.add_option('--tarball', metavar='FILE', help='unpack and install from local tarball FILE ' 'instead of downloading') p.add_option('--list-all', action='store_true', help='list packages from all sources') g = OptionGroup(p, 'Sources') for name, description in sources: g.add_option('--%s' % name, action='store_const', const=name, dest='source', help=description) p.add_option_group(g) p.add_option('--register', action='store_true', help='run non-interactively and register install path in ' 'GPAW setup search paths. This is done by adding lines to ' '~/.gpaw/rc.py') p.add_option('--no-register', action='store_true', help='run non-interactively and do not register install path in ' 'GPAW setup search paths') opts, args = p.parse_args() nargs = len(args) if opts.source is None: opts.source = sources[0][0] if opts.register and opts.no_register: p.error('Conflicting options specified on whether to register ' 'setup install paths in configuration file. Try not specifying ' 'some options.') def get_urls(source): if source == 'gpaw': page = 'https://wiki.fysik.dtu.dk/gpaw/_sources/setups/setups.txt' response = urllib2.urlopen(page) pattern = 'https://wiki.fysik.dtu.dk/gpaw-files/gpaw-setups-*.tar.gz' urls = [line.strip() for line in response if fnmatch.fnmatch(line.strip(), pattern)] return urls elif source == 'sg15': page = 'http://fpmd.ucdavis.edu/qso/potentials/sg15_oncv/' response = urllib2.urlopen(page) # Extract filename from: # sg15_oncv_upf_YYYY-MM-DD.tar.gz pattern = r'>(sg15_oncv_upf_\d\d\d\d-\d\d-\d\d\.tar\.gz)' files = re.compile(pattern).findall(response.read()) files.sort(reverse=True) urls = [page + fname for fname in files] return urls elif source == 'basis': page = 'http://dcwww.camd.dtu.dk/~askhl/files/gpaw-lcao-basis-sets/' pattern = re.compile('>(gpaw-basis-.+?.tar.gz)') response = urllib2.urlopen(page) files = sorted(pattern.findall(response.read()), reverse=True) return [page + fname for fname in files] elif source == 'test': return ['http://dcwww.camd.dtu.dk/~askhl/files/gpaw-test-source/' 'gpaw-dist-test-source.tar.gz'] else: raise ValueError('Unknown source: %s' % source) # The sg15 file is a tarbomb. We will later defuse it by untarring # into a subdirectory, so we don't leave a ghastly mess on the # unsuspecting user's system. if not opts.tarball: if opts.list_all: urls = [] for source in names: urls1 = get_urls(source) urls.extend(urls1) else: urls = get_urls(opts.source) def print_urls(urls, marked=None): for url in urls: pageurl, fname = url.rsplit('/', 1) if url == marked: marking = ' [*]' else: marking = ' ' print(' %s %s' % (marking, url)) if len(urls) == 0: p.error('For some reason, no files were found. Probably this script ' 'is out of date. Please rummage around GPAW web page until ' 'solution is found. Writing e-mails to ' 'gpaw-developers@lists@listserv.fysik.dtu.dk is also likely' 'to help.') if opts.version: matching_urls = [url for url in urls if opts.version in url] if len(matching_urls) > 1: p.error('More than one setup file matches version "%s":\n' '%s' % (opts.version, '\n'.join(matching_urls))) elif len(matching_urls) == 0: p.error('\nNo setup matched the specified version "%s".\n' 'Available setups are:\n' '%s' % (opts.version, '\n'.join(urls))) assert len(matching_urls) == 1 url = matching_urls[0] else: url = urls[0] print('Available setups and pseudopotentials') print_urls(urls, url) print() def print_setups_info(): try: import gpaw except ImportError as e: p.error('Cannot import \'gpaw\'. GPAW does not appear to be ' 'installed. %s' % e) # GPAW may already have been imported, and the contents of the rc # file may have changed since then. Thus, we re-import gpaw to be # sure that everything is as it should be. reload(gpaw) npaths = len(gpaw.setup_paths) if npaths == 0: print('GPAW currently has no setup search paths') else: print('Current GPAW setup paths in order of search priority:') for i, path in enumerate(gpaw.setup_paths): print('%4d. %s' % (i + 1, path)) if nargs == 0: print_setups_info() print() progname = p.get_prog_name() print('Run %s DIR to install newest setups into DIR.' % progname) print('Run %s DIR --version=VERSION to install VERSION (from above).' % progname) print('See %s --help for more info.' % progname) raise SystemExit elif len(args) != 1: p.error('No more than one DIR expected. Please try --help.') targetpath = args[0] if opts.tarball: print('Reading local tarball %s' % opts.tarball) targzfile = tarfile.open(opts.tarball) tarfname = opts.tarball else: tarfname = url.rsplit('/', 1)[1] print('Selected %s. Downloading...' % tarfname) response = urllib2.urlopen(url) targzfile = tarfile.open(fileobj=StringIO(response.read())) if not os.path.exists(targetpath): os.makedirs(targetpath) assert tarfname.endswith('.tar.gz') setup_dirname = tarfname.rsplit('.', 2)[0] # remove .tar.gz ending setup_path = os.path.abspath(os.path.join(targetpath, setup_dirname)) if tarfname.startswith('sg15'): # Defuse tarbomb if not os.path.isdir(setup_path): os.mkdir(setup_path) targetpath = os.path.join(targetpath, setup_dirname) print('Extracting tarball into %s' % targetpath) targzfile.extractall(targetpath) assert os.path.isdir(setup_path) print('Setups installed into %s.' % setup_path) # Okay, now we have to maybe edit people's rc files. rcfiledir = os.path.join(os.environ['HOME'], '.gpaw') rcfilepath = os.path.join(rcfiledir, 'rc.py') # We could do all this by importing the rcfile as well and checking # whether things are okay or not. rcline = "setup_paths.insert(0, '%s')" % setup_path # Run interactive mode unless someone specified a flag requiring otherwise interactive_mode = not (opts.register or opts.no_register) register_path = False if interactive_mode: answer = raw_input('Register this setup path in %s? [y/n] ' % rcfilepath) if answer.lower() in ['y', 'yes']: register_path = True elif answer.lower() in ['n', 'no']: print('As you wish.') else: print('What do you mean by "%s"? Assuming "n".' % answer) else: if opts.register: assert not opts.no_register register_path = True else: assert opts.no_register if register_path: # First we create the file if not os.path.exists(rcfiledir): os.makedirs(rcfiledir) if not os.path.exists(rcfilepath): tmpfd = open(rcfilepath, 'w') # Just create empty file tmpfd.close() for line in open(rcfilepath): if line.startswith(rcline): print('It looks like the path is already registered in %s.' % rcfilepath) print('File will not be modified at this time.') break else: rcfd = open(rcfilepath, 'a') print(rcline, file=rcfd) print('Setup path registered in %s.' % rcfilepath) # Need to explicitly flush/close the file so print_setups_info # sees the change in rc.py rcfd.close() print_setups_info() else: print('You can manually register the setups by adding the') print('following line to %s:' % rcfilepath) print() print(rcline) print() print('Installation complete.') gpaw-0.11.0.13004/tools/gpaw-analyse-basis0000775000175000017500000000011012553643466020226 0ustar jensjjensj00000000000000#!/usr/bin/env python from gpaw.lcao.analyse_basis import main main() gpaw-0.11.0.13004/tools/gpaw-plot-parallel-timings0000775000175000017500000002161412553643466021727 0ustar jensjjensj00000000000000#!/usr/bin/env python from optparse import OptionParser import pylab as pl #from glob import glob p = OptionParser(usage='%prog [OPTION] FILE...', description='plot timings from gpaw parallel timer. ' 'The timer dumps a lot of files called "timings.<...>.txt". ' 'This programme plots the contents of those files. ' 'Typically one would run "%prog timings.*.txt" to plot ' 'timings on all cores. (Note: The plotting code is ' 'rather hacky and ugly at the moment.)') p.add_option('--threshold', type=float, default=0.01, metavar='FRACTION', help='suppress entries of less than FRACTION of total CPU time. ' 'Such entries are shown as black. Default: %default') p.add_option('--ignore', metavar='TIMERS', default='', help='comma-separated list of timer names to be ignored.') p.add_option('--noxcc', action='store_true', help='add "XC correction" to --ignore. XC Correction ' 'is called once for every atom in each SCF step which clutters ' 'the graph a lot.') p.add_option('--interval', metavar='TIME1:TIME2', help='plot only timings within TIME1 and TIME2 ' 'after start of calculation.') p.add_option('--unit', default='s', help='time unit. s, m or h. Default: %default.') p.add_option('--align', default='SCF-cycle', metavar='TIMER', help='align timings of all processes to first call of ' 'TIMER[=%default].') opts, fnames = p.parse_args() timeunit = {'s': 1.0, 'm': 60.0, 'h': 3600.0}[opts.unit] ignored_timers = set(opts.ignore.split(',')) if opts.noxcc: ignored_timers.add('XC Correction') fnames.sort() class Entry: def __init__(self, name, t1, parent=None, childnumber=None): self.name = name self.t1 = t1 self.parent = parent self.children = [] self.childnumber = childnumber if parent is None: self.level = -1 else: self.level = parent.level + 1 def __repr__(self): return 'Entry(name=%s, t1=%s, ...)' % (self.name, self.t1) def stop(self, t2): self.t2 = t2 self.dt = self.t2 - self.t1 def subentry(self, name, time): subentry = Entry(name, time, self, len(self.children)) self.children.append(subentry) return subentry def iterate(self): for child1 in self.children: yield child1 for child2 in child1.iterate(): yield child2 def normalize(self, start): # note: here we "magically" use the timeunit offset = start scale = 1.0 / timeunit self.transform(offset, scale) def transform(self, offset, scale): self.t1 = scale * (self.t1 - offset) self.t2 = scale * (self.t2 - offset) self.dt = self.t2 - self.t1 for child in self.children: child.transform(offset, scale) def get_first_occurrence(self, name): for child in self.iterate(): if child.name == name: return child else: raise ValueError('Entry not found: %s' % name) class EntryCollection: def __init__(self, entries): tstart = min([entry.t1 for entry in entries]) tstop = max([entry.t2 for entry in entries]) try: scf_cycle_starttimes = [entry.get_first_occurrence(opts.align).t1 for entry in entries] except ValueError: print('Warning: No "%s" entry found. Times may not ' 'be synchronized so well' % opts.align) scf_cycle_starttimes = [0] * len(entries) abs_starttimes = [entry.t1 for entry in entries] max_diff = max([scftime - starttime for scftime, starttime in zip(scf_cycle_starttimes, abs_starttimes)]) for entry in entries: assert entry.level == -1 start_time = entry.t1 sync_time = entry.t1 for child in entry.iterate(): if child.name == 'SCF-cycle': # hardcoded name! sync_time = child.t1 break entry.normalize(sync_time - max_diff) #entry.normalize(tstart, tstop) self.entries = entries self.totals = self.get_totals() def get_totals(self): totals = {} for entry in self.entries: for child in entry.iterate(): if child.name not in totals: totals[child.name] = 0.0 totals[child.name] += child.dt / len(self.entries) return totals def get_timings(fname): root = Entry('root', 0.0) head = root for line in open(fname): try: line = line.strip() part1, part2, action = line.rsplit(' ', 2) tokens = part1.split(' ', 3) t = float(tokens[2]) name = tokens[3] if action == 'started': head = head.subentry(name, t) else: assert action == 'stopped', action assert name == head.name head.stop(t) head = head.parent except StandardError: # guard against interrupted file I/O pass while head != root: # If file is incomplete, cut remaining timers short head.stop(t) head = head.parent #assert head == root root.t1 = root.children[0].t1 root.stop(root.children[-1].t2) return root alltimings = [] metadata = None for rank, fname in enumerate(fnames): if fname.endswith('metadata.txt'): assert metadata is None metadata = [line.strip() for line in open(fname)] else: alltimings.append(get_timings(fname)) if len(alltimings) == 0: p.error('no timings found') if metadata is None: metadata = map(str, range(len(alltimings))) entries = EntryCollection(alltimings) ordered_names = [] fig = pl.figure(figsize=(12, 6)) fig2 = pl.figure() ax = fig.add_subplot(111) #nameax = fig.add_subplot(122) nameax = fig2.add_subplot(111) nameax.set_yticks([]) nameax.set_xticks([]) #nameax = [fig2.add_subplot(2, 2, i + 1) for i in range(4)] styles = {} thecolors = 'bgrcmy' thehatches = ['', '//', 'O', '*', 'o', r'\\', '.', '|'] def getstyle(i): return thecolors[i % len(thecolors)], thehatches[i // len(thecolors)] if opts.interval: plotstarttime, plotendtime = map(float, opts.interval.split(':')) else: plotstarttime = 0 plotendtime = max([timing.t2 for timing in alltimings]) nstyles_used = 0 for rank, rootnode in enumerate(alltimings): for child in rootnode.iterate(): if child.name in ignored_timers: continue t1 = child.t1 t2 = child.t2 if t2 < plotstarttime: continue if plotendtime < t1: continue t1 = max(t1, plotstarttime) t2 = min(t2, plotendtime) dt = t2 - t1 if child.name not in styles: if entries.totals[child.name] < opts.threshold: #color, hatch = ('k', '') continue else: color, hatch = getstyle(nstyles_used) assert (color, hatch) not in styles.values() nstyles_used += 1 ordered_names.append(child.name) #nameax[child.level].plot([], [], # color=color, # #hatch=hatch, # marker='s', ls='', # label=child.name) assert child.name not in styles styles[child.name] = color, hatch color, hatch = styles[child.name] centerx = t1 + dt * 0.5 centery = child.level + 0.5 x = [t1, t2, t2, t1] y = [child.level, child.level, child.level + 1, child.level + 1] # hardcoded to max 5. Graphs will overlap if larger. compression = 5.0 y = [y1 / compression + rank - 0.25 for y1 in y] ax.fill(x, y, color=color, label='__nolegend__') ax.fill(x, y, color='None', hatch=hatch, edgecolor='k', alpha=0.7, label='__nolegend__') ax.set_ylabel('rank') ax.set_yticks(range(len(metadata))) ax.set_yticklabels([txt.replace('=', '') for txt in metadata]) ax.set_xlabel('time / %s' % opts.unit) ax.axis(xmin=plotstarttime, xmax=plotendtime) for i, name in enumerate(ordered_names): color, hatch = styles[name] x = [0, 0.8, 0.8, 0] y = [i, i, i + 0.8, i + .8] nameax.fill(x, y, color=color, label='__nolegend__') nameax.fill(x, y, color='None', hatch=hatch, edgecolor='k', alpha=0.7, label='__nolegend__') nameax.text(1.0, i + 0.4, name, va='center', ha='left', color='k') nameax.axis(xmin=-1, xmax=len(ordered_names)) pl.show() gpaw-0.11.0.13004/tools/gpaw-upfplot0000775000175000017500000000010312553643466017166 0ustar jensjjensj00000000000000#!/usr/bin/env python from gpaw.upf import main_plot main_plot() gpaw-0.11.0.13004/tools/gpaw0000775000175000017500000000007412553643466015506 0ustar jensjjensj00000000000000#!/usr/bin/env python from gpaw.cli.main import main main() gpaw-0.11.0.13004/PKG-INFO0000664000175000017500000000076312553644063014556 0ustar jensjjensj00000000000000Metadata-Version: 1.0 Name: gpaw Version: 0.11.0.13004 Summary: An electronic structure code based on the PAW method Home-page: http://wiki.fysik.dtu.dk/gpaw Author: GPAW-community Author-email: gpaw-developers@listserv.fysik.dtu.dk License: GPLv3+ Description: A grid-based real-space Projector Augmented Wave (PAW) method Density Functional Theory (DFT) code featuring: Flexible boundary conditions, k-points and gradient corrected exchange-correlation functionals. Platform: unix gpaw-0.11.0.13004/config.py0000664000175000017500000005153212553643470015301 0ustar jensjjensj00000000000000# Copyright (C) 2006 CSC-Scientific Computing Ltd. # Please see the accompanying LICENSE file for further information. from __future__ import print_function import os import platform import sys import re import distutils.util from distutils.sysconfig import get_config_var, get_config_vars from glob import glob from os.path import join from stat import ST_MTIME def check_packages(packages, msg, include_ase, import_numpy): """Check the python version and required extra packages If ASE is not installed, the `packages` list is extended with the ASE modules if they are found.""" if sys.version_info < (2, 3, 0, 'final', 0): raise SystemExit('Python 2.3.1 or later is required!') if import_numpy: try: import numpy except ImportError: raise SystemExit('numpy is not installed!') else: msg += ['* numpy is not installed.', ' "include_dirs" in your customize.py must point to ' '"numpy/core/include".'] if not include_ase: if import_numpy: try: import ase except ImportError: import_ase = True else: import_ase = False else: import_ase = False if include_ase or import_ase: # Find ASE directories: # include_ase works in case: # cd gpaw # top-level gpaw source directory # tar zxf ~/python-ase-3.1.0.846.tar.gz # ln -s python-ase-3.1.0.846/ase . ase_root = 'ase' if include_ase: assert os.path.isdir(ase_root), ase_root ase = [] for root, dirs, files in os.walk(ase_root): if 'CVS' in dirs: dirs.remove('CVS') if '.svn' in dirs: dirs.remove('.svn') if '__init__.py' in files: ase.append(root.replace('/', '.')) if len(ase) == 0: msg += ['* ASE is not installed! You may be able to install', " gpaw, but you can't use it without ASE!"] else: packages += ase def find_file(arg, dir, files): # looks if the first element of the list arg is contained in the list files # and if so, appends dir to to arg. To be used with the os.path.walk if arg[0] in files: arg.append(dir) def get_system_config(define_macros, undef_macros, include_dirs, libraries, library_dirs, extra_link_args, extra_compile_args, runtime_library_dirs, extra_objects, msg, import_numpy): undef_macros += ['NDEBUG'] if import_numpy: import numpy include_dirs += [numpy.get_include()] # libxc libraries += ['xc'] machine = platform.uname()[4] if machine == 'sun4u': # _ # |_ | ||\ | # _||_|| \| # extra_compile_args += ['-Kpic', '-fast'] # Suppress warning from -fast (-xarch=native): f = open('cc-test.c', 'w') f.write('int main(){}\n') f.close() stderr = os.popen3('cc cc-test.c -fast')[2].read() arch = re.findall('-xarch=(\S+)', stderr) os.remove('cc-test.c') if len(arch) > 0: extra_compile_args += ['-xarch=%s' % arch[-1]] # We need the -Bstatic before the -lsunperf and -lfsu: # http://forum.java.sun.com/thread.jspa?threadID=5072537&messageID=9265782 extra_link_args += ['-Bstatic', '-lsunperf', '-lfsu', '-Bdynamic'] cc_version = os.popen3('cc -V')[2].readline().split()[3] if cc_version > '5.6': libraries.append('mtsk') else: extra_link_args.append('-lmtsk') # define_macros.append(('NO_C99_COMPLEX', '1')) msg += ['* Using SUN high performance library'] elif sys.platform.startswith('win'): # We compile with mingw coming from pythonyx (32-bit) # on the msys command line, e.g.: # LIBRARY_PATH=/c/libxc/lib:/c/OpenBLAS/lib \ # C_INCLUDE_PATH=/c/libxc/include python setup.py build if 'LIBRARY_PATH' in os.environ: library_dirs += os.environ['LIBRARY_PATH'].split(os.path.pathsep) extra_compile_args += ['-Wall', '-std=c99'] lib = '' for ld in library_dirs: # OpenBLAS (includes Lapack) if os.path.exists(join(ld, 'libopenblas.a')): lib = 'openblas' directory = ld break if lib == 'openblas': libraries += [lib, 'gfortran'] if lib: msg += ['* Using %s library from %s' % (lib, directory)] elif sys.platform in ['aix5', 'aix6']: # # o|_ _ _ # ||_)| | | # extra_compile_args += ['-qlanglvl=stdc99'] # setting memory limit is necessary on aix5 if sys.platform == 'aix5': extra_link_args += ['-bmaxdata:0x80000000', '-bmaxstack:0x80000000'] libraries += ['f', 'lapack', 'essl'] define_macros.append(('GPAW_AIX', '1')) elif machine in ['x86_64', 'ppc64']: # _ # \/|_||_ |_ |_| # /\|_||_| _ |_| | # extra_compile_args += ['-Wall', '-std=c99'] # Look for ACML libraries: acml = glob('/opt/acml*/g*64/lib') if len(acml) > 0: library_dirs += [acml[-1]] libraries += ['acml'] if acml[-1].find('gfortran') != -1: libraries.append('gfortran') if acml[-1].find('gnu') != -1: libraries.append('g2c') extra_link_args += ['-Wl,-rpath=' + acml[-1]] msg += ['* Using ACML library'] else: atlas = False for dir in ['/usr/lib', '/usr/local/lib', '/usr/lib64/atlas']: if glob(join(dir, 'libatlas.so')) != []: atlas = True libdir = dir break satlas = False for dir in ['/usr/lib', '/usr/local/lib', '/usr/lib64/atlas']: if glob(join(dir, 'libsatlas.so')) != []: satlas = True libdir = dir break openblas = False for dir in ['/usr/lib', '/usr/local/lib', '/usr/lib64']: if glob(join(dir, 'libopenblas.so')) != []: openblas = True libdir = dir break if openblas: # prefer openblas libraries += ['openblas'] library_dirs += [libdir] msg += ['* Using OpenBLAS library'] else: if atlas: # then atlas # http://math-atlas.sourceforge.net/errata.html#LINK # atlas does not respect OMP_NUM_THREADS - build # single-thread # http://math-atlas.sourceforge.net/faq.html#tsafe libraries += ['lapack', 'f77blas', 'cblas', 'atlas'] library_dirs += [libdir] msg += ['* Using ATLAS library'] elif satlas: # then atlas >= 3.10 Fedora/RHEL libraries += ['satlas'] library_dirs += [libdir] msg += ['* Using ATLAS library'] else: libraries += ['blas', 'lapack'] msg += ['* Using standard lapack'] elif machine == 'ia64': # _ _ # |_ | o # _||_|| # extra_compile_args += ['-Wall', '-std=c99'] libraries += ['mkl', 'mkl_lapack64'] elif platform.machine().startswith('arm'): extra_compile_args += ['-Wall', '-std=c99'] atlas = False for dir in ['/usr/lib', '/usr/local/lib', '/usr/lib/atlas']: if glob(join(dir, 'libatlas.so')) != []: atlas = True libdir = dir break satlas = False for dir in ['/usr/lib', '/usr/local/lib', '/usr/lib/atlas']: if glob(join(dir, 'libsatlas.so')) != []: satlas = True libdir = dir break openblas = False for dir in ['/usr/lib', '/usr/local/lib']: if glob(join(dir, 'libopenblas.so')) != []: openblas = True libdir = dir break if openblas: # prefer openblas libraries += ['openblas'] library_dirs += [libdir] msg += ['* Using OpenBLAS library'] else: if atlas: # then atlas # http://math-atlas.sourceforge.net/errata.html#LINK # atlas does not respect OMP_NUM_THREADS - build single-thread # http://math-atlas.sourceforge.net/faq.html#tsafe libraries += ['lapack', 'f77blas', 'cblas', 'atlas'] library_dirs += [libdir] msg += ['* Using ATLAS library'] elif satlas: # then atlas >= 3.10 Fedora/RHEL libraries += ['satlas'] library_dirs += [libdir] msg += ['* Using ATLAS library'] else: libraries += ['blas', 'lapack'] msg += ['* Using standard lapack'] elif machine == 'i686': # _ # o|_ |_||_ # ||_||_||_| # extra_compile_args += ['-Wall', '-std=c99'] if 'MKL_ROOT' in os.environ: mklbasedir = [os.environ['MKL_ROOT']] else: mklbasedir = glob('/opt/intel/mkl*') libs = ['libmkl_ia32.a'] if mklbasedir != []: os.path.walk(mklbasedir[0], find_file, libs) libs.pop(0) if libs != []: libs.sort() libraries += ['mkl_lapack', 'mkl_ia32', 'guide', 'pthread', 'mkl'] library_dirs += libs msg += ['* Using MKL library: %s' % library_dirs[-1]] # extra_link_args += ['-Wl,-rpath=' + library_dirs[-1]] else: atlas = False for dir in ['/usr/lib', '/usr/local/lib', '/usr/lib/atlas']: if glob(join(dir, 'libatlas.so')) != []: atlas = True libdir = dir break satlas = False for dir in ['/usr/lib', '/usr/local/lib', '/usr/lib/atlas']: if glob(join(dir, 'libsatlas.so')) != []: satlas = True libdir = dir break openblas = False for dir in ['/usr/lib', '/usr/local/lib']: if glob(join(dir, 'libopenblas.so')) != []: openblas = True libdir = dir break if openblas: # prefer openblas libraries += ['openblas'] library_dirs += [libdir] msg += ['* Using OpenBLAS library'] else: if atlas: # then atlas # http://math-atlas.sourceforge.net/errata.html#LINK # atlas does not respect OMP_NUM_THREADS - build single-thread # http://math-atlas.sourceforge.net/faq.html#tsafe libraries += ['lapack', 'f77blas', 'cblas', 'atlas'] library_dirs += [libdir] msg += ['* Using ATLAS library'] elif satlas: # then atlas >= 3.10 Fedora/RHEL libraries += ['satlas'] library_dirs += [libdir] msg += ['* Using ATLAS library'] else: libraries += ['blas', 'lapack'] msg += ['* Using standard lapack'] # add libg2c if available g2c = False for dir in ['/usr/lib', '/usr/local/lib']: if glob(join(dir, 'libg2c.so')) != []: g2c = True break if glob(join(dir, 'libg2c.a')) != []: g2c = True break if g2c: libraries += ['g2c'] elif sys.platform == 'darwin': extra_compile_args += ['-Wall', '-std=c99'] include_dirs += ['/usr/include/malloc'] if glob('/System/Library/Frameworks/vecLib.framework') != []: extra_link_args += ['-framework vecLib'] msg += ['* Using vecLib'] else: libraries += ['blas', 'lapack'] msg += ['* Using standard lapack'] # https://listserv.fysik.dtu.dk/pipermail/gpaw-users/2012-May/001473.html p = platform.dist() if p[0].lower() in ['redhat', 'centos'] and p[1].startswith('6.'): define_macros.append(('_GNU_SOURCE', '1')) return msg def get_parallel_config(mpi_libraries, mpi_library_dirs, mpi_include_dirs, mpi_runtime_library_dirs, mpi_define_macros): globals = {} exec(open('gpaw/mpi/config.py').read(), globals) mpi = globals['get_mpi_implementation']() if mpi == '': mpicompiler = None elif mpi == 'sun': mpi_include_dirs += ['/opt/SUNWhpc/include'] mpi_libraries += ['mpi'] mpi_library_dirs += ['/opt/SUNWhpc/lib'] mpi_runtime_library_dirs += ['/opt/SUNWhpc/lib'] mpicompiler = get_config_var('CC') elif mpi == 'poe': mpicompiler = 'mpcc_r' else: # Try to use mpicc mpicompiler = 'mpicc' return mpicompiler def get_scalapack_config(define_macros): # check ScaLapack settings define_macros.append(('GPAW_WITH_SL', '1')) def get_hdf5_config(define_macros): # check ScaLapack settings define_macros.append(('GPAW_WITH_HDF5', '1')) def mtime(path, name, mtimes): """Return modification time. The modification time of a source file is returned. If one of its dependencies is newer, the mtime of that file is returned. This function fails if two include files with the same name are present in different directories.""" include = re.compile('^#\s*include "(\S+)"', re.MULTILINE) if name in mtimes: return mtimes[name] t = os.stat(os.path.join(path, name))[ST_MTIME] for name2 in include.findall(open(os.path.join(path, name)).read()): path2, name22 = os.path.split(name2) if name22 != name: t = max(t, mtime(os.path.join(path, path2), name22, mtimes)) mtimes[name] = t return t def check_dependencies(sources): # Distutils does not do deep dependencies correctly. We take care of # that here so that "python setup.py build_ext" always does the right # thing! mtimes = {} # modification times # Remove object files if any dependencies have changed: plat = distutils.util.get_platform() + '-' + sys.version[0:3] remove = False for source in sources: path, name = os.path.split(source) t = mtime(path + '/', name, mtimes) o = 'build/temp.%s/%s.o' % (plat, source[:-2]) # object file if os.path.exists(o) and t > os.stat(o)[ST_MTIME]: print('removing', o) os.remove(o) remove = True so = 'build/lib.%s/_gpaw.so' % plat if os.path.exists(so) and remove: # Remove shared object C-extension: # print 'removing', so os.remove(so) def test_configuration(): raise NotImplementedError def write_configuration(define_macros, include_dirs, libraries, library_dirs, extra_link_args, extra_compile_args, runtime_library_dirs, extra_objects, mpicompiler, mpi_libraries, mpi_library_dirs, mpi_include_dirs, mpi_runtime_library_dirs, mpi_define_macros): # Write the compilation configuration into a file try: out = open('configuration.log', 'w') except IOError as x: print(x) return print("Current configuration", file=out) print("libraries", libraries, file=out) print("library_dirs", library_dirs, file=out) print("include_dirs", include_dirs, file=out) print("define_macros", define_macros, file=out) print("extra_link_args", extra_link_args, file=out) print("extra_compile_args", extra_compile_args, file=out) print("runtime_library_dirs", runtime_library_dirs, file=out) print("extra_objects", extra_objects, file=out) if mpicompiler is not None: print(file=out) print("Parallel configuration", file=out) print("mpicompiler", mpicompiler, file=out) print("mpi_libraries", mpi_libraries, file=out) print("mpi_library_dirs", mpi_library_dirs, file=out) print("mpi_include_dirs", mpi_include_dirs, file=out) print("mpi_define_macros", mpi_define_macros, file=out) print("mpi_runtime_library_dirs", mpi_runtime_library_dirs, file=out) out.close() def build_interpreter(define_macros, include_dirs, libraries, library_dirs, extra_link_args, extra_compile_args, runtime_library_dirs, extra_objects, mpicompiler, mpilinker, mpi_libraries, mpi_library_dirs, mpi_include_dirs, mpi_runtime_library_dirs, mpi_define_macros): # Build custom interpreter which is used for parallel calculations cfgDict = get_config_vars() plat = distutils.util.get_platform() + '-' + sys.version[0:3] cfiles = glob('c/[a-zA-Z_]*.c') + ['c/bmgs/bmgs.c'] cfiles += glob('c/xc/*.c') sources = ['c/bc.c', 'c/localized_functions.c', 'c/mpi.c', 'c/_gpaw.c', 'c/operators.c', 'c/woperators.c', 'c/transformers.c', 'c/blacs.c', 'c/utilities.c', 'c/hdf5.c'] objects = ' '.join(['build/temp.%s/' % plat + x[:-1] + 'o' for x in cfiles]) if not os.path.isdir('build/bin.%s/' % plat): os.makedirs('build/bin.%s/' % plat) exefile = 'build/bin.%s/' % plat + '/gpaw-python' libraries += mpi_libraries library_dirs += mpi_library_dirs define_macros += mpi_define_macros include_dirs += mpi_include_dirs runtime_library_dirs += mpi_runtime_library_dirs define_macros.append(('PARALLEL', '1')) define_macros.append(('GPAW_INTERPRETER', '1')) macros = ' '.join(['-D%s=%s' % x for x in define_macros if x[0].strip()]) include_dirs.append(cfgDict['INCLUDEPY']) include_dirs.append(cfgDict['CONFINCLUDEPY']) includes = ' '.join(['-I' + incdir for incdir in include_dirs]) library_dirs.append(cfgDict['LIBPL']) lib_dirs = ' '.join(['-L' + lib for lib in library_dirs]) libs = ' '.join(['-l' + lib for lib in libraries if lib.strip()]) # See if there is "scalable" libpython available libpl = cfgDict['LIBPL'] if glob(libpl + '/libpython*mpi*'): libs += ' -lpython%s_mpi' % cfgDict['VERSION'] else: libs += ' -lpython%s' % cfgDict['VERSION'] libs = ' '.join([libs, cfgDict['LIBS'], cfgDict['LIBM']]) # Hack taken from distutils to determine option for runtime_libary_dirs if sys.platform[:6] == 'darwin': # MacOSX's linker doesn't understand the -R flag at all runtime_lib_option = '-L' elif sys.platform[:5] == 'hp-ux': runtime_lib_option = '+s -L' elif os.popen('mpicc --showme 2> /dev/null', 'r').read()[:3] == 'gcc': runtime_lib_option = '-Wl,-R' elif os.popen('mpicc -show 2> /dev/null', 'r').read()[:3] == 'gcc': runtime_lib_option = '-Wl,-R' else: runtime_lib_option = '-R' runtime_libs = ' '.join([runtime_lib_option + lib for lib in runtime_library_dirs]) extra_link_args.append(cfgDict['LDFLAGS']) if sys.platform in ['aix5', 'aix6']: extra_link_args.append(cfgDict['LINKFORSHARED'].replace( 'Modules', cfgDict['LIBPL'])) elif sys.platform == 'darwin': pass else: extra_link_args.append(cfgDict['LINKFORSHARED']) extra_compile_args.append('-fPIC') # Compile the parallel sources for src in sources: obj = 'build/temp.%s/' % plat + src[:-1] + 'o' cmd = ('%s %s %s %s -o %s -c %s ') % \ (mpicompiler, macros, ' '.join(extra_compile_args), includes, obj, src) print(cmd) if '--dry-run' not in sys.argv: error = os.system(cmd) if error != 0: msg = ['* compiling FAILED! Only serial version of code ' 'will work.'] break # Link the custom interpreter cmd = ('%s -o %s %s %s %s %s %s %s') % \ (mpilinker, exefile, objects, ' '.join(extra_objects), lib_dirs, libs, runtime_libs, ' '.join(extra_link_args)) msg = ['* Building a custom interpreter'] print(cmd) if '--dry-run' not in sys.argv: error = os.system(cmd) if error != 0: msg += ['* linking FAILED! Only serial version of code will ' 'work.'] return error, msg gpaw-0.11.0.13004/setup.py0000664000175000017500000002067312553643470015176 0ustar jensjjensj00000000000000#!/usr/bin/env python # Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. import os import sys import distutils import distutils.util from distutils.core import setup, Extension from glob import glob from os.path import join from config import (check_packages, get_system_config, get_parallel_config, get_scalapack_config, get_hdf5_config, check_dependencies, write_configuration, build_interpreter, get_config_vars) # Get the current version number: version_base = None try: # Write gpaw/svnversion.py and get svnversion: exec(open('gpaw/svnversion_io.py').read()) except (ValueError, TypeError): svnversion = '' exec(open('gpaw/version.py').read()) # get version_base if svnversion: version = version_base + '.' + svnversion else: version = version_base long_description = """\ A grid-based real-space Projector Augmented Wave (PAW) method Density Functional Theory (DFT) code featuring: Flexible boundary conditions, k-points and gradient corrected exchange-correlation functionals.""" msg = [' '] libraries = [] library_dirs = [] include_dirs = [] extra_link_args = [] extra_compile_args = [] runtime_library_dirs = [] extra_objects = [] define_macros = [('NPY_NO_DEPRECATED_API', 7)] undef_macros = [] mpi_libraries = [] mpi_library_dirs = [] mpi_include_dirs = [] mpi_runtime_library_dirs = [] mpi_define_macros = [] platform_id = '' packages = [] for dirname, dirnames, filenames in os.walk('gpaw'): if '__init__.py' in filenames: packages.append(dirname.replace('/', '.')) include_ase = False if '--include-ase' in sys.argv: include_ase = True sys.argv.remove('--include-ase') import_numpy = True if '--ignore-numpy' in sys.argv: import_numpy = False sys.argv.remove('--ignore-numpy') remove_default_flags = False if '--remove-default-flags' in sys.argv: remove_default_flags = True sys.argv.remove('--remove-default-flags') customize = 'customize.py' for i, arg in enumerate(sys.argv): if arg.startswith('--customize'): customize = sys.argv.pop(i).split('=')[1] break check_packages(packages, msg, include_ase, import_numpy) get_system_config(define_macros, undef_macros, include_dirs, libraries, library_dirs, extra_link_args, extra_compile_args, runtime_library_dirs, extra_objects, msg, import_numpy) mpicompiler = get_parallel_config(mpi_libraries, mpi_library_dirs, mpi_include_dirs, mpi_runtime_library_dirs, mpi_define_macros) mpilinker = mpicompiler compiler = None scalapack = False hdf5 = False # User provided customizations: exec(open(customize).read()) if platform_id != '': my_platform = distutils.util.get_platform() + '-' + platform_id def my_get_platform(): return my_platform distutils.util.get_platform = my_get_platform if compiler is not None: msg += ['* Compiling gpaw with %s' % compiler] # A hack to change the used compiler and linker: vars = get_config_vars() if remove_default_flags: for key in ['BASECFLAGS', 'CFLAGS', 'OPT', 'PY_CFLAGS', 'CCSHARED', 'CFLAGSFORSHARED', 'LINKFORSHARED', 'LIBS', 'SHLIBS']: if key in vars: value = vars[key].split() # remove all gcc flags (causing problems with other compilers) for v in list(value): value.remove(v) vars[key] = ' '.join(value) for key in ['CC', 'LDSHARED']: if key in vars: value = vars[key].split() # first argument is the compiler/linker. Replace with mpicompiler: value[0] = compiler vars[key] = ' '.join(value) custom_interpreter = False # Check the command line so that custom interpreter is build only with # 'build', 'build_ext', or 'install': if mpicompiler is not None: for cmd in ['build', 'build_ext', 'install']: if cmd in sys.argv: custom_interpreter = True break # apply ScaLapack settings if scalapack: get_scalapack_config(define_macros) msg.append('* Compiling with ScaLapack') # distutils clean does not remove the _gpaw.so library and gpaw-python # binary so do it here: plat = distutils.util.get_platform() msg += ['* Architecture: ' + plat] plat = plat + '-' + sys.version[0:3] gpawso = 'build/lib.%s/' % plat + '_gpaw.so' gpawbin = 'build/bin.%s/' % plat + 'gpaw-python' if 'clean' in sys.argv: if os.path.isfile(gpawso): print('removing ', gpawso) os.remove(gpawso) if os.path.isfile(gpawbin): print('removing ', gpawbin) os.remove(gpawbin) sources = glob('c/*.c') + ['c/bmgs/bmgs.c'] sources = sources + glob('c/xc/*.c') check_dependencies(sources) extension = Extension('_gpaw', sources, libraries=libraries, library_dirs=library_dirs, include_dirs=include_dirs, define_macros=define_macros, undef_macros=undef_macros, extra_link_args=extra_link_args, extra_compile_args=extra_compile_args, runtime_library_dirs=runtime_library_dirs, extra_objects=extra_objects) extensions = [extension] if hdf5: hdf5_sources = ['c/hdf5.c'] get_hdf5_config(define_macros) msg.append('* Compiling with HDF5') hdf5_extension = Extension('_gpaw_hdf5', hdf5_sources, libraries=libraries, library_dirs=library_dirs, include_dirs=include_dirs, define_macros=define_macros, undef_macros=undef_macros, extra_link_args=extra_link_args, extra_compile_args=extra_compile_args, runtime_library_dirs=runtime_library_dirs, extra_objects=extra_objects) extensions.append(hdf5_extension) files = ['gpaw-analyse-basis', 'gpaw-basis', 'gpaw-install-setups', 'gpaw-mpisim', 'gpaw-plot-parallel-timings', 'gpaw-runscript', 'gpaw-setup', 'gpaw-test', 'gpaw-upfplot', 'gpaw'] scripts = [join('tools', script) for script in files] write_configuration(define_macros, include_dirs, libraries, library_dirs, extra_link_args, extra_compile_args, runtime_library_dirs, extra_objects, mpicompiler, mpi_libraries, mpi_library_dirs, mpi_include_dirs, mpi_runtime_library_dirs, mpi_define_macros) description = 'An electronic structure code based on the PAW method' setup(name='gpaw', version=version, description=description, maintainer='GPAW-community', maintainer_email='gpaw-developers@listserv.fysik.dtu.dk', url='http://wiki.fysik.dtu.dk/gpaw', license='GPLv3+', platforms=['unix'], packages=packages, ext_modules=extensions, scripts=scripts, long_description=long_description) if custom_interpreter: scripts.append('build/bin.%s/' % plat + 'gpaw-python') error, par_msg = build_interpreter( define_macros, include_dirs, libraries, library_dirs, extra_link_args, extra_compile_args, runtime_library_dirs, extra_objects, mpicompiler, mpilinker, mpi_libraries, mpi_library_dirs, mpi_include_dirs, mpi_runtime_library_dirs, mpi_define_macros) msg += par_msg # install also gpaw-python if 'install' in sys.argv and error == 0: setup(name='gpaw', version=version, description=description, maintainer='GPAW-community', maintainer_email='gpaw-developers@listserv.fysik.dtu.dk', url='http://wiki.fysik.dtu.dk/gpaw', license='GPLv3+', platforms=['unix'], packages=packages, ext_modules=[extension], scripts=scripts, long_description=long_description) else: msg += ['* Only a serial version of gpaw was built!'] # Messages make sense only when building if 'build' in sys.argv or 'build_ext' in sys.argv or 'install' in sys.argv: for line in msg: print(line) gpaw-0.11.0.13004/gpaw/0000775000175000017500000000000012553644063014411 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/point_charges.py0000664000175000017500000001532112553643471017614 0ustar jensjjensj00000000000000import os.path import numpy as np from ase.atom import Atom from ase.atoms import Atoms from ase.units import Bohr import _gpaw from gpaw import debug from gpaw.external_potential import ElectrostaticPotential class PointCharges(Atoms, ElectrostaticPotential): def __init__(self, *args, **kwargs): self.pc_nc = None self.charge_n = None Atoms.__init__(self, *args, **kwargs) def charge(self): """Return the summed charge of all point charges.""" charge = 0 for pc in self: charge += pc.charge return charge def read(self, file, filetype=None): """Read point charges from a file.""" if hasattr(self, 'potential'): del(self.potential) del(self.gd) if filetype is None and isinstance(file, str): # estimate file type from name ending filetype = os.path.split(file)[-1].split('.')[-1] filetype = filetype.lower() if filetype == 'pc_info': self.read_PC_info(file) elif filetype == 'xyz': self.read_xyz(file) else: raise NotImplementedError('unknown file type "'+filetype+'"') ## print " found %d PC's" % len(self) def read_PC_info(self, file): """Read point charges from a PC_info file.""" if isinstance(file, str): f = open(file) else: f = file lines = f.readlines() L0 = lines[0].split() del lines[0] for line in lines: words = line.split() if len(words) > 3: q, x, y, z = words[:4] self.append(PointCharge(position=(float(x) * Bohr, float(y) * Bohr, float(z) * Bohr), charge=float(q) ) ) else: break def read_xyz(self, file): """Read point charges from a xyz file.""" if isinstance(file, str): f = open(file) else: f = file lines = f.readlines() L0 = lines[0].split() del lines[0:2] n = int(L0[0]) for i in range(n): words = lines[i].split() dummy, x, y, z, q = words[:5] self.append(PointCharge(position=(float(x), float(y), float(z)), charge=float(q) ) ) def get_potential(self, gd=None): """Create the Coulomb potential on the grid.""" if hasattr(self, 'potential'): if gd == self.gd or gd is None: # nothing changed return self.potential if gd is None: gd = self.gd assert gd.orthogonal potential = gd.empty() n = len(self) pc_nc = np.empty((n, 3)) charge_n = np.empty((n)) for a, pc in enumerate(self): pc_nc[a] = pc.position / Bohr charge_n[a] = pc.charge self.pc_nc = pc_nc self.charge_n = charge_n _gpaw.pc_potential(potential, pc_nc, charge_n, gd.beg_c, gd.end_c, gd.h_cv.diagonal()) # save grid descriptor and potential for future use self.potential = potential self.gd = gd return potential def get_nuclear_energy(self, nucleus): return -1. * nucleus.setup.Z * self.get_value(spos_c = nucleus.spos_c) def get_value(self, position=None, spos_c=None): """The potential value (as seen by an electron) at a certain grid point. position [Angstrom] spos_c scaled position on the grid""" if position is None: vr = np.dot(spos_c, self.gd.h_cv * self.gd.N_c) else: vr = position / Bohr if debug: v = 0 for pc in self: # use c function XXXXX d = np.sqrt(np.sum((vr - pc.position / Bohr)**2)) v -= pc.charge / d else: if self.pc_nc is None or self.charge_n is None: n = len(self) pc_nc = np.empty((n, 3)) charge_n = np.empty((n)) for a, pc in enumerate(self): pc_nc[a] = pc.position / Bohr charge_n[a] = pc.charge self.pc_nc = pc_nc self.charge_n = charge_n v = _gpaw.pc_potential_value(vr, self.pc_nc, self.charge_n) return v def get_taylor(self, position=None, spos_c=None): """Get the Taylor expansion around a point position [Angstrom] output [Hartree, Hartree/Bohr] """ if position is None: gd = self.gd pos = np.dot(spos_c, gd.h_cv * gd.N_c) * Bohr else: pos = position vr = pos / Bohr nabla = np.zeros((3)) for pc in self: dist = vr - pc.position / Bohr d2 = np.sum(dist**2) nabla += dist * ( pc.charge / (d2 * np.sqrt(d2)) ) # see spherical_harmonics.py for the assignment return [[self.get_value(position=pos)], np.array([nabla[1], nabla[2], nabla[0]])] def write(self, file='PC.xyz', filetype=None): if filetype is None and isinstance(file, str): # estimate file type from name ending filetype = os.path.split(file)[-1].split('.')[-1] filetype = filetype.lower() if filetype == 'xyz': self.write_xyz(file) else: raise NotImplementedError('unknown file type "'+filetype+'"') ## print " found %d PC's" % len(self) def write_xyz(self, file='PC.xyz'): if isinstance(file, str): f = open(file, 'w') else: f = file f.write('%d\nPoint charges\n' % len(self)) for pc in self: (x, y, z) = pc.position q = pc.charge f.write('PC %12.6g %12.6g %12.6g %12.6g\n' % (x, y, z, q)) f.close() def __eq__(self, other): """ ASE atoms object does not compare charges. Hence, when calling GPAW.set(external=...) two identical PointCharge object with different charges won't trigger a reinitialization of the Hamiltionian object. """ try: return Atoms.__eq__(self, other) and \ np.all(self.get_charges() == other.get_charges()) except: return NotImplemented class PointCharge(Atom): def __init__(self, position, charge): Atom.__init__(self, position=position, charge=charge) gpaw-0.11.0.13004/gpaw/wavefunctions/0000775000175000017500000000000012553644063017304 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/wavefunctions/pw.py0000664000175000017500000013375512553643470020323 0ustar jensjjensj00000000000000# -*- coding: utf-8 -*- from __future__ import print_function, division import functools import numbers from math import pi from math import factorial as fac import numpy as np import ase.units as units from ase.utils.timing import timer import gpaw.fftw as fftw from gpaw.band_descriptor import BandDescriptor from gpaw.blacs import BlacsGrid, BlacsDescriptor, Redistributor from gpaw.density import Density from gpaw.hs_operators import MatrixOperator from gpaw.lfc import BaseLFC from gpaw.lcao.overlap import fbt from gpaw.hamiltonian import Hamiltonian from gpaw.matrix_descriptor import MatrixDescriptor from gpaw.spherical_harmonics import Y, nablarlYL from gpaw.spline import Spline from gpaw.utilities import unpack from gpaw.utilities.blas import rk, r2k, gemv, gemm, axpy from gpaw.utilities.progressbar import ProgressBar from gpaw.wavefunctions.fdpw import FDPWWaveFunctions class PW: name = 'pw' def __init__(self, ecut=340, fftwflags=fftw.ESTIMATE, cell=None): """Plane-wave basis mode. ecut: float Plane-wave cutoff in eV. fftwflags: int Flags for making FFTW plan (default is ESTIMATE). cell: 3x3 ndarray Use this unit cell to chose the planewaves.""" self.ecut = ecut / units.Hartree self.fftwflags = fftwflags if cell is None: self.cell_cv = None else: self.cell_cv = cell / units.Bohr def __call__(self, diagksl, orthoksl, initksl, gd, *args): if self.cell_cv is None: ecut = self.ecut else: volume = abs(np.linalg.det(gd.cell_cv)) volume0 = abs(np.linalg.det(self.cell_cv)) ecut = self.ecut * (volume0 / volume)**(2 / 3.0) wfs = PWWaveFunctions(ecut, self.fftwflags, diagksl, orthoksl, initksl, gd, *args) return wfs def __eq__(self, other): return (isinstance(other, PW) and self.ecut == other.ecut) def __ne__(self, other): return not self == other class PWDescriptor: ndim = 1 # all 3d G-vectors are stored in a 1d ndarray def __init__(self, ecut, gd, dtype=None, kd=None, fftwflags=fftw.ESTIMATE): assert gd.pbc_c.all() assert gd.comm.size == 1 self.ecut = ecut self.gd = gd self.fftwflags = fftwflags N_c = gd.N_c self.comm = gd.comm assert ((gd.h_cv**2).sum(1) <= 0.5 * pi**2 / ecut).all() if dtype is None: if kd is None or kd.gamma: dtype = float else: dtype = complex self.dtype = dtype if dtype == float: Nr_c = N_c.copy() Nr_c[2] = N_c[2] // 2 + 1 i_Qc = np.indices(Nr_c).transpose((1, 2, 3, 0)) i_Qc[..., :2] += N_c[:2] // 2 i_Qc[..., :2] %= N_c[:2] i_Qc[..., :2] -= N_c[:2] // 2 self.tmp_Q = fftw.empty(Nr_c, complex) self.tmp_R = self.tmp_Q.view(float)[:, :, :N_c[2]] else: i_Qc = np.indices(N_c).transpose((1, 2, 3, 0)) i_Qc += N_c // 2 i_Qc %= N_c i_Qc -= N_c // 2 self.tmp_Q = fftw.empty(N_c, complex) self.tmp_R = self.tmp_Q self.nbytes = self.tmp_R.nbytes self.fftplan = fftw.FFTPlan(self.tmp_R, self.tmp_Q, -1, fftwflags) self.ifftplan = fftw.FFTPlan(self.tmp_Q, self.tmp_R, 1, fftwflags) # Calculate reciprocal lattice vectors: B_cv = 2.0 * pi * gd.icell_cv i_Qc.shape = (-1, 3) self.G_Qv = np.dot(i_Qc, B_cv) self.nbytes += self.G_Qv.nbytes self.kd = kd if kd is None: self.K_qv = np.zeros((1, 3)) else: self.K_qv = np.dot(kd.ibzk_qc, B_cv) # Map from vectors inside sphere to fft grid: self.Q_qG = [] self.G2_qG = [] Q_Q = np.arange(len(i_Qc), dtype=np.int32) self.ngmin = 100000000 self.ngmax = 0 for q, K_v in enumerate(self.K_qv): G2_Q = ((self.G_Qv + K_v)**2).sum(axis=1) mask_Q = (G2_Q <= 2 * ecut) if self.dtype == float: mask_Q &= ((i_Qc[:, 2] > 0) | (i_Qc[:, 1] > 0) | ((i_Qc[:, 0] >= 0) & (i_Qc[:, 1] == 0))) Q_G = Q_Q[mask_Q] self.Q_qG.append(Q_G) self.G2_qG.append(G2_Q[Q_G]) ng = len(Q_G) self.ngmin = min(ng, self.ngmin) self.ngmax = max(ng, self.ngmax) self.nbytes += Q_G.nbytes + self.G2_qG[q].nbytes if kd is not None: self.ngmin = kd.comm.min(self.ngmin) self.ngmax = kd.comm.max(self.ngmax) self.n_c = np.array([self.ngmax]) # used by hs_operators.py XXX def get_reciprocal_vectors(self, q=0, add_q=True): """ Returns reciprocal lattice vectors plus q, G + q, in xyz coordinates. """ assert q < len(self.K_qv), ('Choose a q-index belonging to ' + 'the irreducible Brillouin zone.') q_v = self.K_qv[q] if add_q: G_Gv = self.G_Qv[self.Q_qG[q]] + q_v else: G_Gv = self.G_Qv[self.Q_qG[q]] return G_Gv def __getstate__(self): return (self.ecut, self.gd, self.dtype, self.kd, self.fftwflags) def __setstate__(self, state): self.__init__(*state) def estimate_memory(self, mem): mem.subnode('Arrays', self.nbytes) def bytecount(self, dtype=float): return self.ngmax * 16 def zeros(self, x=(), dtype=None, q=-1): a_xG = self.empty(x, dtype, q) a_xG.fill(0.0) return a_xG def empty(self, x=(), dtype=None, q=-1): if dtype is not None: assert dtype == self.dtype if isinstance(x, numbers.Integral): x = (x,) if q == -1: shape = x + (self.ngmax,) else: shape = x + self.Q_qG[q].shape return np.empty(shape, complex) def fft(self, f_R, q=-1, Q_G=None): """Fast Fourier transform. Returns c(G) for G 0: return Q_G = np.empty(self.pd.ngmax, np.int32) for r in range(self.kd.comm.size): for q, ks in enumerate(self.kd.get_indices(r)): s, k = divmod(ks, self.kd.nibzkpts) ng = self.ng_k[k] if s == 1: return if r == self.kd.comm.rank: Q_G[:ng] = self.pd.Q_qG[q] if r > 0: self.kd.comm.send(Q_G, 0) if self.kd.comm.rank == 0: if r > 0: self.kd.comm.receive(Q_G, r) Q_G[ng:] = -1 writer.fill(Q_G, k) def read(self, reader, hdf5): assert reader['version'] >= 3 for kpt in self.kpt_u: if kpt.s == 0: Q_G = reader.get('PlaneWaveIndices', kpt.k) ng = self.ng_k[kpt.k] assert (Q_G[:ng] == self.pd.Q_qG[kpt.q]).all() assert (Q_G[ng:] == -1).all() assert not hdf5 if self.bd.comm.size == 1: for kpt in self.kpt_u: ng = self.ng_k[kpt.k] kpt.psit_nG = reader.get_reference('PseudoWaveFunctions', (kpt.s, kpt.k), length=ng) return for kpt in self.kpt_u: kpt.psit_nG = self.empty(self.bd.mynbands, q=kpt.q) ng = self.ng_k[kpt.k] for myn, psit_G in enumerate(kpt.psit_nG): n = self.bd.global_index(myn) psit_G[:] = reader.get('PseudoWaveFunctions', kpt.s, kpt.k, n)[..., :ng] def hs(self, ham, q=-1, s=0, md=None): npw = len(self.pd.Q_qG[q]) N = self.pd.tmp_R.size if md is None: H_GG = np.zeros((npw, npw), complex) S_GG = np.zeros((npw, npw), complex) G1 = 0 G2 = npw else: H_GG = md.zeros(dtype=complex) S_GG = md.zeros(dtype=complex) G1, G2 = next(md.my_blocks(S_GG))[:2] H_GG.ravel()[G1::npw + 1] = (0.5 * self.pd.gd.dv / N * self.pd.G2_qG[q][G1:G2]) for G in range(G1, G2): x_G = self.pd.zeros(q=q) x_G[G] = 1.0 H_GG[G - G1] += (self.pd.gd.dv / N * self.pd.fft(ham.vt_sG[s] * self.pd.ifft(x_G, q), q)) S_GG.ravel()[G1::npw + 1] = self.pd.gd.dv / N f_IG = self.pt.expand(q) nI = len(f_IG) dH_II = np.zeros((nI, nI)) dS_II = np.zeros((nI, nI)) I1 = 0 for a in self.pt.my_atom_indices: dH_ii = unpack(ham.dH_asp[a][s]) dS_ii = self.setups[a].dO_ii I2 = I1 + len(dS_ii) dH_II[I1:I2, I1:I2] = dH_ii / N**2 dS_II[I1:I2, I1:I2] = dS_ii / N**2 I1 = I2 H_GG += np.dot(f_IG.T[G1:G2].conj(), np.dot(dH_II, f_IG)) S_GG += np.dot(f_IG.T[G1:G2].conj(), np.dot(dS_II, f_IG)) return H_GG, S_GG @timer('Full diag') def diagonalize_full_hamiltonian(self, ham, atoms, occupations, txt, nbands=None, scalapack=None, expert=False): assert self.dtype == complex if nbands is None: nbands = self.pd.ngmin // self.bd.comm.size * self.bd.comm.size else: assert nbands <= self.pd.ngmin if expert: iu = nbands else: iu = None self.bd = bd = BandDescriptor(nbands, self.bd.comm) p = functools.partial(print, file=txt) p('Diagonalizing full Hamiltonian ({0} lowest bands)'.format(nbands)) p('Matrix size (min, max): {0}, {1}'.format(self.pd.ngmin, self.pd.ngmax)) mem = 3 * self.pd.ngmax**2 * 16 / bd.comm.size / 1024**2 p('Approximate memory usage per core: {0:.3f} MB'.format(mem)) if bd.comm.size > 1: if isinstance(scalapack, (list, tuple)): nprow, npcol, b = scalapack else: nprow = int(round(bd.comm.size**0.5)) while bd.comm.size % nprow != 0: nprow -= 1 npcol = bd.comm.size // nprow b = 64 p('ScaLapack grid: {0}x{1},'.format(nprow, npcol), 'block-size:', b) bg = BlacsGrid(bd.comm, bd.comm.size, 1) bg2 = BlacsGrid(bd.comm, nprow, npcol) scalapack = True else: nprow = npcol = 1 scalapack = False self.pt.set_positions(atoms.get_scaled_positions()) self.kpt_u[0].P_ani = None self.allocate_arrays_for_projections(self.pt.my_atom_indices) myslice = bd.get_slice() pb = ProgressBar(txt) nkpt = len(self.kpt_u) for u, kpt in enumerate(self.kpt_u): pb.update(u / nkpt) npw = len(self.pd.Q_qG[kpt.q]) if scalapack: mynpw = -(-npw // bd.comm.size) md = BlacsDescriptor(bg, npw, npw, mynpw, npw) md2 = BlacsDescriptor(bg2, npw, npw, b, b) else: md = md2 = MatrixDescriptor(npw, npw) with self.timer('Build H and S'): H_GG, S_GG = self.hs(ham, kpt.q, kpt.s, md) if scalapack: r = Redistributor(bd.comm, md, md2) H_GG = r.redistribute(H_GG) S_GG = r.redistribute(S_GG) psit_nG = md2.empty(dtype=complex) eps_n = np.empty(npw) with self.timer('Diagonalize'): if not scalapack: md2.general_diagonalize_dc(H_GG, S_GG, psit_nG, eps_n, iu=iu) else: md2.general_diagonalize_dc(H_GG, S_GG, psit_nG, eps_n) del H_GG, S_GG kpt.eps_n = eps_n[myslice].copy() if scalapack: md3 = BlacsDescriptor(bg, npw, npw, bd.mynbands, npw) r = Redistributor(bd.comm, md2, md3) psit_nG = r.redistribute(psit_nG) kpt.psit_nG = psit_nG[:bd.mynbands].copy() del psit_nG with self.timer('Projections'): self.pt.integrate(kpt.psit_nG, kpt.P_ani, kpt.q) kpt.f_n = None pb.finish() occupations.calculate(self) def initialize_from_lcao_coefficients(self, basis_functions, mynbands): N_c = self.gd.N_c psit_nR = self.gd.empty(mynbands, self.dtype) for kpt in self.kpt_u: if self.kd.gamma: emikr_R = 1.0 else: k_c = self.kd.ibzk_kc[kpt.k] emikr_R = np.exp(-2j * pi * np.dot(np.indices(N_c).T, k_c / N_c).T) psit_nR[:] = 0.0 basis_functions.lcao_to_grid(kpt.C_nM, psit_nR, kpt.q) kpt.C_nM = None kpt.psit_nG = self.pd.empty(self.bd.mynbands, q=kpt.q) for n in range(mynbands): kpt.psit_nG[n] = self.pd.fft(psit_nR[n] * emikr_R, kpt.q) def random_wave_functions(self, mynao): rs = np.random.RandomState(self.world.rank) for kpt in self.kpt_u: psit_nG = kpt.psit_nG[mynao:] weight_G = 1.0 / (1.0 + self.pd.G2_qG[kpt.q]) psit_nG.real = rs.uniform(-1, 1, psit_nG.shape) * weight_G psit_nG.imag = rs.uniform(-1, 1, psit_nG.shape) * weight_G def estimate_memory(self, mem): FDPWWaveFunctions.estimate_memory(self, mem) self.pd.estimate_memory(mem.subnode('PW-descriptor')) def get_kinetic_stress(self): sigma_vv = np.zeros((3, 3), dtype=complex) pd = self.pd dOmega = pd.gd.dv / pd.gd.N_c.prod() if pd.dtype == float: dOmega *= 2 K_qv = self.pd.K_qv for kpt in self.kpt_u: G_Gv = pd.get_reciprocal_vectors(q=kpt.q, add_q=False) psit2_G = 0.0 for n, f in enumerate(kpt.f_n): psit2_G += f * np.abs(kpt.psit_nG[n])**2 for alpha in range(3): Ga_G = G_Gv[:, alpha] + K_qv[kpt.q, alpha] for beta in range(3): Gb_G = G_Gv[:, beta] + K_qv[kpt.q, beta] sigma_vv[alpha, beta] += (psit2_G * Ga_G * Gb_G).sum() sigma_vv *= -dOmega self.bd.comm.sum(sigma_vv) self.kd.comm.sum(sigma_vv) return sigma_vv def ft(spline): l = spline.get_angular_momentum_number() rc = 50.0 N = 2**10 assert spline.get_cutoff() <= rc dr = rc / N r_r = np.arange(N) * dr dk = pi / 2 / rc k_q = np.arange(2 * N) * dk f_r = spline.map(r_r) * (4 * pi) f_q = fbt(l, f_r, r_r, k_q) f_q[1:] /= k_q[1:]**(2 * l + 1) f_q[0] = (np.dot(f_r, r_r**(2 + 2 * l)) * dr * 2**l * fac(l) / fac(2 * l + 1)) return Spline(l, k_q[-1], f_q) class PWLFC(BaseLFC): def __init__(self, spline_aj, pd, blocksize=5000): """Reciprocal-space plane-wave localized function collection. spline_aj: list of list of spline objects Splines. pd: PWDescriptor Plane-wave descriptor object. blocksize: int Block-size to use when looping over G-vectors. Default is to do all G-vectors in one big block.""" self.pd = pd self.spline_aj = spline_aj self.dtype = pd.dtype self.initialized = False # These will be filled in later: self.lf_aj = [] self.Y_qLG = [] if blocksize is not None: if pd.ngmax <= blocksize: # No need to block G-vectors blocksize = None self.blocksize = blocksize # These are set later in set_potitions(): self.eikR_qa = None self.my_atom_indices = None self.indices = None self.pos_av = None self.nI = None def initialize(self): if self.initialized: return cache = {} lmax = -1 # Fourier transform radial functions: for a, spline_j in enumerate(self.spline_aj): self.lf_aj.append([]) for spline in spline_j: l = spline.get_angular_momentum_number() if spline not in cache: f = ft(spline) f_qG = [] for G2_G in self.pd.G2_qG: G_G = G2_G**0.5 f_qG.append(f.map(G_G)) cache[spline] = f_qG else: f_qG = cache[spline] self.lf_aj[a].append((l, f_qG)) lmax = max(lmax, l) # Spherical harmonics: for q, K_v in enumerate(self.pd.K_qv): G_Gv = self.pd.get_reciprocal_vectors(q=q) Y_LG = np.empty(((lmax + 1)**2, len(G_Gv))) for L in range((lmax + 1)**2): Y_LG[L] = Y(L, *G_Gv.T) self.Y_qLG.append(Y_LG) self.initialized = True def estimate_memory(self, mem): splines = set() lmax = -1 for spline_j in self.spline_aj: for spline in spline_j: splines.add(spline) l = spline.get_angular_momentum_number() lmax = max(lmax, l) nbytes = ((len(splines) + (lmax + 1)**2) * sum(G2_G.nbytes for G2_G in self.pd.G2_qG)) mem.subnode('Arrays', nbytes) def get_function_count(self, a): return sum(2 * l + 1 for l, f_qG in self.lf_aj[a]) def __iter__(self): I1 = 0 for a in self.my_atom_indices: j = 0 i1 = 0 for l, f_qG in self.lf_aj[a]: i2 = i1 + 2 * l + 1 I2 = I1 + 2 * l + 1 yield a, j, i1, i2, I1, I2 i1 = i2 I1 = I2 j += 1 def set_positions(self, spos_ac): self.initialize() kd = self.pd.kd if kd is None or kd.gamma: self.eikR_qa = np.ones((1, len(spos_ac))) else: self.eikR_qa = np.exp(2j * pi * np.dot(kd.ibzk_qc, spos_ac.T)) self.pos_av = np.dot(spos_ac, self.pd.gd.cell_cv) self.my_atom_indices = np.arange(len(spos_ac)) self.indices = [] I1 = 0 for a in self.my_atom_indices: I2 = I1 + self.get_function_count(a) self.indices.append((a, I1, I2)) I1 = I2 self.nI = I1 def expand(self, q=-1, G1=0, G2=None): if G2 is None: G2 = self.Y_qLG[q].shape[1] f_IG = np.empty((self.nI, G2 - G1), complex) emiGR_Ga = np.exp(-1j * np.dot(self.pd.G_Qv[self.pd.Q_qG[q][G1:G2]], self.pos_av.T)) for a, j, i1, i2, I1, I2 in self: l, f_qG = self.lf_aj[a][j] f_IG[I1:I2] = (emiGR_Ga[:, a] * f_qG[q][G1:G2] * (-1.0j)**l * self.Y_qLG[q][l**2:(l + 1)**2, G1:G2]) return f_IG def block(self, q=-1): nG = self.Y_qLG[q].shape[1] if self.blocksize: G1 = 0 while G1 < nG: G2 = min(G1 + self.blocksize, nG) yield G1, G2 G1 = G2 else: yield 0, nG def add(self, a_xG, c_axi=1.0, q=-1, f0_IG=None): if isinstance(c_axi, float): assert q == -1, a_xG.dims == 1 a_xG += (c_axi / self.pd.gd.dv) * self.expand(-1).sum(0) return c_xI = np.empty(a_xG.shape[:-1] + (self.nI,), self.pd.dtype) for a, I1, I2 in self.indices: c_xI[..., I1:I2] = c_axi[a] * self.eikR_qa[q][a].conj() c_xI = c_xI.reshape((np.prod(c_xI.shape[:-1], dtype=int), self.nI)) a_xG = a_xG.reshape((-1, a_xG.shape[-1])).view(self.pd.dtype) for G1, G2 in self.block(q): if f0_IG is None: f_IG = self.expand(q, G1, G2) else: f_IG = f0_IG if self.pd.dtype == float: f_IG = f_IG.view(float) G1 *= 2 G2 *= 2 gemm(1.0 / self.pd.gd.dv, f_IG, c_xI, 1.0, a_xG[:, G1:G2]) def integrate(self, a_xG, c_axi=None, q=-1): c_xI = np.zeros(a_xG.shape[:-1] + (self.nI,), self.pd.dtype) b_xI = c_xI.reshape((np.prod(c_xI.shape[:-1], dtype=int), self.nI)) a_xG = a_xG.reshape((-1, a_xG.shape[-1])) alpha = 1.0 / self.pd.gd.N_c.prod() if self.pd.dtype == float: alpha *= 2 a_xG = a_xG.view(float) if c_axi is None: c_axi = self.dict(a_xG.shape[:-1]) x = 0.0 for G1, G2 in self.block(q): f_IG = self.expand(q, G1, G2) if self.pd.dtype == float: if G1 == 0: f_IG[:, 0] *= 0.5 f_IG = f_IG.view(float) G1 *= 2 G2 *= 2 gemm(alpha, f_IG, a_xG[:, G1:G2], x, b_xI, 'c') x = 1.0 for a, I1, I2 in self.indices: c_axi[a][:] = self.eikR_qa[q][a] * c_xI[..., I1:I2] return c_axi def derivative(self, a_xG, c_axiv, q=-1): c_vxI = np.zeros((3,) + a_xG.shape[:-1] + (self.nI,), self.pd.dtype) b_vxI = c_vxI.reshape((3, np.prod(c_vxI.shape[1:-1], dtype=int), self.nI)) a_xG = a_xG.reshape((-1, a_xG.shape[-1])).view(self.pd.dtype) alpha = 1.0 / self.pd.gd.N_c.prod() K_v = self.pd.K_qv[q] x = 0.0 for G1, G2 in self.block(q): f_IG = self.expand(q, G1, G2) G_Gv = self.pd.G_Qv[self.pd.Q_qG[q][G1:G2]] if self.pd.dtype == float: for v in range(3): gemm(2 * alpha, (f_IG * 1.0j * G_Gv[:, v]).view(float), a_xG[:, 2 * G1:2 * G2], x, b_vxI[v], 'c') else: for v in range(3): gemm(-alpha, f_IG * (G_Gv[:, v] + K_v[v]), a_xG[:, G1:G2], x, b_vxI[v], 'c') x = 1.0 for v in range(3): if self.pd.dtype == float: for a, I1, I2 in self.indices: c_axiv[a][..., v] = c_vxI[v, ..., I1:I2] else: for a, I1, I2 in self.indices: c_axiv[a][..., v] = (1.0j * self.eikR_qa[q][a] * c_vxI[v, ..., I1:I2]) def stress_tensor_contribution(self, a_xG, c_axi=1.0, q=-1): cache = {} for a, j, i1, i2, I1, I2 in self: spline = self.spline_aj[a][j] if spline not in cache: s = ft(spline) G_G = self.pd.G2_qG[q]**0.5 f_G = [] dfdGoG_G = [] for G in G_G: f, dfdG = s.get_value_and_derivative(G) if G < 1e-10: G = 1.0 f_G.append(f) dfdGoG_G.append(dfdG / G) f_G = np.array(f_G) dfdGoG_G = np.array(dfdGoG_G) cache[spline] = (f_G, dfdGoG_G) else: f_G, dfdGoG_G = cache[spline] if isinstance(c_axi, float): c_axi = dict((a, c_axi) for a in range(len(self.pos_av))) G0_Gv = self.pd.get_reciprocal_vectors(q=q) stress_vv = np.zeros((3, 3)) for G1, G2 in self.block(q): G_Gv = G0_Gv[G1:G2] aa_xG = a_xG[..., G1:G2] for v1 in range(3): for v2 in range(3): stress_vv[v1, v2] += self._stress_tensor_contribution( v1, v2, cache, G1, G2, G_Gv, aa_xG, c_axi, q) return stress_vv def _stress_tensor_contribution(self, v1, v2, cache, G1, G2, G_Gv, a_xG, c_axi, q): f_IG = np.empty((self.nI, G2 - G1), complex) K_v = self.pd.K_qv[q] for a, j, i1, i2, I1, I2 in self: l = self.lf_aj[a][j][0] spline = self.spline_aj[a][j] f_G, dfdGoG_G = cache[spline] emiGR_G = np.exp(-1j * np.dot(G_Gv, self.pos_av[a])) f_IG[I1:I2] = (emiGR_G * (-1.0j)**l * np.exp(1j * np.dot(K_v, self.pos_av[a])) * ( dfdGoG_G[G1:G2] * G_Gv[:, v1] * G_Gv[:, v2] * self.Y_qLG[q][l**2:(l + 1)**2, G1:G2] + f_G[G1:G2] * G_Gv[:, v1] * [nablarlYL(L, G_Gv.T)[v2] for L in range(l**2, (l + 1)**2)])) c_xI = np.zeros(a_xG.shape[:-1] + (self.nI,), self.pd.dtype) b_xI = c_xI.reshape((np.prod(c_xI.shape[:-1], dtype=int), self.nI)) a_xG = a_xG.reshape((-1, a_xG.shape[-1])) alpha = 1.0 / self.pd.gd.N_c.prod() if self.pd.dtype == float: alpha *= 2 if G1 == 0: f_IG[:, 0] *= 0.5 f_IG = f_IG.view(float) a_xG = a_xG.copy().view(float) gemm(alpha, f_IG, a_xG, 0.0, b_xI, 'c') stress = 0.0 for a, I1, I2 in self.indices: stress -= self.eikR_qa[q][a] * (c_axi[a] * c_xI[..., I1:I2]).sum() return stress.real class PseudoCoreKineticEnergyDensityLFC(PWLFC): def add(self, tauct_R): tauct_R += self.pd.ifft(1.0 / self.pd.gd.dv * self.expand(-1).sum(0)) def derivative(self, dedtaut_R, dF_aiv): PWLFC.derivative(self, self.pd.fft(dedtaut_R), dF_aiv) class ReciprocalSpaceDensity(Density): def __init__(self, gd, finegd, nspins, charge, collinear=True): Density.__init__(self, gd, finegd, nspins, charge, collinear) self.ecut2 = 0.5 * pi**2 / (self.gd.h_cv**2).sum(1).max() * 0.9999 self.pd2 = PWDescriptor(self.ecut2, self.gd) self.ecut3 = 0.5 * pi**2 / (self.finegd.h_cv**2).sum(1).max() * 0.9999 self.pd3 = PWDescriptor(self.ecut3, self.finegd) self.G3_G = self.pd2.map(self.pd3) def initialize(self, setups, timer, magmom_av, hund): Density.initialize(self, setups, timer, magmom_av, hund) spline_aj = [] for setup in setups: if setup.nct is None: spline_aj.append([]) else: spline_aj.append([setup.nct]) self.nct = PWLFC(spline_aj, self.pd2) self.ghat = PWLFC([setup.ghat_l for setup in setups], self.pd3) def set_positions(self, spos_ac, atom_partition): Density.set_positions(self, spos_ac, atom_partition) self.nct_q = self.pd2.zeros() self.nct.add(self.nct_q, 1.0 / self.nspins) self.nct_G = self.pd2.ifft(self.nct_q) def interpolate_pseudo_density(self, comp_charge=None): """Interpolate pseudo density to fine grid.""" if comp_charge is None: comp_charge = self.calculate_multipole_moments() if self.nt_sg is None: self.nt_sg = self.finegd.empty(self.nspins * self.ncomp**2) self.nt_sQ = self.pd2.empty(self.nspins * self.ncomp**2) for nt_G, nt_Q, nt_g in zip(self.nt_sG, self.nt_sQ, self.nt_sg): nt_g[:], nt_Q[:] = self.pd2.interpolate(nt_G, self.pd3) def interpolate(self, in_xR, out_xR=None): """Interpolate array(s).""" if out_xR is None: out_xR = self.finegd.empty(in_xR.shape[:-3]) a_xR = in_xR.reshape((-1,) + in_xR.shape[-3:]) b_xR = out_xR.reshape((-1,) + out_xR.shape[-3:]) for in_R, out_R in zip(a_xR, b_xR): out_R[:] = self.pd2.interpolate(in_R, self.pd3)[0] return out_xR def calculate_pseudo_charge(self): self.nt_Q = self.nt_sQ[:self.nspins].sum(axis=0) self.rhot_q = self.pd3.zeros() self.rhot_q[self.G3_G] = self.nt_Q * 8 self.ghat.add(self.rhot_q, self.Q_aL) self.rhot_q[0] = 0.0 def get_pseudo_core_kinetic_energy_density_lfc(self): return PseudoCoreKineticEnergyDensityLFC( [[setup.tauct] for setup in self.setups], self.pd2) def calculate_dipole_moment(self): if np.__version__ < '1.6.0': raise NotImplementedError pd = self.pd3 N_c = pd.tmp_Q.shape m0_q, m1_q, m2_q = [i_G == 0 for i_G in np.unravel_index(pd.Q_qG[0], N_c)] rhot_q = self.rhot_q.imag rhot_cs = [rhot_q[m1_q & m2_q], rhot_q[m0_q & m2_q], rhot_q[m0_q & m1_q]] d_c = [np.dot(rhot_s[1:], 1.0 / np.arange(1, len(rhot_s))) for rhot_s in rhot_cs] return -np.dot(d_c, pd.gd.cell_cv) / pi * pd.gd.dv class ReciprocalSpaceHamiltonian(Hamiltonian): def __init__(self, gd, finegd, pd2, pd3, nspins, setups, timer, xc, world, kptband_comm, vext=None, collinear=True): Hamiltonian.__init__(self, gd, finegd, nspins, setups, timer, xc, world, kptband_comm, vext, collinear) self.vbar = PWLFC([[setup.vbar] for setup in setups], pd2) self.pd2 = pd2 self.pd3 = pd3 class PS: def initialize(self): pass def get_stencil(self): return '????' def estimate_memory(self, mem): pass self.poisson = PS() self.npoisson = 0 def summary(self, fd): Hamiltonian.summary(self, fd) fd.write('Interpolation: FFT\n') fd.write('Poisson solver: FFT\n') def set_positions(self, spos_ac, atom_partition): Hamiltonian.set_positions(self, spos_ac, atom_partition) self.vbar_Q = self.pd2.zeros() self.vbar.add(self.vbar_Q) def update_pseudo_potential(self, density): self.ebar = self.pd2.integrate(self.vbar_Q, density.nt_sQ.sum(0)) self.timer.start('Poisson') self.vHt_q = 4 * pi * density.rhot_q self.vHt_q[1:] /= self.pd3.G2_qG[0][1:] self.epot = 0.5 * self.pd3.integrate(self.vHt_q, density.rhot_q) self.timer.stop('Poisson') self.vt_Q = self.vbar_Q + self.vHt_q[density.G3_G] / 8 self.vt_sG[:] = self.pd2.ifft(self.vt_Q) self.timer.start('XC 3D grid') vxct_sg = self.finegd.zeros(self.nspins) self.exc = self.xc.calculate(self.finegd, density.nt_sg, vxct_sg) for vt_G, vxct_g in zip(self.vt_sG, vxct_sg): vxc_G, vxc_Q = self.pd3.restrict(vxct_g, self.pd2) vt_G += vxc_G self.vt_Q += vxc_Q / self.nspins self.timer.stop('XC 3D grid') eext = 0.0 return self.epot, self.ebar, eext, self.exc def calculate_atomic_hamiltonians(self, density): W_aL = {} for a in density.D_asp: W_aL[a] = np.empty((self.setups[a].lmax + 1)**2) density.ghat.integrate(self.vHt_q, W_aL) return W_aL def calculate_kinetic_energy(self, density): ekin = 0.0 for vt_G, nt_G in zip(self.vt_sG, density.nt_sG): ekin -= self.gd.integrate(vt_G, nt_G) ekin += self.gd.integrate(self.vt_sG, density.nct_G).sum() return ekin def restrict(self, in_xR, out_xR=None): """Restrict array.""" if out_xR is None: out_xR = self.gd.empty(in_xR.shape[:-3]) a_xR = in_xR.reshape((-1,) + in_xR.shape[-3:]) b_xR = out_xR.reshape((-1,) + out_xR.shape[-3:]) for in_R, out_R in zip(a_xR, b_xR): out_R[:] = self.pd3.restrict(in_R, self.pd2)[0] return out_xR def calculate_forces2(self, dens, ghat_aLv, nct_av, vbar_av): dens.ghat.derivative(self.vHt_q, ghat_aLv) dens.nct.derivative(self.vt_Q, nct_av) self.vbar.derivative(dens.nt_sQ.sum(0), vbar_av) gpaw-0.11.0.13004/gpaw/wavefunctions/lcao.py0000664000175000017500000011624012553643470020601 0ustar jensjjensj00000000000000import numpy as np from gpaw.lfc import BasisFunctions from gpaw.utilities import unpack from gpaw.utilities.tools import tri2full from gpaw import debug from gpaw.lcao.overlap import NewTwoCenterIntegrals as NewTCI from gpaw.utilities.blas import gemm, gemmdot from gpaw.wavefunctions.base import WaveFunctions from gpaw.lcao.atomic_correction import get_atomic_correction class LCAO: name = 'lcao' def __init__(self, atomic_correction=None): self.atomic_correction = atomic_correction def __call__(self, collinear, *args, **kwargs): if collinear: cls = LCAOWaveFunctions else: from gpaw.xc.noncollinear import \ NonCollinearLCAOWaveFunctions cls = NonCollinearLCAOWaveFunctions return cls(*args, atomic_correction=self.atomic_correction, **kwargs) # replace by class to make data structure perhaps a bit less confusing def get_r_and_offsets(nl, spos_ac, cell_cv): r_and_offset_aao = {} def add(a1, a2, R_c, offset): if not (a1, a2) in r_and_offset_aao: r_and_offset_aao[(a1, a2)] = [] r_and_offset_aao[(a1, a2)].append((R_c, offset)) for a1, spos1_c in enumerate(spos_ac): a2_a, offsets = nl.get_neighbors(a1) for a2, offset in zip(a2_a, offsets): spos2_c = spos_ac[a2] + offset R_c = np.dot(spos2_c - spos1_c, cell_cv) add(a1, a2, R_c, offset) if a1 != a2 or offset.any(): add(a2, a1, -R_c, -offset) return r_and_offset_aao class LCAOWaveFunctions(WaveFunctions): mode = 'lcao' def __init__(self, ksl, gd, nvalence, setups, bd, dtype, world, kd, kptband_comm, timer, atomic_correction=None): WaveFunctions.__init__(self, gd, nvalence, setups, bd, dtype, world, kd, kptband_comm, timer) self.ksl = ksl self.S_qMM = None self.T_qMM = None self.P_aqMi = None if atomic_correction is None: if ksl.using_blacs: atomic_correction = 'distributed' else: atomic_correction = 'dense' if isinstance(atomic_correction, str): atomic_correction = get_atomic_correction(atomic_correction) self.atomic_correction = atomic_correction self.timer.start('TCI: Evaluate splines') self.tci = NewTCI(gd.cell_cv, gd.pbc_c, setups, kd.ibzk_qc, kd.gamma) self.timer.stop('TCI: Evaluate splines') self.basis_functions = BasisFunctions(gd, [setup.phit_j for setup in setups], kd, dtype=dtype, cut=True) def empty(self, n=(), global_array=False, realspace=False): if realspace: return self.gd.empty(n, self.dtype, global_array) else: if isinstance(n, int): n = (n,) nao = self.setups.nao return np.empty(n + (nao,), self.dtype) def summary(self, fd): fd.write('Wave functions: LCAO\n') fd.write(' Diagonalizer: %s\n' % self.ksl.get_description()) fd.write(' Atomic Correction: %s\n' % self.atomic_correction.description) fd.write(" Datatype: %s\n" % self.dtype.__name__) def set_eigensolver(self, eigensolver): WaveFunctions.set_eigensolver(self, eigensolver) eigensolver.initialize(self.gd, self.dtype, self.setups.nao, self.ksl) def set_positions(self, spos_ac, atom_partition=None): self.timer.start('Basic WFS set positions') WaveFunctions.set_positions(self, spos_ac, atom_partition) self.timer.stop('Basic WFS set positions') self.timer.start('Basis functions set positions') self.basis_functions.set_positions(spos_ac) self.timer.stop('Basis functions set positions') if self.ksl is not None: self.basis_functions.set_matrix_distribution(self.ksl.Mstart, self.ksl.Mstop) nq = len(self.kd.ibzk_qc) nao = self.setups.nao mynbands = self.bd.mynbands Mstop = self.ksl.Mstop Mstart = self.ksl.Mstart mynao = Mstop - Mstart if self.ksl.using_blacs: # XXX # S and T have been distributed to a layout with blacs, so # discard them to force reallocation from scratch. # # TODO: evaluate S and T when they *are* distributed, thus saving # memory and avoiding this problem self.S_qMM = None self.T_qMM = None S_qMM = self.S_qMM T_qMM = self.T_qMM if S_qMM is None: # XXX # First time: assert T_qMM is None if self.ksl.using_blacs: # XXX self.tci.set_matrix_distribution(Mstart, mynao) S_qMM = np.empty((nq, mynao, nao), self.dtype) T_qMM = np.empty((nq, mynao, nao), self.dtype) for kpt in self.kpt_u: if kpt.C_nM is None: kpt.C_nM = np.empty((mynbands, nao), self.dtype) self.P_aqMi = {} for a in self.basis_functions.my_atom_indices: ni = self.setups[a].ni self.P_aqMi[a] = np.empty((nq, nao, ni), self.dtype) self.timer.start('TCI: Calculate S, T, P') # Calculate lower triangle of S and T matrices: self.tci.calculate(spos_ac, S_qMM, T_qMM, self.P_aqMi) # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX if self.atomic_correction.name != 'dense': from gpaw.lcao.newoverlap import newoverlap self.P_neighbors_a, self.P_aaqim = newoverlap(self, spos_ac) self.atomic_correction.gobble_data(self) # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX self.atomic_correction.add_overlap_correction(self, S_qMM) self.timer.stop('TCI: Calculate S, T, P') if self.atomic_correction.implements_distributed_projections(): my_atom_indices = self.atomic_correction.get_a_values() else: my_atom_indices = self.basis_functions.my_atom_indices self.allocate_arrays_for_projections(my_atom_indices) S_MM = None # allow garbage collection of old S_qMM after redist S_qMM = self.ksl.distribute_overlap_matrix(S_qMM, root=-1) T_qMM = self.ksl.distribute_overlap_matrix(T_qMM, root=-1) for kpt in self.kpt_u: q = kpt.q kpt.S_MM = S_qMM[q] kpt.T_MM = T_qMM[q] if (debug and self.band_comm.size == 1 and self.gd.comm.rank == 0 and nao > 0 and not self.ksl.using_blacs): # S and T are summed only on comm master, so check only there from numpy.linalg import eigvalsh self.timer.start('Check positive definiteness') for S_MM in S_qMM: tri2full(S_MM, UL='L') smin = eigvalsh(S_MM).real.min() if smin < 0: raise RuntimeError('Overlap matrix has negative ' 'eigenvalue: %e' % smin) self.timer.stop('Check positive definiteness') self.positions_set = True self.S_qMM = S_qMM self.T_qMM = T_qMM def initialize(self, density, hamiltonian, spos_ac): self.timer.start('LCAO WFS Initialize') if density.nt_sG is None: if self.kpt_u[0].f_n is None or self.kpt_u[0].C_nM is None: density.initialize_from_atomic_densities(self.basis_functions) else: # We have the info we need for a density matrix, so initialize # from that instead of from scratch. This will be the case # after set_positions() during a relaxation density.initialize_from_wavefunctions(self) # Initialize GLLB-potential from basis function orbitals if hamiltonian.xc.type == 'GLLB': hamiltonian.xc.initialize_from_atomic_orbitals(\ self.basis_functions) else: # After a restart, nt_sg doesn't exist yet, so we'll have to # make sure it does. Of course, this should have been taken care # of already by this time, so we should improve the code elsewhere density.calculate_normalized_charges_and_mix() #print "Updating hamiltonian in LCAO initialize wfs" hamiltonian.update(density) self.timer.stop('LCAO WFS Initialize') def initialize_wave_functions_from_lcao(self): """ Fill the calc.wfs.kpt_[u].psit_nG arrays with usefull data. Normally psit_nG is NOT used in lcao mode, but some extensions (like ase.dft.wannier) want to have it. This code is adapted from fd.py / initialize_from_lcao_coefficients() and fills psit_nG with data constructed from the current lcao coefficients (kpt.C_nM). (This may or may not work in band-parallel case!) """ #print('initialize_wave_functions_from_lcao') bfs = self.basis_functions for kpt in self.kpt_u: #print("kpt: {0}".format(kpt)) kpt.psit_nG = self.gd.zeros(self.bd.nbands, self.dtype) bfs.lcao_to_grid(kpt.C_nM, kpt.psit_nG[:self.bd.mynbands], kpt.q) # kpt.C_nM = None def initialize_wave_functions_from_restart_file(self): """Dummy function to ensure compatibility to fd mode""" self.initialize_wave_functions_from_lcao() def calculate_density_matrix(self, f_n, C_nM, rho_MM=None): # ATLAS can't handle uninitialized output array: #rho_MM.fill(42) self.timer.start('Calculate density matrix') rho_MM = self.ksl.calculate_density_matrix(f_n, C_nM, rho_MM) self.timer.stop('Calculate density matrix') return rho_MM # ---------------------------- if 1: # XXX Should not conjugate, but call gemm(..., 'c') # Although that requires knowing C_Mn and not C_nM. # that also conforms better to the usual conventions in literature Cf_Mn = C_nM.T.conj() * f_n self.timer.start('gemm') gemm(1.0, C_nM, Cf_Mn, 0.0, rho_MM, 'n') self.timer.stop('gemm') self.timer.start('band comm sum') self.bd.comm.sum(rho_MM) self.timer.stop('band comm sum') else: # Alternative suggestion. Might be faster. Someone should test this from gpaw.utilities.blas import r2k C_Mn = C_nM.T.copy() r2k(0.5, C_Mn, f_n * C_Mn, 0.0, rho_MM) tri2full(rho_MM) def calculate_atomic_density_matrices_with_occupation(self, D_asp, f_un): ac = self.atomic_correction if ac.implements_distributed_projections(): D2_asp = ac.redistribute(self, D_asp, type='asp', op='forth') WaveFunctions.calculate_atomic_density_matrices_with_occupation( self, D2_asp, f_un) D3_asp = ac.redistribute(self, D2_asp, type='asp', op='back') for a in D_asp: D_asp[a][:] = D3_asp[a] else: WaveFunctions.calculate_atomic_density_matrices_with_occupation( self, D_asp, f_un) def calculate_density_matrix_delta(self, d_nn, C_nM, rho_MM=None): # ATLAS can't handle uninitialized output array: #rho_MM.fill(42) self.timer.start('Calculate density matrix') rho_MM = self.ksl.calculate_density_matrix_delta(d_nn, C_nM, rho_MM) self.timer.stop('Calculate density matrix') return rho_MM def add_to_density_from_k_point_with_occupation(self, nt_sG, kpt, f_n): """Add contribution to pseudo electron-density. Do not use the standard occupation numbers, but ones given with argument f_n.""" # Custom occupations are used in calculation of response potential # with GLLB-potential if kpt.rho_MM is None: rho_MM = self.calculate_density_matrix(f_n, kpt.C_nM) if hasattr(kpt, 'c_on'): assert self.bd.comm.size == 1 d_nn = np.zeros((self.bd.mynbands, self.bd.mynbands), dtype=kpt.C_nM.dtype) for ne, c_n in zip(kpt.ne_o, kpt.c_on): assert abs(c_n.imag).max() < 1e-14 d_nn += ne * np.outer(c_n.conj(), c_n).real rho_MM += self.calculate_density_matrix_delta(d_nn, kpt.C_nM) else: rho_MM = kpt.rho_MM self.timer.start('Construct density') self.basis_functions.construct_density(rho_MM, nt_sG[kpt.s], kpt.q) self.timer.stop('Construct density') def add_to_kinetic_density_from_k_point(self, taut_G, kpt): raise NotImplementedError('Kinetic density calculation for LCAO ' 'wavefunctions is not implemented.') def calculate_forces(self, hamiltonian, F_av): self.timer.start('LCAO forces') spos_ac = self.tci.atoms.get_scaled_positions() % 1.0 ksl = self.ksl nao = ksl.nao mynao = ksl.mynao nq = len(self.kd.ibzk_qc) dtype = self.dtype tci = self.tci gd = self.gd bfs = self.basis_functions Mstart = ksl.Mstart Mstop = ksl.Mstop from gpaw.kohnsham_layouts import BlacsOrbitalLayouts isblacs = isinstance(ksl, BlacsOrbitalLayouts) # XXX if not isblacs: self.timer.start('TCI derivative') dThetadR_qvMM = np.empty((nq, 3, mynao, nao), dtype) dTdR_qvMM = np.empty((nq, 3, mynao, nao), dtype) dPdR_aqvMi = {} for a in self.basis_functions.my_atom_indices: ni = self.setups[a].ni dPdR_aqvMi[a] = np.empty((nq, 3, nao, ni), dtype) tci.calculate_derivative(spos_ac, dThetadR_qvMM, dTdR_qvMM, dPdR_aqvMi) gd.comm.sum(dThetadR_qvMM) gd.comm.sum(dTdR_qvMM) self.timer.stop('TCI derivative') my_atom_indices = bfs.my_atom_indices atom_indices = bfs.atom_indices def _slices(indices): for a in indices: M1 = bfs.M_a[a] - Mstart M2 = M1 + self.setups[a].nao if M2 > 0: yield a, max(0, M1), M2 def slices(): return _slices(atom_indices) def my_slices(): return _slices(my_atom_indices) # # ----- ----- # \ -1 \ * # E = ) S H rho = ) c eps f c # mu nu / mu x x z z nu / n mu n n n nu # ----- ----- # x z n # # We use the transpose of that matrix. The first form is used # if rho is given, otherwise the coefficients are used. self.timer.start('Initial') rhoT_uMM = [] ET_uMM = [] if not isblacs: if self.kpt_u[0].rho_MM is None: self.timer.start('Get density matrix') for kpt in self.kpt_u: rhoT_MM = ksl.get_transposed_density_matrix(kpt.f_n, kpt.C_nM) rhoT_uMM.append(rhoT_MM) ET_MM = ksl.get_transposed_density_matrix(kpt.f_n * kpt.eps_n, kpt.C_nM) ET_uMM.append(ET_MM) if hasattr(kpt, 'c_on'): # XXX does this work with BLACS/non-BLACS/etc.? assert self.bd.comm.size == 1 d_nn = np.zeros((self.bd.mynbands, self.bd.mynbands), dtype=kpt.C_nM.dtype) for ne, c_n in zip(kpt.ne_o, kpt.c_on): d_nn += ne * np.outer(c_n.conj(), c_n) rhoT_MM += ksl.get_transposed_density_matrix_delta(\ d_nn, kpt.C_nM) ET_MM += ksl.get_transposed_density_matrix_delta(\ d_nn * kpt.eps_n, kpt.C_nM) self.timer.stop('Get density matrix') else: rhoT_uMM = [] ET_uMM = [] for kpt in self.kpt_u: H_MM = self.eigensolver.calculate_hamiltonian_matrix(\ hamiltonian, self, kpt) tri2full(H_MM) S_MM = kpt.S_MM.copy() tri2full(S_MM) ET_MM = np.linalg.solve(S_MM, gemmdot(H_MM, kpt.rho_MM)).T.copy() del S_MM, H_MM rhoT_MM = kpt.rho_MM.T.copy() rhoT_uMM.append(rhoT_MM) ET_uMM.append(ET_MM) self.timer.stop('Initial') if isblacs: # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX from gpaw.blacs import BlacsGrid, Redistributor def get_density_matrix(f_n, C_nM, redistributor): rho1_mm = ksl.calculate_blocked_density_matrix(f_n, C_nM).conj() rho_mm = redistributor.redistribute(rho1_mm) return rho_mm pcutoff_a = [max([pt.get_cutoff() for pt in setup.pt_j]) for setup in self.setups] phicutoff_a = [max([phit.get_cutoff() for phit in setup.phit_j]) for setup in self.setups] # XXX should probably use bdsize x gdsize instead # That would be consistent with some existing grids grid = BlacsGrid(ksl.block_comm, self.gd.comm.size, self.bd.comm.size) blocksize1 = -(-nao // grid.nprow) blocksize2 = -(-nao // grid.npcol) # XXX what are rows and columns actually? desc = grid.new_descriptor(nao, nao, blocksize1, blocksize2) rhoT_umm = [] ET_umm = [] redistributor = Redistributor(grid.comm, ksl.mmdescriptor, desc) Fpot_av = np.zeros_like(F_av) for u, kpt in enumerate(self.kpt_u): self.timer.start('Get density matrix') rhoT_mm = get_density_matrix(kpt.f_n, kpt.C_nM, redistributor) rhoT_umm.append(rhoT_mm) self.timer.stop('Get density matrix') self.timer.start('Potential') rhoT_mM = ksl.distribute_to_columns(rhoT_mm, desc) vt_G = hamiltonian.vt_sG[kpt.s] Fpot_av += bfs.calculate_force_contribution(vt_G, rhoT_mM, kpt.q) del rhoT_mM self.timer.stop('Potential') self.timer.start('Get density matrix') for kpt in self.kpt_u: ET_mm = get_density_matrix(kpt.f_n * kpt.eps_n, kpt.C_nM, redistributor) ET_umm.append(ET_mm) self.timer.stop('Get density matrix') M1start = blocksize1 * grid.myrow M2start = blocksize2 * grid.mycol M1stop = min(M1start + blocksize1, nao) M2stop = min(M2start + blocksize2, nao) m1max = M1stop - M1start m2max = M2stop - M2start if not isblacs: # Kinetic energy contribution # # ----- d T # a \ mu nu # F += 2 Re ) -------- rho # / d R nu mu # ----- mu nu # mu in a; nu # Fkin_av = np.zeros_like(F_av) for u, kpt in enumerate(self.kpt_u): dEdTrhoT_vMM = (dTdR_qvMM[kpt.q] * rhoT_uMM[u][np.newaxis]).real for a, M1, M2 in my_slices(): Fkin_av[a, :] += \ 2.0 * dEdTrhoT_vMM[:, M1:M2].sum(-1).sum(-1) del dEdTrhoT_vMM # Density matrix contribution due to basis overlap # # ----- d Theta # a \ mu nu # F += -2 Re ) ------------ E # / d R nu mu # ----- mu nu # mu in a; nu # Ftheta_av = np.zeros_like(F_av) for u, kpt in enumerate(self.kpt_u): dThetadRE_vMM = (dThetadR_qvMM[kpt.q] * ET_uMM[u][np.newaxis]).real for a, M1, M2 in my_slices(): Ftheta_av[a, :] += \ -2.0 * dThetadRE_vMM[:, M1:M2].sum(-1).sum(-1) del dThetadRE_vMM if isblacs: from gpaw.lcao.overlap import TwoCenterIntegralCalculator self.timer.start('Prepare TCI loop') M_a = bfs.M_a Fkin2_av = np.zeros_like(F_av) Ftheta2_av = np.zeros_like(F_av) cell_cv = tci.atoms.cell spos_ac = tci.atoms.get_scaled_positions() % 1.0 overlapcalc = TwoCenterIntegralCalculator(self.kd.ibzk_qc, derivative=False) # XXX this is not parallel *AT ALL*. self.timer.start('Get neighbors') nl = tci.atompairs.pairs.neighbors r_and_offset_aao = get_r_and_offsets(nl, spos_ac, cell_cv) atompairs = sorted(r_and_offset_aao.keys()) self.timer.stop('Get neighbors') T_expansions = tci.T_expansions Theta_expansions = tci.Theta_expansions P_expansions = tci.P_expansions nq = len(self.kd.ibzk_qc) dH_asp = hamiltonian.dH_asp self.timer.start('broadcast dH') alldH_asp = {} for a in range(len(self.setups)): gdrank = bfs.sphere_a[a].rank if gdrank == gd.rank: dH_sp = dH_asp[a] else: ni = self.setups[a].ni dH_sp = np.empty((self.nspins, ni * (ni + 1) // 2)) gd.comm.broadcast(dH_sp, gdrank) # okay, now everyone gets copies of dH_sp alldH_asp[a] = dH_sp self.timer.stop('broadcast dH') # This will get sort of hairy. We need to account for some # three-center overlaps, such as: # # a1 # Phi ~a3 a3 ~a3 a2 a2,a1 # < ---- |p > dH

rho # dR # # To this end we will loop over all pairs of atoms (a1, a3), # and then a sub-loop over (a3, a2). from gpaw.lcao.overlap import DerivativeAtomicDisplacement class Displacement(DerivativeAtomicDisplacement): def __init__(self, a1, a2, R_c, offset): phases = overlapcalc.phaseclass(overlapcalc.ibzk_qc, offset) DerivativeAtomicDisplacement.__init__(self, None, a1, a2, R_c, offset, phases) # Cache of Displacement objects with spherical harmonics with # evaluated spherical harmonics. disp_aao = {} def get_displacements(a1, a2, maxdistance): # XXX the way maxdistance is handled it can lead to # bad caching when different maxdistances are passed # to subsequent calls with same pair of atoms disp_o = disp_aao.get((a1, a2)) if disp_o is None: disp_o = [] for R_c, offset in r_and_offset_aao[(a1, a2)]: if np.linalg.norm(R_c) > maxdistance: continue disp = Displacement(a1, a2, R_c, offset) disp_o.append(disp) disp_aao[(a1, a2)] = disp_o return [disp for disp in disp_o if disp.r < maxdistance] self.timer.stop('Prepare TCI loop') self.timer.start('Not so complicated loop') for (a1, a2) in atompairs: if a1 >= a2: # Actually this leads to bad load balance. # We should take a1 > a2 or a1 < a2 equally many times. # Maybe decide which of these choices # depending on whether a2 % 1 == 0 continue m1start = M_a[a1] - M1start m2start = M_a[a2] - M2start if m1start >= blocksize1 or m2start >= blocksize2: continue # (we have only one block per CPU) T_expansion = T_expansions.get(a1, a2) Theta_expansion = Theta_expansions.get(a1, a2) #P_expansion = P_expansions.get(a1, a2) nm1, nm2 = T_expansion.shape m1stop = min(m1start + nm1, m1max) m2stop = min(m2start + nm2, m2max) if m1stop <= 0 or m2stop <= 0: continue m1start = max(m1start, 0) m2start = max(m2start, 0) J1start = max(0, M1start - M_a[a1]) J2start = max(0, M2start - M_a[a2]) M1stop = J1start + m1stop - m1start J2stop = J2start + m2stop - m2start dTdR_qvmm = T_expansion.zeros((nq, 3), dtype=dtype) dThetadR_qvmm = Theta_expansion.zeros((nq, 3), dtype=dtype) disp_o = get_displacements(a1, a2, phicutoff_a[a1] + phicutoff_a[a2]) for disp in disp_o: disp.evaluate_overlap(T_expansion, dTdR_qvmm) disp.evaluate_overlap(Theta_expansion, dThetadR_qvmm) for u, kpt in enumerate(self.kpt_u): rhoT_mm = rhoT_umm[u][m1start:m1stop, m2start:m2stop] ET_mm = ET_umm[u][m1start:m1stop, m2start:m2stop] Fkin_v = 2.0 * (dTdR_qvmm[kpt.q][:, J1start:M1stop, J2start:J2stop] * rhoT_mm[np.newaxis]).real.sum(-1).sum(-1) Ftheta_v = 2.0 * (dThetadR_qvmm[kpt.q][:, J1start:M1stop, J2start:J2stop] * ET_mm[np.newaxis]).real.sum(-1).sum(-1) Fkin2_av[a1] += Fkin_v Fkin2_av[a2] -= Fkin_v Ftheta2_av[a1] -= Ftheta_v Ftheta2_av[a2] += Ftheta_v Fkin_av = Fkin2_av Ftheta_av = Ftheta2_av self.timer.stop('Not so complicated loop') dHP_and_dSP_aauim = {} a2values = {} for (a2, a3) in atompairs: if not a3 in a2values: a2values[a3] = [] a2values[a3].append(a2) Fatom_av = np.zeros_like(F_av) Frho_av = np.zeros_like(F_av) self.timer.start('Complicated loop') for a1, a3 in atompairs: if a1 == a3: # Functions reside on same atom, so their overlap # does not change when atom is displaced continue m1start = M_a[a1] - M1start if m1start >= blocksize1: continue P_expansion = P_expansions.get(a1, a3) nm1 = P_expansion.shape[0] m1stop = min(m1start + nm1, m1max) if m1stop <= 0: continue m1start = max(m1start, 0) J1start = max(0, M1start - M_a[a1]) J1stop = J1start + m1stop - m1start disp_o = get_displacements(a1, a3, phicutoff_a[a1] + pcutoff_a[a3]) if len(disp_o) == 0: continue dPdR_qvmi = P_expansion.zeros((nq, 3), dtype=dtype) for disp in disp_o: disp.evaluate_overlap(P_expansion, dPdR_qvmi) dPdR_qvmi = dPdR_qvmi[:, :, J1start:J1stop, :].copy() for a2 in a2values[a3]: m2start = M_a[a2] - M2start if m2start >= blocksize2: continue P_expansion2 = P_expansions.get(a2, a3) nm2 = P_expansion2.shape[0] m2stop = min(m2start + nm2, m2max) if m2stop <= 0: continue disp_o = get_displacements(a2, a3, phicutoff_a[a2] + pcutoff_a[a3]) if len(disp_o) == 0: continue m2start = max(m2start, 0) J2start = max(0, M2start - M_a[a2]) J2stop = J2start + m2stop - m2start if (a2, a3) in dHP_and_dSP_aauim: dHP_uim, dSP_uim = dHP_and_dSP_aauim[(a2, a3)] else: P_qmi = P_expansion2.zeros((nq,), dtype=dtype) for disp in disp_o: disp.evaluate_direct(P_expansion2, P_qmi) P_qmi = P_qmi[:, J2start:J2stop].copy() dH_sp = alldH_asp[a3] dS_ii = self.setups[a3].dO_ii dHP_uim = [] dSP_uim = [] for u, kpt in enumerate(self.kpt_u): dH_ii = unpack(dH_sp[kpt.s]) dHP_im = np.dot(P_qmi[kpt.q], dH_ii).T.conj() # XXX only need nq of these dSP_im = np.dot(P_qmi[kpt.q], dS_ii).T.conj() dHP_uim.append(dHP_im) dSP_uim.append(dSP_im) dHP_and_dSP_aauim[(a2, a3)] = dHP_uim, dSP_uim for u, kpt in enumerate(self.kpt_u): rhoT_mm = rhoT_umm[u][m1start:m1stop, m2start:m2stop] ET_mm = ET_umm[u][m1start:m1stop, m2start:m2stop] dPdRdHP_vmm = np.dot(dPdR_qvmi[kpt.q], dHP_uim[u]) dPdRdSP_vmm = np.dot(dPdR_qvmi[kpt.q], dSP_uim[u]) Fatom_c = 2.0 * (dPdRdHP_vmm * rhoT_mm).real.sum(-1).sum(-1) Frho_c = 2.0 * (dPdRdSP_vmm * ET_mm).real.sum(-1).sum(-1) Fatom_av[a1] += Fatom_c Fatom_av[a3] -= Fatom_c Frho_av[a1] -= Frho_c Frho_av[a3] += Frho_c self.timer.stop('Complicated loop') if not isblacs: # Potential contribution # # ----- / d Phi (r) # a \ | mu ~ # F += -2 Re ) | ---------- v (r) Phi (r) dr rho # / | d R nu nu mu # ----- / a # mu in a; nu # self.timer.start('Potential') Fpot_av = np.zeros_like(F_av) for u, kpt in enumerate(self.kpt_u): vt_G = hamiltonian.vt_sG[kpt.s] Fpot_av += bfs.calculate_force_contribution(vt_G, rhoT_uMM[u], kpt.q) self.timer.stop('Potential') # Density matrix contribution from PAW correction # # ----- ----- # a \ a \ b # F += 2 Re ) Z E - 2 Re ) Z E # / mu nu nu mu / mu nu nu mu # ----- ----- # mu nu b; mu in a; nu # # with # b* # ----- dP # b \ i mu b b # Z = ) -------- dS P # mu nu / dR ij j nu # ----- b mu # ij # self.timer.start('Paw correction') Frho_av = np.zeros_like(F_av) for u, kpt in enumerate(self.kpt_u): work_MM = np.zeros((mynao, nao), dtype) ZE_MM = None for b in my_atom_indices: setup = self.setups[b] dO_ii = np.asarray(setup.dO_ii, dtype) dOP_iM = np.zeros((setup.ni, nao), dtype) gemm(1.0, self.P_aqMi[b][kpt.q], dO_ii, 0.0, dOP_iM, 'c') for v in range(3): gemm(1.0, dOP_iM, dPdR_aqvMi[b][kpt.q][v][Mstart:Mstop], 0.0, work_MM, 'n') ZE_MM = (work_MM * ET_uMM[u]).real for a, M1, M2 in slices(): dE = 2 * ZE_MM[M1:M2].sum() Frho_av[a, v] -= dE # the "b; mu in a; nu" term Frho_av[b, v] += dE # the "mu nu" term del work_MM, ZE_MM self.timer.stop('Paw correction') # Atomic density contribution # ----- ----- # a \ a \ b # F += -2 Re ) A rho + 2 Re ) A rho # / mu nu nu mu / mu nu nu mu # ----- ----- # mu nu b; mu in a; nu # # b* # ----- d P # b \ i mu b b # A = ) ------- dH P # mu nu / d R ij j nu # ----- b mu # ij # self.timer.start('Atomic Hamiltonian force') Fatom_av = np.zeros_like(F_av) for u, kpt in enumerate(self.kpt_u): for b in my_atom_indices: H_ii = np.asarray(unpack(hamiltonian.dH_asp[b][kpt.s]), dtype) HP_iM = gemmdot(H_ii, np.ascontiguousarray( self.P_aqMi[b][kpt.q].T.conj())) for v in range(3): dPdR_Mi = dPdR_aqvMi[b][kpt.q][v][Mstart:Mstop] ArhoT_MM = (gemmdot(dPdR_Mi, HP_iM) * rhoT_uMM[u]).real for a, M1, M2 in slices(): dE = 2 * ArhoT_MM[M1:M2].sum() Fatom_av[a, v] += dE # the "b; mu in a; nu" term Fatom_av[b, v] -= dE # the "mu nu" term self.timer.stop('Atomic Hamiltonian force') F_av += Fkin_av + Fpot_av + Ftheta_av + Frho_av + Fatom_av self.timer.start('Wait for sum') ksl.orbital_comm.sum(F_av) if self.bd.comm.rank == 0: self.kd.comm.sum(F_av, 0) self.timer.stop('Wait for sum') self.timer.stop('LCAO forces') def _get_wave_function_array(self, u, n, realspace=True): kpt = self.kpt_u[u] if kpt.C_nM is None: # Hack to make sure things are available after restart self.lazyloader.load(self) C_M = kpt.C_nM[n] if realspace: psit_G = self.gd.zeros(dtype=self.dtype) self.basis_functions.lcao_to_grid(C_M, psit_G, kpt.q) return psit_G else: return C_M def load_lazily(self, hamiltonian, spos_ac): """Horrible hack to recalculate lcao coefficients after restart.""" self.basis_functions.set_positions(spos_ac) class LazyLoader: def __init__(self, hamiltonian, spos_ac): self.spos_ac = spos_ac def load(self, wfs): wfs.set_positions(self.spos_ac) # this sets rank_a # Now we need to pass atom_partition or things to work # XXX WTF why does one have to fiddle with atom_partition??? hamiltonian.set_positions(self.spos_ac, wfs.atom_partition) wfs.eigensolver.iterate(hamiltonian, wfs) del wfs.lazyloader self.lazyloader = LazyLoader(hamiltonian, spos_ac) def write(self, writer, write_wave_functions=False): writer['Mode'] = 'lcao' if not write_wave_functions: return writer.dimension('nbasis', self.setups.nao) writer.add('WaveFunctionCoefficients', ('nspins', 'nibzkpts', 'nbands', 'nbasis'), dtype=self.dtype) for s in range(self.nspins): for k in range(self.kd.nibzkpts): C_nM = self.collect_array('C_nM', k, s) writer.fill(C_nM, s, k) def read_coefficients(self, reader): for kpt in self.kpt_u: kpt.C_nM = self.bd.empty(self.setups.nao, dtype=self.dtype) for myn, C_M in enumerate(kpt.C_nM): n = self.bd.global_index(myn) C_M[:] = reader.get('WaveFunctionCoefficients', kpt.s, kpt.k, n) def estimate_memory(self, mem): nq = len(self.kd.ibzk_qc) nao = self.setups.nao ni_total = sum([setup.ni for setup in self.setups]) itemsize = mem.itemsize[self.dtype] mem.subnode('C [qnM]', nq * self.bd.mynbands * nao * itemsize) nM1, nM2 = self.ksl.get_overlap_matrix_shape() mem.subnode('S, T [2 x qmm]', 2 * nq * nM1 * nM2 * itemsize) mem.subnode('P [aqMi]', nq * nao * ni_total // self.gd.comm.size) self.tci.estimate_memory(mem.subnode('TCI')) self.basis_functions.estimate_memory(mem.subnode('BasisFunctions')) self.eigensolver.estimate_memory(mem.subnode('Eigensolver'), self.dtype) gpaw-0.11.0.13004/gpaw/wavefunctions/fdpw.py0000664000175000017500000002101012553643470020611 0ustar jensjjensj00000000000000from __future__ import division import numpy as np from gpaw import extra_parameters from gpaw.io import FileReference from gpaw.lcao.eigensolver import DirectLCAO from gpaw.lfc import BasisFunctions from gpaw.overlap import Overlap from gpaw.utilities import unpack from gpaw.utilities.timing import nulltimer from gpaw.wavefunctions.base import WaveFunctions from gpaw.wavefunctions.lcao import LCAOWaveFunctions class FDPWWaveFunctions(WaveFunctions): """Base class for finite-difference and planewave classes.""" def __init__(self, diagksl, orthoksl, initksl, *args, **kwargs): WaveFunctions.__init__(self, *args, **kwargs) self.diagksl = diagksl self.orthoksl = orthoksl self.initksl = initksl self.set_orthonormalized(False) self.overlap = self.make_overlap() def set_setups(self, setups): WaveFunctions.set_setups(self, setups) def set_orthonormalized(self, flag): self.orthonormalized = flag def set_positions(self, spos_ac, atom_partition=None): WaveFunctions.set_positions(self, spos_ac, atom_partition) self.set_orthonormalized(False) self.pt.set_positions(spos_ac) self.allocate_arrays_for_projections(self.pt.my_atom_indices) self.positions_set = True def make_overlap(self): return Overlap(self.orthoksl, self.timer) def initialize(self, density, hamiltonian, spos_ac): if self.kpt_u[0].psit_nG is None: basis_functions = BasisFunctions(self.gd, [setup.phit_j for setup in self.setups], self.kd, dtype=self.dtype, cut=True) basis_functions.set_positions(spos_ac) elif isinstance(self.kpt_u[0].psit_nG, FileReference): self.initialize_wave_functions_from_restart_file() if self.kpt_u[0].psit_nG is not None: density.initialize_from_wavefunctions(self) elif density.nt_sG is None: density.initialize_from_atomic_densities(basis_functions) # Initialize GLLB-potential from basis function orbitals if hamiltonian.xc.type == 'GLLB': hamiltonian.xc.initialize_from_atomic_orbitals( basis_functions) else: # XXX??? # We didn't even touch density, but some combinations in paw.set() # will make it necessary to do this for some reason. density.calculate_normalized_charges_and_mix() hamiltonian.update(density) if self.kpt_u[0].psit_nG is None: self.initialize_wave_functions_from_basis_functions( basis_functions, density, hamiltonian, spos_ac) def initialize_wave_functions_from_basis_functions(self, basis_functions, density, hamiltonian, spos_ac): if self.initksl is None: raise RuntimeError('use fewer bands or more basis functions') self.timer.start('LCAO initialization') lcaoksl, lcaobd = self.initksl, self.initksl.bd lcaowfs = LCAOWaveFunctions(lcaoksl, self.gd, self.nvalence, self.setups, lcaobd, self.dtype, self.world, self.kd, self.kptband_comm, nulltimer) lcaowfs.basis_functions = basis_functions lcaowfs.timer = self.timer self.timer.start('Set positions (LCAO WFS)') lcaowfs.set_positions(spos_ac, self.atom_partition) self.timer.stop('Set positions (LCAO WFS)') eigensolver = DirectLCAO() eigensolver.initialize(self.gd, self.dtype, self.setups.nao, lcaoksl) # XXX when density matrix is properly distributed, be sure to # update the density here also eigensolver.iterate(hamiltonian, lcaowfs) # Transfer coefficients ... for kpt, lcaokpt in zip(self.kpt_u, lcaowfs.kpt_u): kpt.C_nM = lcaokpt.C_nM # and get rid of potentially big arrays early: del eigensolver, lcaowfs self.timer.start('LCAO to grid') self.initialize_from_lcao_coefficients(basis_functions, lcaobd.mynbands) self.timer.stop('LCAO to grid') if self.bd.mynbands > lcaobd.mynbands: # Add extra states. If the number of atomic orbitals is # less than the desired number of bands, then extra random # wave functions are added. self.random_wave_functions(lcaobd.mynbands) self.timer.stop('LCAO initialization') def initialize_wave_functions_from_restart_file(self): if not isinstance(self.kpt_u[0].psit_nG, FileReference): return # Calculation started from a restart file. Copy data # from the file to memory: for kpt in self.kpt_u: file_nG = kpt.psit_nG kpt.psit_nG = self.empty(self.bd.mynbands, q=kpt.q) if extra_parameters.get('sic'): kpt.W_nn = np.zeros((self.bd.nbands, self.bd.nbands), dtype=self.dtype) # Read band by band to save memory for n, psit_G in enumerate(kpt.psit_nG): if self.gd.comm.rank == 0: big_psit_G = file_nG[n][:].astype(psit_G.dtype) else: big_psit_G = None self.gd.distribute(big_psit_G, psit_G) def orthonormalize(self): for kpt in self.kpt_u: self.overlap.orthonormalize(self, kpt) self.set_orthonormalized(True) def calculate_forces(self, hamiltonian, F_av): # Calculate force-contribution from k-points: F_av.fill(0.0) F_aniv = self.pt.dict(self.bd.mynbands, derivative=True) for kpt in self.kpt_u: self.pt.derivative(kpt.psit_nG, F_aniv, kpt.q) for a, F_niv in F_aniv.items(): F_niv = F_niv.conj() F_niv *= kpt.f_n[:, np.newaxis, np.newaxis] dH_ii = unpack(hamiltonian.dH_asp[a][kpt.s]) P_ni = kpt.P_ani[a] F_vii = np.dot(np.dot(F_niv.transpose(), P_ni), dH_ii) F_niv *= kpt.eps_n[:, np.newaxis, np.newaxis] dO_ii = hamiltonian.setups[a].dO_ii F_vii -= np.dot(np.dot(F_niv.transpose(), P_ni), dO_ii) F_av[a] += 2 * F_vii.real.trace(0, 1, 2) # Hack used in delta-scf calculations: if hasattr(kpt, 'c_on'): assert self.bd.comm.size == 1 self.pt.derivative(kpt.psit_nG, F_aniv, kpt.q) # XXX again d_nn = np.zeros((self.bd.mynbands, self.bd.mynbands), dtype=complex) for ne, c_n in zip(kpt.ne_o, kpt.c_on): d_nn += ne * np.outer(c_n.conj(), c_n) for a, F_niv in F_aniv.items(): F_niv = F_niv.conj() dH_ii = unpack(hamiltonian.dH_asp[a][kpt.s]) Q_ni = np.dot(d_nn, kpt.P_ani[a]) F_vii = np.dot(np.dot(F_niv.transpose(), Q_ni), dH_ii) F_niv *= kpt.eps_n[:, np.newaxis, np.newaxis] dO_ii = hamiltonian.setups[a].dO_ii F_vii -= np.dot(np.dot(F_niv.transpose(), Q_ni), dO_ii) F_av[a] += 2 * F_vii.real.trace(0, 1, 2) self.bd.comm.sum(F_av, 0) if self.bd.comm.rank == 0: self.kd.comm.sum(F_av, 0) def _get_wave_function_array(self, u, n, realspace=True): psit_nG = self.kpt_u[u].psit_nG if psit_nG is None: raise RuntimeError('This calculator has no wave functions!') return psit_nG[n][:] # dereference possible tar-file content def estimate_memory(self, mem): gridbytes = self.bytes_per_wave_function() n = len(self.kpt_u) * self.bd.mynbands mem.subnode('Arrays psit_nG', n * gridbytes) self.eigensolver.estimate_memory(mem.subnode('Eigensolver'), self) ni = sum(dataset.ni for dataset in self.setups) / self.gd.comm.size mem.subnode('Projections', n * ni * np.dtype(self.dtype).itemsize) self.pt.estimate_memory(mem.subnode('Projectors')) self.matrixoperator.estimate_memory(mem.subnode('Overlap op'), self.dtype) gpaw-0.11.0.13004/gpaw/wavefunctions/base.py0000664000175000017500000003720612553643470020601 0ustar jensjjensj00000000000000import numpy as np from gpaw.utilities import pack, unpack2 from gpaw.utilities.blas import gemm from gpaw.utilities.partition import AtomPartition from gpaw.utilities.timing import nulltimer class EmptyWaveFunctions: mode = 'undefined' def __bool__(self): return False __nonzero__ = __bool__ # for Python 2 def set_eigensolver(self, eigensolver): pass def set_orthonormalized(self, flag): pass def estimate_memory(self, mem): mem.set('Unknown WFs', 0) class WaveFunctions(EmptyWaveFunctions): """... setups: List of setup objects. symmetry: Symmetry object. kpt_u: List of **k**-point objects. nbands: int Number of bands. nspins: int Number of spins. dtype: dtype Data type of wave functions (float or complex). bzk_kc: ndarray Scaled **k**-points used for sampling the whole Brillouin zone - values scaled to [-0.5, 0.5). ibzk_kc: ndarray Scaled **k**-points in the irreducible part of the Brillouin zone. weight_k: ndarray Weights of the **k**-points in the irreducible part of the Brillouin zone (summing up to 1). kpt_comm: MPI-communicator for parallelization over **k**-points. """ collinear = True # ncomp is a number of array components necessary to hold # information about non-collinear spins. With collinear spin # it is always 1; else it is 2. ncomp = 1 def __init__(self, gd, nvalence, setups, bd, dtype, world, kd, kptband_comm, timer=None): self.gd = gd self.nspins = kd.nspins self.ns = self.nspins * self.ncomp**2 self.nvalence = nvalence self.bd = bd #self.nbands = self.bd.nbands #XXX #self.mynbands = self.bd.mynbands #XXX self.dtype = dtype assert dtype == float or dtype == complex self.world = world self.kd = kd self.kptband_comm = kptband_comm self.band_comm = self.bd.comm # XXX if timer is None: timer = nulltimer self.timer = timer self.atom_partition = None self.kpt_u = kd.create_k_points(self.gd) self.eigensolver = None self.positions_set = False self.set_setups(setups) def set_setups(self, setups): self.setups = setups def set_eigensolver(self, eigensolver): self.eigensolver = eigensolver def __bool__(self): return True __nonzero__ = __bool__ # for Python 2 def calculate_density_contribution(self, nt_sG): """Calculate contribution to pseudo density from wave functions.""" nt_sG.fill(0.0) for kpt in self.kpt_u: self.add_to_density_from_k_point(nt_sG, kpt) self.kptband_comm.sum(nt_sG) self.timer.start('Symmetrize density') for nt_G in nt_sG: self.kd.symmetry.symmetrize(nt_G, self.gd) self.timer.stop('Symmetrize density') def add_to_density_from_k_point(self, nt_sG, kpt): self.add_to_density_from_k_point_with_occupation(nt_sG, kpt, kpt.f_n) def get_orbital_density_matrix(self, a, kpt, n): """Add the nth band density from kpt to density matrix D_sp""" ni = self.setups[a].ni D_sii = np.zeros((self.nspins, ni, ni)) P_i = kpt.P_ani[a][n] D_sii[kpt.s] += np.outer(P_i.conj(), P_i).real D_sp = [pack(D_ii) for D_ii in D_sii] return D_sp def calculate_atomic_density_matrices_k_point(self, D_sii, kpt, a, f_n): if kpt.rho_MM is not None: P_Mi = self.P_aqMi[a][kpt.q] #P_Mi = kpt.P_aMi_sparse[a] #ind = get_matrix_index(kpt.P_aMi_index[a]) #D_sii[kpt.s] += np.dot(np.dot(P_Mi.T.conj(), kpt.rho_MM), # P_Mi).real rhoP_Mi = np.zeros_like(P_Mi) D_ii = np.zeros(D_sii[kpt.s].shape, kpt.rho_MM.dtype) #gemm(1.0, P_Mi, kpt.rho_MM[ind.T, ind], 0.0, tmp) gemm(1.0, P_Mi, kpt.rho_MM, 0.0, rhoP_Mi) gemm(1.0, rhoP_Mi, P_Mi.T.conj().copy(), 0.0, D_ii) D_sii[kpt.s] += D_ii.real #D_sii[kpt.s] += dot(dot(P_Mi.T.conj().copy(), # kpt.rho_MM[ind.T, ind]), P_Mi).real else: P_ni = kpt.P_ani[a] D_sii[kpt.s] += np.dot(P_ni.T.conj() * f_n, P_ni).real if hasattr(kpt, 'c_on'): for ne, c_n in zip(kpt.ne_o, kpt.c_on): d_nn = ne * np.outer(c_n.conj(), c_n) D_sii[kpt.s] += np.dot(P_ni.T.conj(), np.dot(d_nn, P_ni)).real def calculate_atomic_density_matrices(self, D_asp): """Calculate atomic density matrices from projections.""" f_un = [kpt.f_n for kpt in self.kpt_u] self.calculate_atomic_density_matrices_with_occupation(D_asp, f_un) def calculate_atomic_density_matrices_with_occupation(self, D_asp, f_un): """Calculate atomic density matrices from projections with custom occupation f_un.""" # Parameter check (if user accidentally passes f_n instead of f_un) if f_un[0] is not None: # special case for transport calculations... assert isinstance(f_un[0], np.ndarray) # Varying f_n used in calculation of response part of GLLB-potential for a, D_sp in D_asp.items(): ni = self.setups[a].ni D_sii = np.zeros((len(D_sp), ni, ni)) for f_n, kpt in zip(f_un, self.kpt_u): self.calculate_atomic_density_matrices_k_point(D_sii, kpt, a, f_n) D_sp[:] = [pack(D_ii) for D_ii in D_sii] self.kptband_comm.sum(D_sp) self.symmetrize_atomic_density_matrices(D_asp) def symmetrize_atomic_density_matrices(self, D_asp): if len(self.kd.symmetry.op_scc) == 0: return if hasattr(D_asp, 'redistribute'): a_sa = self.kd.symmetry.a_sa D_asp.redistribute(self.atom_partition.as_serial()) for s in range(self.nspins): D_aii = [unpack2(D_asp[a][s]) for a in range(len(D_asp))] for a, D_ii in enumerate(D_aii): setup = self.setups[a] D_asp[a][s] = pack(setup.symmetrize(a, D_aii, a_sa)) D_asp.redistribute(self.atom_partition) else: all_D_asp = [] for a, setup in enumerate(self.setups): D_sp = D_asp.get(a) if D_sp is None: ni = setup.ni D_sp = np.empty((self.ns, ni * (ni + 1) // 2)) self.gd.comm.broadcast(D_sp, self.atom_partition.rank_a[a]) all_D_asp.append(D_sp) for s in range(self.nspins): D_aii = [unpack2(D_sp[s]) for D_sp in all_D_asp] for a, D_sp in D_asp.items(): setup = self.setups[a] D_sp[s] = pack(setup.symmetrize(a, D_aii, self.kd.symmetry.a_sa)) def set_positions(self, spos_ac, atom_partition=None): self.positions_set = False #rank_a = self.gd.get_ranks_from_positions(spos_ac) #atom_partition = AtomPartition(self.gd.comm, rank_a) # XXX pass AtomPartition around instead of spos_ac? # All the classes passing around spos_ac end up needing the ranks # anyway. if atom_partition is None: rank_a = self.gd.get_ranks_from_positions(spos_ac) atom_partition = AtomPartition(self.gd.comm, rank_a) if self.atom_partition is not None and self.kpt_u[0].P_ani is not None: self.timer.start('Redistribute') mynks = len(self.kpt_u) def get_empty(a): ni = self.setups[a].ni return np.empty((mynks, self.bd.mynbands, ni), self.dtype) self.atom_partition.redistribute(atom_partition, [kpt.P_ani for kpt in self.kpt_u], get_empty) self.timer.stop('Redistribute') self.atom_partition = atom_partition self.kd.symmetry.check(spos_ac) def allocate_arrays_for_projections(self, my_atom_indices): if not self.positions_set and self.kpt_u[0].P_ani is not None: # Projections have been read from file - don't delete them! pass else: for kpt in self.kpt_u: kpt.P_ani = {} for a in my_atom_indices: ni = self.setups[a].ni for kpt in self.kpt_u: kpt.P_ani[a] = np.empty((self.bd.mynbands, ni), self.dtype) def collect_eigenvalues(self, k, s): return self.collect_array('eps_n', k, s) def collect_occupations(self, k, s): return self.collect_array('f_n', k, s) def collect_array(self, name, k, s, subset=None): """Helper method for collect_eigenvalues and collect_occupations. For the parallel case find the rank in kpt_comm that contains the (k,s) pair, for this rank, collect on the corresponding domain a full array on the domain master and send this to the global master.""" kpt_u = self.kpt_u kpt_rank, u = self.kd.get_rank_and_index(s, k) if self.kd.comm.rank == kpt_rank: a_nx = getattr(kpt_u[u], name) if subset is not None: a_nx = a_nx[subset] # Domain master send this to the global master if self.gd.comm.rank == 0: if self.band_comm.size == 1: if kpt_rank == 0: return a_nx else: self.kd.comm.ssend(a_nx, 0, 1301) else: b_nx = self.bd.collect(a_nx) if self.band_comm.rank == 0: if kpt_rank == 0: return b_nx else: self.kd.comm.ssend(b_nx, 0, 1301) elif self.world.rank == 0 and kpt_rank != 0: # Only used to determine shape and dtype of receiving buffer: a_nx = getattr(kpt_u[0], name) if subset is not None: a_nx = a_nx[subset] b_nx = np.zeros((self.bd.nbands,) + a_nx.shape[1:], dtype=a_nx.dtype) self.kd.comm.receive(b_nx, kpt_rank, 1301) return b_nx def collect_auxiliary(self, value, k, s, shape=1, dtype=float): """Helper method for collecting band-independent scalars/arrays. For the parallel case find the rank in kpt_comm that contains the (k,s) pair, for this rank, collect on the corresponding domain a full array on the domain master and send this to the global master.""" kpt_u = self.kpt_u kpt_rank, u = self.kd.get_rank_and_index(s, k) if self.kd.comm.rank == kpt_rank: if isinstance(value, str): a_o = getattr(kpt_u[u], value) else: a_o = value[u] # assumed list # Make sure data is a mutable object a_o = np.asarray(a_o) if a_o.dtype is not dtype: a_o = a_o.astype(dtype) # Domain master send this to the global master if self.gd.comm.rank == 0: if kpt_rank == 0: return a_o else: self.kd.comm.send(a_o, 0, 1302) elif self.world.rank == 0 and kpt_rank != 0: b_o = np.zeros(shape, dtype=dtype) self.kd.comm.receive(b_o, kpt_rank, 1302) return b_o def collect_projections(self, k, s): """Helper method for collecting projector overlaps across domains. For the parallel case find the rank in kpt_comm that contains the (k,s) pair, for this rank, send to the global master.""" kpt_rank, u = self.kd.get_rank_and_index(s, k) natoms = self.atom_partition.natoms nproj = sum([setup.ni for setup in self.setups]) if self.world.rank == 0: if kpt_rank == 0: P_ani = self.kpt_u[u].P_ani all_P_ni = np.empty((self.bd.nbands, nproj), self.dtype) for band_rank in range(self.band_comm.size): nslice = self.bd.get_slice(band_rank) i = 0 for a in range(natoms): ni = self.setups[a].ni if kpt_rank == 0 and band_rank == 0 and a in P_ani: P_ni = P_ani[a] else: P_ni = np.empty((self.bd.mynbands, ni), self.dtype) # XXX will fail with nonstandard communicator nesting world_rank = (self.atom_partition.rank_a[a] + kpt_rank * self.gd.comm.size * self.band_comm.size + band_rank * self.gd.comm.size) self.world.receive(P_ni, world_rank, 1303 + a) all_P_ni[nslice, i:i + ni] = P_ni i += ni assert i == nproj return all_P_ni elif self.kd.comm.rank == kpt_rank: # plain else works too... P_ani = self.kpt_u[u].P_ani for a in range(natoms): if a in P_ani: self.world.ssend(P_ani[a], 0, 1303 + a) def get_wave_function_array(self, n, k, s, realspace=True): """Return pseudo-wave-function array on master. n: int Global band index. k: int Global IBZ k-point index. s: int Spin index (0 or 1). realspace: bool Transform plane wave or LCAO expansion coefficients to real-space. For the parallel case find the ranks in kd.comm and bd.comm that contains to (n, k, s), and collect on the corresponding domain a full array on the domain master and send this to the global master.""" kpt_rank, u = self.kd.get_rank_and_index(s, k) band_rank, myn = self.bd.who_has(n) rank = self.world.rank if (self.kd.comm.rank == kpt_rank and self.band_comm.rank == band_rank): psit_G = self._get_wave_function_array(u, myn, realspace) if realspace: psit_G = self.gd.collect(psit_G) if rank == 0: return psit_G # Domain master send this to the global master if self.gd.comm.rank == 0: self.world.ssend(psit_G, 0, 1398) if rank == 0: # allocate full wave function and receive psit_G = self.empty(global_array=True, realspace=realspace) # XXX this will fail when using non-standard nesting # of communicators. world_rank = (kpt_rank * self.gd.comm.size * self.band_comm.size + band_rank * self.gd.comm.size) self.world.receive(psit_G, world_rank, 1398) return psit_G def read_projections(self, reader): nslice = self.bd.get_slice() for u, kpt in enumerate(self.kpt_u): P_nI = reader.get('Projections', kpt.s, kpt.k) I1 = 0 kpt.P_ani = {} for a, setup in enumerate(self.setups): I2 = I1 + setup.ni if self.gd.comm.rank == 0: kpt.P_ani[a] = np.array(P_nI[nslice, I1:I2], self.dtype) I1 = I2 gpaw-0.11.0.13004/gpaw/wavefunctions/fd.py0000664000175000017500000003167612553643470020265 0ustar jensjjensj00000000000000import numpy as np from gpaw.kpoint import KPoint from gpaw.mpi import serial_comm from gpaw.io import FileReference from gpaw.utilities.blas import axpy from gpaw.transformers import Transformer from gpaw.hs_operators import MatrixOperator from gpaw.preconditioner import Preconditioner from gpaw.fd_operators import Laplace, Gradient from gpaw.kpt_descriptor import KPointDescriptor from gpaw.wavefunctions.fdpw import FDPWWaveFunctions from gpaw.lfc import LocalizedFunctionsCollection as LFC class FD: name = 'fd' def __init__(self): pass # Could hold parameters like FD stencils def __call__(self, *args, **kwargs): return FDWaveFunctions(*args, **kwargs) class FDWaveFunctions(FDPWWaveFunctions): mode = 'fd' def __init__(self, stencil, diagksl, orthoksl, initksl, gd, nvalence, setups, bd, dtype, world, kd, kptband_comm, timer=None): FDPWWaveFunctions.__init__(self, diagksl, orthoksl, initksl, gd, nvalence, setups, bd, dtype, world, kd, kptband_comm, timer) # Kinetic energy operator: self.kin = Laplace(self.gd, -0.5, stencil, self.dtype) self.matrixoperator = MatrixOperator(self.orthoksl) self.taugrad_v = None # initialized by MGGA functional def empty(self, n=(), global_array=False, realspace=False, q=-1): return self.gd.empty(n, self.dtype, global_array) def integrate(self, a_xg, b_yg=None, global_integral=True): return self.gd.integrate(a_xg, b_yg, global_integral) def bytes_per_wave_function(self): return self.gd.bytecount(self.dtype) def set_setups(self, setups): self.pt = LFC(self.gd, [setup.pt_j for setup in setups], self.kd, dtype=self.dtype, forces=True) FDPWWaveFunctions.set_setups(self, setups) def set_positions(self, spos_ac, atom_partition=None): FDPWWaveFunctions.set_positions(self, spos_ac, atom_partition) def summary(self, fd): fd.write('Wave functions: Uniform real-space grid\n') fd.write('Kinetic energy operator: %s\n' % self.kin.description) def make_preconditioner(self, block=1): return Preconditioner(self.gd, self.kin, self.dtype, block) def apply_pseudo_hamiltonian(self, kpt, hamiltonian, psit_xG, Htpsit_xG): self.timer.start('Apply hamiltonian') self.kin.apply(psit_xG, Htpsit_xG, kpt.phase_cd) hamiltonian.apply_local_potential(psit_xG, Htpsit_xG, kpt.s) self.timer.stop('Apply hamiltonian') def add_orbital_density(self, nt_G, kpt, n): if self.dtype == float: axpy(1.0, kpt.psit_nG[n]**2, nt_G) else: axpy(1.0, kpt.psit_nG[n].real**2, nt_G) axpy(1.0, kpt.psit_nG[n].imag**2, nt_G) def add_to_density_from_k_point_with_occupation(self, nt_sG, kpt, f_n): # Used in calculation of response part of GLLB-potential nt_G = nt_sG[kpt.s] if self.dtype == float: for f, psit_G in zip(f_n, kpt.psit_nG): axpy(f, psit_G**2, nt_G) else: for f, psit_G in zip(f_n, kpt.psit_nG): axpy(f, psit_G.real**2, nt_G) axpy(f, psit_G.imag**2, nt_G) # Hack used in delta-scf calculations: if hasattr(kpt, 'c_on'): assert self.bd.comm.size == 1 d_nn = np.zeros((self.bd.mynbands, self.bd.mynbands), dtype=complex) for ne, c_n in zip(kpt.ne_o, kpt.c_on): d_nn += ne * np.outer(c_n.conj(), c_n) for d_n, psi0_G in zip(d_nn, kpt.psit_nG): for d, psi_G in zip(d_n, kpt.psit_nG): if abs(d) > 1.e-12: nt_G += (psi0_G.conj() * d * psi_G).real def calculate_kinetic_energy_density(self): if self.taugrad_v is None: self.taugrad_v = [ Gradient(self.gd, v, n=3, dtype=self.dtype).apply for v in range(3)] assert not hasattr(self.kpt_u[0], 'c_on') if self.kpt_u[0].psit_nG is None: raise RuntimeError('No wavefunctions yet') if isinstance(self.kpt_u[0].psit_nG, FileReference): # XXX initialize raise RuntimeError('Wavefunctions have not been initialized.') taut_sG = self.gd.zeros(self.nspins) dpsit_G = self.gd.empty(dtype=self.dtype) for kpt in self.kpt_u: for f, psit_G in zip(kpt.f_n, kpt.psit_nG): for v in range(3): self.taugrad_v[v](psit_G, dpsit_G, kpt.phase_cd) axpy(0.5 * f, abs(dpsit_G)**2, taut_sG[kpt.s]) self.kd.comm.sum(taut_sG) self.band_comm.sum(taut_sG) return taut_sG def apply_mgga_orbital_dependent_hamiltonian(self, kpt, psit_xG, Htpsit_xG, dH_asp, dedtaut_G): a_G = self.gd.empty(dtype=psit_xG.dtype) for psit_G, Htpsit_G in zip(psit_xG, Htpsit_xG): for v in range(3): self.taugrad_v[v](psit_G, a_G, kpt.phase_cd) self.taugrad_v[v](dedtaut_G * a_G, a_G, kpt.phase_cd) axpy(-0.5, a_G, Htpsit_G) def ibz2bz(self, atoms): """Transform wave functions in IBZ to the full BZ.""" assert self.kd.comm.size == 1 # New k-point descriptor for full BZ: kd = KPointDescriptor(self.kd.bzk_kc, nspins=self.nspins) #kd.set_symmetry(atoms, self.setups, enabled=False) kd.set_communicator(serial_comm) self.pt = LFC(self.gd, [setup.pt_j for setup in self.setups], kd, dtype=self.dtype) self.pt.set_positions(atoms.get_scaled_positions()) self.initialize_wave_functions_from_restart_file() weight = 2.0 / kd.nspins / kd.nbzkpts # Build new list of k-points: kpt_u = [] for s in range(self.nspins): for k in range(kd.nbzkpts): # Index of symmetry related point in the IBZ ik = self.kd.bz2ibz_k[k] r, u = self.kd.get_rank_and_index(s, ik) assert r == 0 kpt = self.kpt_u[u] phase_cd = np.exp(2j * np.pi * self.gd.sdisp_cd * kd.bzk_kc[k, :, np.newaxis]) # New k-point: kpt2 = KPoint(weight, s, k, k, phase_cd) kpt2.f_n = kpt.f_n / kpt.weight / kd.nbzkpts * 2 / self.nspins kpt2.eps_n = kpt.eps_n.copy() # Transform wave functions using symmetry operation: Psit_nG = self.gd.collect(kpt.psit_nG) if Psit_nG is not None: Psit_nG = Psit_nG.copy() for Psit_G in Psit_nG: Psit_G[:] = self.kd.transform_wave_function(Psit_G, k) kpt2.psit_nG = self.gd.empty(self.bd.nbands, dtype=self.dtype) self.gd.distribute(Psit_nG, kpt2.psit_nG) # Calculate PAW projections: kpt2.P_ani = self.pt.dict(len(kpt.psit_nG)) self.pt.integrate(kpt2.psit_nG, kpt2.P_ani, k) kpt_u.append(kpt2) self.kd = kd self.kpt_u = kpt_u def write(self, writer, write_wave_functions=False): writer['Mode'] = 'fd' if not write_wave_functions: return writer.add('PseudoWaveFunctions', ('nspins', 'nibzkpts', 'nbands', 'ngptsx', 'ngptsy', 'ngptsz'), dtype=self.dtype) if hasattr(writer, 'hdf5'): parallel = (self.world.size > 1) for kpt in self.kpt_u: indices = [kpt.s, kpt.k] indices.append(self.bd.get_slice()) indices += self.gd.get_slice() writer.fill(kpt.psit_nG, parallel=parallel, *indices) else: for s in range(self.nspins): for k in range(self.kd.nibzkpts): for n in range(self.bd.nbands): psit_G = self.get_wave_function_array(n, k, s) writer.fill(psit_G, s, k, n) def read(self, reader, hdf5): if ((not hdf5 and self.bd.comm.size == 1) or (hdf5 and self.world.size == 1)): # We may not be able to keep all the wave # functions in memory - so psit_nG will be a special type of # array that is really just a reference to a file: for kpt in self.kpt_u: kpt.psit_nG = reader.get_reference('PseudoWaveFunctions', (kpt.s, kpt.k)) else: for kpt in self.kpt_u: kpt.psit_nG = self.empty(self.bd.mynbands) if hdf5: indices = [kpt.s, kpt.k] indices.append(self.bd.get_slice()) indices += self.gd.get_slice() reader.get('PseudoWaveFunctions', out=kpt.psit_nG, parallel=(self.world.size > 1), *indices) else: # Read band by band to save memory for myn, psit_G in enumerate(kpt.psit_nG): n = self.bd.global_index(myn) if self.gd.comm.rank == 0: big_psit_G = np.array( reader.get('PseudoWaveFunctions', kpt.s, kpt.k, n), self.dtype) else: big_psit_G = None self.gd.distribute(big_psit_G, psit_G) def initialize_from_lcao_coefficients(self, basis_functions, mynbands): for kpt in self.kpt_u: kpt.psit_nG = self.gd.zeros(self.bd.mynbands, self.dtype) basis_functions.lcao_to_grid(kpt.C_nM, kpt.psit_nG[:mynbands], kpt.q) kpt.C_nM = None def random_wave_functions(self, nao): """Generate random wave functions.""" gpts = self.gd.N_c[0] * self.gd.N_c[1] * self.gd.N_c[2] if self.bd.nbands < gpts / 64: gd1 = self.gd.coarsen() gd2 = gd1.coarsen() psit_G1 = gd1.empty(dtype=self.dtype) psit_G2 = gd2.empty(dtype=self.dtype) interpolate2 = Transformer(gd2, gd1, 1, self.dtype).apply interpolate1 = Transformer(gd1, self.gd, 1, self.dtype).apply shape = tuple(gd2.n_c) scale = np.sqrt(12 / abs(np.linalg.det(gd2.cell_cv))) old_state = np.random.get_state() np.random.seed(4 + self.world.rank) for kpt in self.kpt_u: for psit_G in kpt.psit_nG[nao:]: if self.dtype == float: psit_G2[:] = (np.random.random(shape) - 0.5) * scale else: psit_G2.real = (np.random.random(shape) - 0.5) * scale psit_G2.imag = (np.random.random(shape) - 0.5) * scale interpolate2(psit_G2, psit_G1, kpt.phase_cd) interpolate1(psit_G1, psit_G, kpt.phase_cd) np.random.set_state(old_state) elif gpts / 64 <= self.bd.nbands < gpts / 8: gd1 = self.gd.coarsen() psit_G1 = gd1.empty(dtype=self.dtype) interpolate1 = Transformer(gd1, self.gd, 1, self.dtype).apply shape = tuple(gd1.n_c) scale = np.sqrt(12 / abs(np.linalg.det(gd1.cell_cv))) old_state = np.random.get_state() np.random.seed(4 + self.world.rank) for kpt in self.kpt_u: for psit_G in kpt.psit_nG[nao:]: if self.dtype == float: psit_G1[:] = (np.random.random(shape) - 0.5) * scale else: psit_G1.real = (np.random.random(shape) - 0.5) * scale psit_G1.imag = (np.random.random(shape) - 0.5) * scale interpolate1(psit_G1, psit_G, kpt.phase_cd) np.random.set_state(old_state) else: shape = tuple(self.gd.n_c) scale = np.sqrt(12 / abs(np.linalg.det(self.gd.cell_cv))) old_state = np.random.get_state() np.random.seed(4 + self.world.rank) for kpt in self.kpt_u: for psit_G in kpt.psit_nG[nao:]: if self.dtype == float: psit_G[:] = (np.random.random(shape) - 0.5) * scale else: psit_G.real = (np.random.random(shape) - 0.5) * scale psit_G.imag = (np.random.random(shape) - 0.5) * scale np.random.set_state(old_state) def estimate_memory(self, mem): FDPWWaveFunctions.estimate_memory(self, mem) gpaw-0.11.0.13004/gpaw/wavefunctions/__init__.py0000664000175000017500000000000012553643470021404 0ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/rotation.py0000664000175000017500000000332012553643470016621 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. from math import sqrt, cos, sin import numpy as np from gpaw.spherical_harmonics import Y s = sqrt(0.5) t = sqrt(3) / 3 # Points on the unit sphere: sphere_lm = [ \ np.array([(1, 0, 0)]), # s np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1)]), # p np.array([(s, s, 0), (0, s, s), (s, 0, s), (1, 0, 0), (0, 0, 1)]), # d np.array([(s, s, 0), (0, s, s), (s, 0, s), (1, 0, 0), (s, -s, 0), (t, -t, t), (t, t, -t)])] # f def Y_matrix(l, U_vv): """YMatrix(l, symmetry) -> matrix. For 2*l+1 points on the unit sphere (m1=0,...,2*l) calculate the value of Y_lm2 for m2=0,...,2*l. The points are those from the list sphere_lm[l] rotated as described by U_vv.""" Y_mm = np.zeros((2 * l + 1, 2 * l + 1)) for m1, point in enumerate(sphere_lm[l]): x, y, z = np.dot(point, U_vv) for m2 in range(2 * l + 1): L = l**2 + m2 Y_mm[m1, m2] = Y(L, x, y, z) return Y_mm identity = np.eye(3) iY_lmm = [np.linalg.inv(Y_matrix(l, identity)) for l in range(4)] def rotation(l, U_vv): """Rotation(l, symmetry) -> transformation matrix. Find the transformation from Y_lm1 to Y_lm2.""" return np.dot(iY_lmm[l], Y_matrix(l, U_vv)) def Y_rotation(l, angle): Y_mm = np.zeros((2 * l + 1, 2 * l + 1)) sn = sin(angle) cs = cos(angle) for m1, point in enumerate(sphere_lm[l]): x = point[0] y = cs * point[1] - sn * point[2] z = sn * point[1] + cs * point[2] for m2 in range(2 * l + 1): L = l**2 + m2 Y_mm[m1, m2] = Y(L, x, y, z) return Y_mm del s, identity gpaw-0.11.0.13004/gpaw/poisson.py0000664000175000017500000005642212553643472016471 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. from math import pi import warnings import numpy as np from numpy.fft import fftn, ifftn, fft2, ifft2 from gpaw.transformers import Transformer from gpaw.fd_operators import Laplace, LaplaceA, LaplaceB from gpaw import PoissonConvergenceError from gpaw.utilities.blas import axpy from gpaw.utilities.gauss import Gaussian from gpaw.utilities.ewald import madelung from gpaw.utilities.tools import construct_reciprocal import _gpaw POISSON_GRID_WARNING="""Grid unsuitable for Poisson solver! The Poisson solver does not have sufficient multigrid levels for good performance and will converge inefficiently if at all, or yield wrong results. You may need to manually specify a grid such that the number of points along each direction is divisible by a high power of 2, such as 8, 16, or 32 depending on system size; examples: GPAW(gpts=(32, 32, 288)) or from gpaw.tools import h2gpts GPAW(gpts=h2gpts(0.2, atoms.get_cell(), idiv=16)) Parallelizing over very small domains can also undesirably limit the number of multigrid levels even if the total number of grid points is divisible by a high power of 2.""" class PoissonSolver: def __init__(self, nn=3, relax='J', eps=2e-10, maxiter=1000, remove_moment=None, use_charge_center=False): self.relax = relax self.nn = nn self.eps = eps self.charged_periodic_correction = None self.maxiter = maxiter self.remove_moment = remove_moment self.use_charge_center = use_charge_center # Relaxation method if relax == 'GS': # Gauss-Seidel self.relax_method = 1 elif relax == 'J': # Jacobi self.relax_method = 2 else: raise NotImplementedError('Relaxation method %s' % relax) self.description = None def get_stencil(self): return self.nn def set_grid_descriptor(self, gd): # Should probably be renamed initialize self.gd = gd scale = -0.25 / pi if self.nn == 'M': if not gd.orthogonal: raise RuntimeError('Cannot use Mehrstellen stencil with ' 'non orthogonal cell.') self.operators = [LaplaceA(gd, -scale)] self.B = LaplaceB(gd) else: self.operators = [Laplace(gd, scale, self.nn)] self.B = None self.interpolators = [] self.restrictors = [] level = 0 self.presmooths = [2] self.postsmooths = [1] # Weights for the relaxation, # only used if 'J' (Jacobi) is chosen as method self.weights = [2.0 / 3.0] while level < 8: try: gd2 = gd.coarsen() except ValueError: break self.operators.append(Laplace(gd2, scale, 1)) self.interpolators.append(Transformer(gd2, gd)) self.restrictors.append(Transformer(gd, gd2)) self.presmooths.append(4) self.postsmooths.append(4) self.weights.append(1.0) level += 1 gd = gd2 self.levels = level if self.operators[-1].gd.N_c.max() > 36: # Try to warn exactly once no matter how one uses the solver. if gd.comm.parent is None: warn = (gd.comm.rank == 0) else: warn = (gd.comm.parent.rank == 0) if warn: warntxt = '\n'.join([POISSON_GRID_WARNING, '', self.get_description()]) else: warntxt = ('Poisson warning from domain rank %d' % self.gd.comm.rank) # Warn from all ranks to avoid deadlocks. warnings.warn(warntxt, stacklevel=2) def get_description(self): name = {1: 'Gauss-Seidel', 2: 'Jacobi'}[self.relax_method] coarsest_grid = self.operators[-1].gd.N_c coarsest_grid_string = ' x '.join([str(N) for N in coarsest_grid]) assert self.levels + 1 == len(self.operators) lines = ['%s solver with %d multi-grid levels' % (name, self.levels + 1), ' Coarsest grid: %s points' % coarsest_grid_string] if coarsest_grid.max() > 24: # This friendly warning has lower threshold than the big long # one that we print when things are really bad. lines.extend([' Warning: Coarse grid has more than 24 points.', ' More multi-grid levels recommended.']) lines.extend([' Stencil: %s' % self.operators[0].description, ' Tolerance: %e' % self.eps, ' Max iterations: %d' % self.maxiter]) if self.remove_moment is not None: lines.append(' Remove moments up to L=%d' % self.remove_moment) if self.use_charge_center: lines.append(' Compensate for charged system using center of ' 'majority charge') return '\n'.join(lines) def initialize(self, load_gauss=False): # Should probably be renamed allocate gd = self.gd self.rhos = [gd.empty()] self.phis = [None] self.residuals = [gd.empty()] for level in range(self.levels): gd2 = gd.coarsen() self.phis.append(gd2.empty()) self.rhos.append(gd2.empty()) self.residuals.append(gd2.empty()) gd = gd2 assert len(self.phis) == len(self.rhos) level += 1 assert level == self.levels self.step = 0.66666666 / self.operators[0].get_diagonal_element() self.presmooths[level] = 8 self.postsmooths[level] = 8 if load_gauss: self.load_gauss() def load_gauss(self, center=None): if not hasattr(self, 'rho_gauss') or center is not None: gauss = Gaussian(self.gd, center=center) self.rho_gauss = gauss.get_gauss(0) self.phi_gauss = gauss.get_gauss_pot(0) def solve(self, phi, rho, charge=None, eps=None, maxcharge=1e-6, zero_initial_phi=False): if eps is None: eps = self.eps actual_charge = self.gd.integrate(rho) background = (actual_charge / self.gd.dv / self.gd.get_size_of_global_array().prod()) if self.remove_moment: assert not self.gd.pbc_c.any() if not hasattr(self, 'gauss'): self.gauss = Gaussian(self.gd) rho_neutral = rho.copy() phi_cor_L = [] for L in range(self.remove_moment): phi_cor_L.append(self.gauss.remove_moment(rho_neutral, L)) # Remove multipoles for better initial guess for phi_cor in phi_cor_L: phi -= phi_cor niter = self.solve_neutral(phi, rho_neutral, eps=eps) # correct error introduced by removing multipoles for phi_cor in phi_cor_L: phi += phi_cor return niter if charge is None: charge = actual_charge if abs(charge) <= maxcharge: # System is charge neutral. Use standard solver return self.solve_neutral(phi, rho - background, eps=eps) elif abs(charge) > maxcharge and self.gd.pbc_c.all(): # System is charged and periodic. Subtract a homogeneous # background charge # Set initial guess for potential if zero_initial_phi: phi[:] = 0.0 iters = self.solve_neutral(phi, rho - background, eps=eps) return iters elif abs(charge) > maxcharge and not self.gd.pbc_c.any(): # The system is charged and in a non-periodic unit cell. # Determine the potential by 1) subtract a gaussian from the # density, 2) determine potential from the neutralized density # and 3) add the potential from the gaussian density. # Load necessary attributes # use_charge_center: The monopole will be removed at the # center of the majority charge, which prevents artificial # dipoles. # Due to the shape of the Gaussian and it's Fourier-Transform, # the Gaussian representing the charge should stay at least # 7 gpts from the borders - see: # https://listserv.fysik.dtu.dk/pipermail/gpaw-developers/2015-July/005806.html if self.use_charge_center: charge_sign = actual_charge / abs(actual_charge) rho_sign = rho * charge_sign rho_sign[np.where(rho_sign < 0)] = 0 absolute_charge = self.gd.integrate(rho_sign) center = - self.gd.calculate_dipole_moment(rho_sign) \ / absolute_charge border_offset = np.inner(self.gd.h_cv, np.array((7, 7, 7))) borders = np.inner(self.gd.h_cv, self.gd.N_c) borders -= border_offset if np.any(center > borders) or np.any(center < border_offset): raise RuntimeError( 'Poisson solver: center of charge outside' + \ ' borders - please increase box') center[np.where(center > borders)] = borders self.load_gauss(center=center) else: self.load_gauss() # Remove monopole moment q = actual_charge / np.sqrt(4 * pi) # Monopole moment rho_neutral = rho - q * self.rho_gauss # neutralized density # Set initial guess for potential if zero_initial_phi: phi[:] = 0.0 else: axpy(-q, self.phi_gauss, phi) # phi -= q * self.phi_gauss # Determine potential from neutral density using standard solver niter = self.solve_neutral(phi, rho_neutral, eps=eps) # correct error introduced by removing monopole axpy(q, self.phi_gauss, phi) # phi += q * self.phi_gauss return niter else: # System is charged with mixed boundaryconditions msg = ('Charged systems with mixed periodic/zero' ' boundary conditions') raise NotImplementedError(msg) def solve_neutral(self, phi, rho, eps=2e-10): self.phis[0] = phi if self.B is None: self.rhos[0][:] = rho else: self.B.apply(rho, self.rhos[0]) niter = 1 maxiter = self.maxiter while self.iterate2(self.step) > eps and niter < maxiter: niter += 1 if niter == maxiter: msg = 'Poisson solver did not converge in %d iterations!' % maxiter raise PoissonConvergenceError(msg) # Set the average potential to zero in periodic systems if np.alltrue(self.gd.pbc_c): phi_ave = self.gd.comm.sum(np.sum(phi.ravel())) N_c = self.gd.get_size_of_global_array() phi_ave /= np.product(N_c) phi -= phi_ave return niter def iterate(self, step, level=0): residual = self.residuals[level] niter = 0 while True: niter += 1 if level > 0 and niter == 1: residual[:] = -self.rhos[level] else: self.operators[level].apply(self.phis[level], residual) residual -= self.rhos[level] error = self.gd.comm.sum(np.vdot(residual, residual)) if niter == 1 and level < self.levels: self.restrictors[level].apply(residual, self.rhos[level + 1]) self.phis[level + 1][:] = 0.0 self.iterate(4.0 * step, level + 1) self.interpolators[level].apply(self.phis[level + 1], residual) self.phis[level] -= residual continue residual *= step self.phis[level] -= residual if niter == 2: break return error def iterate2(self, step, level=0): """Smooths the solution in every multigrid level""" residual = self.residuals[level] if level < self.levels: self.operators[level].relax(self.relax_method, self.phis[level], self.rhos[level], self.presmooths[level], self.weights[level]) self.operators[level].apply(self.phis[level], residual) residual -= self.rhos[level] self.restrictors[level].apply(residual, self.rhos[level + 1]) self.phis[level + 1][:] = 0.0 self.iterate2(4.0 * step, level + 1) self.interpolators[level].apply(self.phis[level + 1], residual) self.phis[level] -= residual self.operators[level].relax(self.relax_method, self.phis[level], self.rhos[level], self.postsmooths[level], self.weights[level]) if level == 0: self.operators[level].apply(self.phis[level], residual) residual -= self.rhos[level] error = self.gd.comm.sum(np.dot(residual.ravel(), residual.ravel())) * self.gd.dv return error def estimate_memory(self, mem): # XXX Memory estimate works only for J and GS, not FFT solver # Poisson solver appears to use same amount of memory regardless # of whether it's J or GS, which is a bit strange gdbytes = self.gd.bytecount() nbytes = -gdbytes # No phi on finest grid, compensate ahead for level in range(self.levels): nbytes += 3 * gdbytes # Arrays: rho, phi, residual gdbytes //= 8 mem.subnode('rho, phi, residual [%d levels]' % self.levels, nbytes) def __repr__(self): template = 'PoissonSolver(relax=\'%s\', nn=%s, eps=%e)' representation = template % (self.relax, repr(self.nn), self.eps) return representation class NoInteractionPoissonSolver: relax_method = 0 nn = 1 def get_description(self): return 'No interaction' def get_stencil(self): return 1 def solve(self, phi, rho, charge): return 0 def set_grid_descriptor(self, gd): pass def initialize(self): pass class FFTPoissonSolver(PoissonSolver): """FFT Poisson solver for general unit cells.""" relax_method = 0 nn = 999 def __init__(self, eps=2e-10): self.charged_periodic_correction = None self.remove_moment = None self.eps = eps def get_description(self): return 'FFT' def set_grid_descriptor(self, gd): assert gd.pbc_c.all() self.gd = gd def initialize(self): if self.gd.comm.rank == 0: self.k2_Q, self.N3 = construct_reciprocal(self.gd) def solve_neutral(self, phi_g, rho_g, eps=None): if self.gd.comm.size == 1: phi_g[:] = ifftn(fftn(rho_g) * 4.0 * pi / self.k2_Q).real else: rho_g = self.gd.collect(rho_g) if self.gd.comm.rank == 0: globalphi_g = ifftn(fftn(rho_g) * 4.0 * pi / self.k2_Q).real else: globalphi_g = None self.gd.distribute(globalphi_g, phi_g) return 1 class FixedBoundaryPoissonSolver(PoissonSolver): """Solve the Poisson equation with FFT in two directions, and with central differential method in the third direction.""" def __init__(self, nn=1): # XXX How can this work when it does not call __init___ # on PoissonSolver? -askhl self.nn = nn self.charged_periodic_correction = None assert self.nn == 1 def set_grid_descriptor(self, gd): assert gd.pbc_c.all() assert gd.orthogonal self.gd = gd def initialize(self, b_phi1, b_phi2): distribution = np.zeros([self.gd.comm.size], int) if self.gd.comm.rank == 0: gd = self.gd N_c1 = gd.N_c[:2, np.newaxis] i_cq = np.indices(gd.N_c[:2]).reshape((2, -1)) i_cq += N_c1 // 2 i_cq %= N_c1 i_cq -= N_c1 // 2 B_vc = 2.0 * np.pi * gd.icell_cv.T[:2, :2] k_vq = np.dot(B_vc, i_cq) k_vq *= k_vq k_vq2 = np.sum(k_vq, axis=0) k_vq2 = k_vq2.reshape(-1) b_phi1 = fft2(b_phi1, None, (0, 1)) b_phi2 = fft2(b_phi2, None, (0, 1)) b_phi1 = b_phi1[:, :, -1].reshape(-1) b_phi2 = b_phi2[:, :, 0].reshape(-1) loc_b_phi1 = np.array_split(b_phi1, self.gd.comm.size) loc_b_phi2 = np.array_split(b_phi2, self.gd.comm.size) loc_k_vq2 = np.array_split(k_vq2, self.gd.comm.size) self.loc_b_phi1 = loc_b_phi1[0] self.loc_b_phi2 = loc_b_phi2[0] self.k_vq2 = loc_k_vq2[0] for i in range(self.gd.comm.size): distribution[i] = len(loc_b_phi1[i]) self.gd.comm.broadcast(distribution, 0) for i in range(1, self.gd.comm.size): self.gd.comm.ssend(loc_b_phi1[i], i, 135) self.gd.comm.ssend(loc_b_phi2[i], i, 246) self.gd.comm.ssend(loc_k_vq2[i], i, 169) else: self.gd.comm.broadcast(distribution, 0) self.loc_b_phi1 = np.zeros([distribution[self.gd.comm.rank]], dtype=complex) self.loc_b_phi2 = np.zeros([distribution[self.gd.comm.rank]], dtype=complex) self.k_vq2 = np.zeros([distribution[self.gd.comm.rank]]) self.gd.comm.receive(self.loc_b_phi1, 0, 135) self.gd.comm.receive(self.loc_b_phi2, 0, 246) self.gd.comm.receive(self.k_vq2, 0, 169) k_distribution = np.arange(np.sum(distribution)) self.k_distribution = np.array_split(k_distribution, self.gd.comm.size) self.d1, self.d2, self.d3 = self.gd.N_c self.r_distribution = np.array_split(np.arange(self.d3), self.gd.comm.size) self.comm_reshape = not (self.gd.parsize_c[0] == 1 and self.gd.parsize_c[1] == 1) def solve(self, phi_g, rho_g, charge=None): if charge is None: actual_charge = self.gd.integrate(rho_g) else: actual_charge = charge if self.charged_periodic_correction is None: self.charged_periodic_correction = madelung(self.gd.cell_cv) background = (actual_charge / self.gd.dv / self.gd.get_size_of_global_array().prod()) self.solve_neutral(phi_g, rho_g - background) phi_g += actual_charge * self.charged_periodic_correction def scatter_r_distribution(self, global_rho_g, dtype=float): d1 = self.d1 d2 = self.d2 comm = self.gd.comm index = self.r_distribution[comm.rank] if comm.rank == 0: rho_g1 = global_rho_g[:, :, index] for i in range(1, comm.size): ind = self.r_distribution[i] comm.ssend(global_rho_g[:, :, ind].copy(), i, 178) else: rho_g1 = np.zeros([d1, d2, len(index)], dtype=dtype) comm.receive(rho_g1, 0, 178) return rho_g1 def gather_r_distribution(self, rho_g, dtype=complex): comm = self.gd.comm index = self.r_distribution[comm.rank] d1, d2, d3 = self.d1, self.d2, self.d3 if comm.rank == 0: global_rho_g = np.zeros([d1, d2, d3], dtype) global_rho_g[:, :, index] = rho_g for i in range(1, comm.size): ind = self.r_distribution[i] rho_gi = np.zeros([d1, d2, len(ind)], dtype) comm.receive(rho_gi, i, 368) global_rho_g[:, :, ind] = rho_gi else: comm.ssend(rho_g, 0, 368) global_rho_g = None return global_rho_g def scatter_k_distribution(self, global_rho_g): comm = self.gd.comm index = self.k_distribution[comm.rank] if comm.rank == 0: rho_g = global_rho_g[index] for i in range(1, comm.size): ind = self.k_distribution[i] comm.ssend(global_rho_g[ind], i, 370) else: rho_g = np.zeros([len(index), self.d3], dtype=complex) comm.receive(rho_g, 0, 370) return rho_g def gather_k_distribution(self, phi_g): comm = self.gd.comm index = self.k_distribution[comm.rank] d12 = self.d1 * self.d2 if comm.rank == 0: global_phi_g = np.zeros([d12, self.d3], dtype=complex) global_phi_g[index] = phi_g for i in range(1, comm.size): ind = self.k_distribution[i] phi_gi = np.zeros([len(ind), self.d3], dtype=complex) comm.receive(phi_gi, i, 569) global_phi_g[ind] = phi_gi else: comm.ssend(phi_g, 0, 569) global_phi_g = None return global_phi_g def solve_neutral(self, phi_g, rho_g): # b_phi1 and b_phi2 are the boundary Hartree potential values # of left and right sides if self.comm_reshape: global_rho_g0 = self.gd.collect(rho_g) rho_g1 = self.scatter_r_distribution(global_rho_g0) else: rho_g1 = rho_g # use copy() to avoid the C_contiguous=False rho_g2 = fft2(rho_g1, None, (0, 1)).copy() global_rho_g = self.gather_r_distribution(rho_g2) if self.gd.comm.rank == 0: global_rho_g.shape = (self.d1 * self.d2, self.d3) rho_g3 = self.scatter_k_distribution(global_rho_g) du0 = np.zeros(self.d3 - 1, dtype=complex) du20 = np.zeros(self.d3 - 2, dtype=complex) h2 = self.gd.h_cv[2, 2] ** 2 phi_g1 = np.zeros(rho_g3.shape, dtype=complex) index = self.k_distribution[self.gd.comm.rank] for phi, rho, rv2, bp1, bp2, i in zip(phi_g1, rho_g3, self.k_vq2, self.loc_b_phi1, self.loc_b_phi2, range(len(index))): A = np.zeros(self.d3, dtype=complex) + 2 + h2 * rv2 phi = rho * np.pi * 4 * h2 phi[0] += bp1 phi[-1] += bp2 du = du0 - 1 dl = du0 - 1 du2 = du20 - 1 _gpaw.linear_solve_tridiag(self.d3, A, du, dl, du2, phi) phi_g1[i] = phi global_phi_g = self.gather_k_distribution(phi_g1) if self.gd.comm.rank == 0: global_phi_g.shape = (self.d1, self.d2, self.d3) phi_g2 = self.scatter_r_distribution(global_phi_g, dtype=complex) # use copy() to avoid the C_contiguous=False phi_g3 = ifft2(phi_g2, None, (0, 1)).real.copy() if self.comm_reshape: global_phi_g = self.gather_r_distribution(phi_g3, dtype=float) self.gd.distribute(global_phi_g, phi_g) else: phi_g[:] = phi_g3 gpaw-0.11.0.13004/gpaw/sphere/0000775000175000017500000000000012553644063015677 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/sphere/lebedev.py0000664000175000017500000006674512553643472017704 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. from __future__ import print_function import numpy as np def run(): from gpaw.spherical_harmonics import Y weight_n = np.zeros(50) Y_nL = np.zeros((50, 25)) R_nv = np.zeros((50, 3)) # We use 50 Lebedev quadrature points which will integrate # spherical harmonics correctly for l < 12: n = 0 for v in [0, 1, 2]: for s in [-1, 1]: R_nv[n, v] = s n += 1 C = 2**-0.5 for v1 in [0, 1, 2]: v2 = (v1 + 1) % 3 v3 = (v1 + 2) % 3 for s1 in [-1, 1]: for s2 in [-1, 1]: R_nv[n, v2] = s1 * C R_nv[n, v3] = s2 * C n += 1 C = 3**-0.5 for s1 in [-1, 1]: for s2 in [-1, 1]: for s3 in [-1, 1]: R_nv[n] = (s1 * C, s2 * C, s3 * C) n += 1 C1 = 0.30151134457776357 C2 = (1.0 - 2.0 * C1**2)**0.5 for v1 in [0, 1, 2]: v2 = (v1 + 1) % 3 v3 = (v1 + 2) % 3 for s1 in [-1, 1]: for s2 in [-1, 1]: for s3 in [-1, 1]: R_nv[n, v1] = s1 * C2 R_nv[n, v2] = s2 * C1 R_nv[n, v3] = s3 * C1 n += 1 assert n == 50 weight_n[0:6] = 0.01269841269841270 weight_n[6:18] = 0.02257495590828924 weight_n[18:26] = 0.02109375000000000 weight_n[26:50] = 0.02017333553791887 n = 0 for x, y, z in R_nv: Y_nL[n] = [Y(L, x, y, z) for L in range(25)] n += 1 # Write all 50 points to an xyz file as 50 hydrogen atoms: f = open('50.xyz', 'w') f.write('50\n\n') for x, y, z in R_nv: print('H', 4 * x, 4 * y, 4 * z, file=f) #print np.dot(weights, Y_nL) * (4*pi)**.5 print('weight_n = np.array(%s)' % weight_n.tolist()) print('Y_nL = np.array(%s)' % Y_nL.tolist()) print('R_nv = np.array(%s)' % R_nv.tolist()) return weight_n, Y_nL, R_nv if __name__ == '__main__': run() weight_n = np.array([0.0126984126984127, 0.0126984126984127, 0.0126984126984127, 0.0126984126984127, 0.0126984126984127, 0.0126984126984127, 0.02257495590828924, 0.02257495590828924, 0.02257495590828924, 0.02257495590828924, 0.02257495590828924, 0.02257495590828924, 0.02257495590828924, 0.02257495590828924, 0.02257495590828924, 0.02257495590828924, 0.02257495590828924, 0.02257495590828924, 0.021093750000000001, 0.021093750000000001, 0.021093750000000001, 0.021093750000000001, 0.021093750000000001, 0.021093750000000001, 0.021093750000000001, 0.021093750000000001, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887, 0.02017333553791887]) Y_nL = np.array([[0.28209479177387814, 0.0, 0.0, -0.48860251190291992, 0.0, 0.0, -0.31539156525252005, 0.0, 0.54627421529603959, 0.0, 0.0, 0.0, 0.0, 0.45704579946446577, 0.0, -0.59004358992664352, 0.0, 0.0, 0.0, 0.0, 0.31735664074561293, 0.0, -0.47308734787878004, 0.0, 0.62583573544917614], [0.28209479177387814, 0.0, 0.0, 0.48860251190291992, 0.0, 0.0, -0.31539156525252005, 0.0, 0.54627421529603959, 0.0, 0.0, 0.0, 0.0, -0.45704579946446577, 0.0, 0.59004358992664352, 0.0, 0.0, 0.0, 0.0, 0.31735664074561293, 0.0, -0.47308734787878004, 0.0, 0.62583573544917614], [0.28209479177387814, -0.48860251190291992, 0.0, 0.0, 0.0, 0.0, -0.31539156525252005, 0.0, -0.54627421529603959, 0.59004358992664352, 0.0, 0.45704579946446577, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.31735664074561293, 0.0, 0.47308734787878004, 0.0, 0.62583573544917614], [0.28209479177387814, 0.48860251190291992, 0.0, 0.0, 0.0, 0.0, -0.31539156525252005, 0.0, -0.54627421529603959, -0.59004358992664352, 0.0, -0.45704579946446577, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.31735664074561293, 0.0, 0.47308734787878004, 0.0, 0.62583573544917614], [0.28209479177387814, 0.0, -0.48860251190291992, 0.0, 0.0, 0.0, 0.63078313050504009, 0.0, 0.0, 0.0, 0.0, 0.0, -0.7463526651802308, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.84628437532163447, 0.0, 0.0, 0.0, 0.0], [0.28209479177387814, 0.0, 0.48860251190291992, 0.0, 0.0, 0.0, 0.63078313050504009, 0.0, 0.0, 0.0, 0.0, 0.0, 0.7463526651802308, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.84628437532163447, 0.0, 0.0, 0.0, 0.0], [0.28209479177387814, -0.3454941494713355, -0.3454941494713355, 0.0, 0.0, 0.54627421529603959, 0.15769578262626005, 0.0, -0.27313710764801985, 0.2086119118163921, 0.0, -0.4847702761712262, 0.13193775767639854, 0.0, 0.51099273821664126, 0.0, 0.0, -0.44253269244498283, 0.0, 0.16726163588932241, -0.34380302747441421, 0.0, -0.59135918484847527, 0.0, 0.15645893386229406], [0.28209479177387814, -0.3454941494713355, 0.3454941494713355, 0.0, 0.0, -0.54627421529603959, 0.15769578262626005, 0.0, -0.27313710764801985, 0.2086119118163921, 0.0, -0.4847702761712262, -0.13193775767639854, 0.0, -0.51099273821664126, 0.0, 0.0, 0.44253269244498283, 0.0, -0.16726163588932241, -0.34380302747441421, 0.0, -0.59135918484847527, 0.0, 0.15645893386229406], [0.28209479177387814, 0.3454941494713355, -0.3454941494713355, 0.0, 0.0, -0.54627421529603959, 0.15769578262626005, 0.0, -0.27313710764801985, -0.2086119118163921, 0.0, 0.4847702761712262, 0.13193775767639854, 0.0, 0.51099273821664126, 0.0, 0.0, 0.44253269244498283, 0.0, -0.16726163588932241, -0.34380302747441421, 0.0, -0.59135918484847527, 0.0, 0.15645893386229406], [0.28209479177387814, 0.3454941494713355, 0.3454941494713355, 0.0, 0.0, 0.54627421529603959, 0.15769578262626005, 0.0, -0.27313710764801985, -0.2086119118163921, 0.0, 0.4847702761712262, -0.13193775767639854, 0.0, -0.51099273821664126, 0.0, 0.0, -0.44253269244498283, 0.0, 0.16726163588932241, -0.34380302747441421, 0.0, -0.59135918484847527, 0.0, 0.15645893386229406], [0.28209479177387814, 0.0, -0.3454941494713355, -0.3454941494713355, 0.0, 0.0, 0.15769578262626005, 0.54627421529603959, 0.27313710764801985, 0.0, 0.0, 0.0, 0.13193775767639854, -0.4847702761712262, -0.51099273821664126, -0.2086119118163921, 0.0, 0.0, 0.0, 0.0, -0.34380302747441421, 0.16726163588932241, 0.59135918484847527, 0.44253269244498283, 0.15645893386229406], [0.28209479177387814, 0.0, -0.3454941494713355, 0.3454941494713355, 0.0, 0.0, 0.15769578262626005, -0.54627421529603959, 0.27313710764801985, 0.0, 0.0, 0.0, 0.13193775767639854, 0.4847702761712262, -0.51099273821664126, 0.2086119118163921, 0.0, 0.0, 0.0, 0.0, -0.34380302747441421, -0.16726163588932241, 0.59135918484847527, -0.44253269244498283, 0.15645893386229406], [0.28209479177387814, 0.0, 0.3454941494713355, -0.3454941494713355, 0.0, 0.0, 0.15769578262626005, -0.54627421529603959, 0.27313710764801985, 0.0, 0.0, 0.0, -0.13193775767639854, -0.4847702761712262, 0.51099273821664126, -0.2086119118163921, 0.0, 0.0, 0.0, 0.0, -0.34380302747441421, -0.16726163588932241, 0.59135918484847527, -0.44253269244498283, 0.15645893386229406], [0.28209479177387814, 0.0, 0.3454941494713355, 0.3454941494713355, 0.0, 0.0, 0.15769578262626005, 0.54627421529603959, 0.27313710764801985, 0.0, 0.0, 0.0, -0.13193775767639854, 0.4847702761712262, 0.51099273821664126, 0.2086119118163921, 0.0, 0.0, 0.0, 0.0, -0.34380302747441421, 0.16726163588932241, 0.59135918484847527, 0.44253269244498283, 0.15645893386229406], [0.28209479177387814, -0.3454941494713355, 0.0, -0.3454941494713355, 0.54627421529603959, 0.0, -0.3153915652525201, 0.0, 0.0, -0.41722382363278415, 0.0, 0.32318018411415073, 0.0, 0.32318018411415073, 0.0, 0.41722382363278415, -1.1102230246251565e-16, 0.0, -0.47308734787878015, 0.0, 0.31735664074561298, 0.0, 0.0, 0.0, -0.62583573544917659], [0.28209479177387814, 0.3454941494713355, 0.0, -0.3454941494713355, -0.54627421529603959, 0.0, -0.3153915652525201, 0.0, 0.0, 0.41722382363278415, 0.0, -0.32318018411415073, 0.0, 0.32318018411415073, 0.0, 0.41722382363278415, 1.1102230246251565e-16, 0.0, 0.47308734787878015, 0.0, 0.31735664074561298, 0.0, 0.0, 0.0, -0.62583573544917659], [0.28209479177387814, -0.3454941494713355, 0.0, 0.3454941494713355, -0.54627421529603959, 0.0, -0.3153915652525201, 0.0, 0.0, -0.41722382363278415, 0.0, 0.32318018411415073, 0.0, -0.32318018411415073, 0.0, -0.41722382363278415, 1.1102230246251565e-16, 0.0, 0.47308734787878015, 0.0, 0.31735664074561298, 0.0, 0.0, 0.0, -0.62583573544917659], [0.28209479177387814, 0.3454941494713355, 0.0, 0.3454941494713355, 0.54627421529603959, 0.0, -0.3153915652525201, 0.0, 0.0, 0.41722382363278415, 0.0, -0.32318018411415073, 0.0, -0.32318018411415073, 0.0, -0.41722382363278415, -1.1102230246251565e-16, 0.0, -0.47308734787878015, 0.0, 0.31735664074561298, 0.0, 0.0, 0.0, -0.62583573544917659], [0.28209479177387814, -0.28209479177387814, -0.28209479177387814, -0.28209479177387814, 0.36418281019735971, 0.36418281019735971, 0.0, 0.36418281019735971, 0.0, -0.22710788365184043, -0.55629843151037861, -0.17591701023519801, 0.28727127476813386, -0.17591701023519801, 0.0, 0.22710788365184048, 0.0, 0.3933623932844289, 0.42052208700336002, -0.14867700967939762, -0.32911059040285784, -0.14867700967939762, 0.0, -0.3933623932844289, -0.27814921575518947], [0.28209479177387814, -0.28209479177387814, 0.28209479177387814, -0.28209479177387814, 0.36418281019735971, -0.36418281019735971, 0.0, -0.36418281019735971, 0.0, -0.22710788365184043, 0.55629843151037861, -0.17591701023519801, -0.28727127476813386, -0.17591701023519801, 0.0, 0.22710788365184048, 0.0, -0.3933623932844289, 0.42052208700336002, 0.14867700967939762, -0.32911059040285784, 0.14867700967939762, 0.0, 0.3933623932844289, -0.27814921575518947], [0.28209479177387814, 0.28209479177387814, -0.28209479177387814, -0.28209479177387814, -0.36418281019735971, -0.36418281019735971, 0.0, 0.36418281019735971, 0.0, 0.22710788365184043, 0.55629843151037861, 0.17591701023519801, 0.28727127476813386, -0.17591701023519801, 0.0, 0.22710788365184048, 0.0, -0.3933623932844289, -0.42052208700336002, 0.14867700967939762, -0.32911059040285784, -0.14867700967939762, 0.0, -0.3933623932844289, -0.27814921575518947], [0.28209479177387814, 0.28209479177387814, 0.28209479177387814, -0.28209479177387814, -0.36418281019735971, 0.36418281019735971, 0.0, -0.36418281019735971, 0.0, 0.22710788365184043, -0.55629843151037861, 0.17591701023519801, -0.28727127476813386, -0.17591701023519801, 0.0, 0.22710788365184048, 0.0, 0.3933623932844289, -0.42052208700336002, -0.14867700967939762, -0.32911059040285784, 0.14867700967939762, 0.0, 0.3933623932844289, -0.27814921575518947], [0.28209479177387814, -0.28209479177387814, -0.28209479177387814, 0.28209479177387814, -0.36418281019735971, 0.36418281019735971, 0.0, -0.36418281019735971, 0.0, -0.22710788365184043, 0.55629843151037861, -0.17591701023519801, 0.28727127476813386, 0.17591701023519801, 0.0, -0.22710788365184048, 0.0, 0.3933623932844289, -0.42052208700336002, -0.14867700967939762, -0.32911059040285784, 0.14867700967939762, 0.0, 0.3933623932844289, -0.27814921575518947], [0.28209479177387814, -0.28209479177387814, 0.28209479177387814, 0.28209479177387814, -0.36418281019735971, -0.36418281019735971, 0.0, 0.36418281019735971, 0.0, -0.22710788365184043, -0.55629843151037861, -0.17591701023519801, -0.28727127476813386, 0.17591701023519801, 0.0, -0.22710788365184048, 0.0, -0.3933623932844289, -0.42052208700336002, 0.14867700967939762, -0.32911059040285784, -0.14867700967939762, 0.0, -0.3933623932844289, -0.27814921575518947], [0.28209479177387814, 0.28209479177387814, -0.28209479177387814, 0.28209479177387814, 0.36418281019735971, -0.36418281019735971, 0.0, -0.36418281019735971, 0.0, 0.22710788365184043, -0.55629843151037861, 0.17591701023519801, 0.28727127476813386, 0.17591701023519801, 0.0, -0.22710788365184048, 0.0, -0.3933623932844289, 0.42052208700336002, 0.14867700967939762, -0.32911059040285784, 0.14867700967939762, 0.0, 0.3933623932844289, -0.27814921575518947], [0.28209479177387814, 0.28209479177387814, 0.28209479177387814, 0.28209479177387814, 0.36418281019735971, 0.36418281019735971, 0.0, 0.36418281019735971, 0.0, 0.22710788365184043, 0.55629843151037861, 0.17591701023519801, -0.28727127476813386, 0.17591701023519801, 0.0, -0.22710788365184048, 0.0, 0.3933623932844289, 0.42052208700336002, -0.14867700967939762, -0.32911059040285784, -0.14867700967939762, 0.0, -0.3933623932844289, -0.27814921575518947], [0.28209479177387814, -0.14731920032792212, -0.14731920032792212, -0.44195760098376641, 0.29796775379783974, 0.099322584599279895, -0.22937568382001461, 0.29796775379783974, 0.39729033839711975, -0.42050234001046305, -0.23769603892429697, 0.07516608738008182, 0.28640664895524026, 0.22549826214024549, -0.31692805189906265, -0.29111700462262841, 0.49653083143075138, 0.38035867780395194, -0.093835507017278719, -0.14376206721065715, 0.05944972884490831, -0.43128620163197151, -0.12511400935637168, 0.26332523847965916, 0.14482149250063592], [0.28209479177387814, -0.14731920032792212, 0.14731920032792212, -0.44195760098376641, 0.29796775379783974, -0.099322584599279895, -0.22937568382001461, -0.29796775379783974, 0.39729033839711975, -0.42050234001046305, 0.23769603892429697, 0.07516608738008182, -0.28640664895524026, 0.22549826214024549, 0.31692805189906265, -0.29111700462262841, 0.49653083143075138, -0.38035867780395194, -0.093835507017278719, 0.14376206721065715, 0.05944972884490831, 0.43128620163197151, -0.12511400935637168, -0.26332523847965916, 0.14482149250063592], [0.28209479177387814, 0.14731920032792212, -0.14731920032792212, -0.44195760098376641, -0.29796775379783974, -0.099322584599279895, -0.22937568382001461, 0.29796775379783974, 0.39729033839711975, 0.42050234001046305, 0.23769603892429697, -0.07516608738008182, 0.28640664895524026, 0.22549826214024549, -0.31692805189906265, -0.29111700462262841, -0.49653083143075138, -0.38035867780395194, 0.093835507017278719, 0.14376206721065715, 0.05944972884490831, -0.43128620163197151, -0.12511400935637168, 0.26332523847965916, 0.14482149250063592], [0.28209479177387814, 0.14731920032792212, 0.14731920032792212, -0.44195760098376641, -0.29796775379783974, 0.099322584599279895, -0.22937568382001461, -0.29796775379783974, 0.39729033839711975, 0.42050234001046305, -0.23769603892429697, -0.07516608738008182, -0.28640664895524026, 0.22549826214024549, 0.31692805189906265, -0.29111700462262841, -0.49653083143075138, 0.38035867780395194, 0.093835507017278719, -0.14376206721065715, 0.05944972884490831, 0.43128620163197151, -0.12511400935637168, -0.26332523847965916, 0.14482149250063592], [0.28209479177387814, -0.14731920032792212, -0.14731920032792212, 0.44195760098376641, -0.29796775379783974, 0.099322584599279895, -0.22937568382001461, -0.29796775379783974, 0.39729033839711975, -0.42050234001046305, 0.23769603892429697, 0.07516608738008182, 0.28640664895524026, -0.22549826214024549, -0.31692805189906265, 0.29111700462262841, -0.49653083143075138, 0.38035867780395194, 0.093835507017278719, -0.14376206721065715, 0.05944972884490831, 0.43128620163197151, -0.12511400935637168, -0.26332523847965916, 0.14482149250063592], [0.28209479177387814, -0.14731920032792212, 0.14731920032792212, 0.44195760098376641, -0.29796775379783974, -0.099322584599279895, -0.22937568382001461, 0.29796775379783974, 0.39729033839711975, -0.42050234001046305, -0.23769603892429697, 0.07516608738008182, -0.28640664895524026, -0.22549826214024549, 0.31692805189906265, 0.29111700462262841, -0.49653083143075138, -0.38035867780395194, 0.093835507017278719, 0.14376206721065715, 0.05944972884490831, -0.43128620163197151, -0.12511400935637168, 0.26332523847965916, 0.14482149250063592], [0.28209479177387814, 0.14731920032792212, -0.14731920032792212, 0.44195760098376641, 0.29796775379783974, -0.099322584599279895, -0.22937568382001461, -0.29796775379783974, 0.39729033839711975, 0.42050234001046305, -0.23769603892429697, -0.07516608738008182, 0.28640664895524026, -0.22549826214024549, -0.31692805189906265, 0.29111700462262841, 0.49653083143075138, -0.38035867780395194, -0.093835507017278719, 0.14376206721065715, 0.05944972884490831, 0.43128620163197151, -0.12511400935637168, -0.26332523847965916, 0.14482149250063592], [0.28209479177387814, 0.14731920032792212, 0.14731920032792212, 0.44195760098376641, 0.29796775379783974, 0.099322584599279895, -0.22937568382001461, 0.29796775379783974, 0.39729033839711975, 0.42050234001046305, 0.23769603892429697, -0.07516608738008182, -0.28640664895524026, -0.22549826214024549, 0.31692805189906265, 0.29111700462262841, 0.49653083143075138, 0.38035867780395194, -0.093835507017278719, -0.14376206721065715, 0.05944972884490831, -0.43128620163197151, -0.12511400935637168, 0.26332523847965916, 0.14482149250063592], [0.28209479177387814, -0.44195760098376641, -0.14731920032792212, -0.14731920032792212, 0.29796775379783974, 0.29796775379783974, -0.22937568382001461, 0.099322584599279895, -0.39729033839711975, 0.29111700462262841, -0.23769603892429697, 0.22549826214024549, 0.28640664895524026, 0.07516608738008182, 0.31692805189906265, 0.42050234001046305, -0.49653083143075133, -0.26332523847965916, -0.093835507017278746, -0.43128620163197157, 0.059449728844908303, -0.14376206721065715, 0.12511400935637171, -0.38035867780395199, 0.14482149250063592], [0.28209479177387814, -0.44195760098376641, -0.14731920032792212, 0.14731920032792212, -0.29796775379783974, 0.29796775379783974, -0.22937568382001461, -0.099322584599279895, -0.39729033839711975, 0.29111700462262841, 0.23769603892429697, 0.22549826214024549, 0.28640664895524026, -0.07516608738008182, 0.31692805189906265, -0.42050234001046305, 0.49653083143075133, -0.26332523847965916, 0.093835507017278746, -0.43128620163197157, 0.059449728844908303, 0.14376206721065715, 0.12511400935637171, 0.38035867780395199, 0.14482149250063592], [0.28209479177387814, -0.44195760098376641, 0.14731920032792212, -0.14731920032792212, 0.29796775379783974, -0.29796775379783974, -0.22937568382001461, -0.099322584599279895, -0.39729033839711975, 0.29111700462262841, 0.23769603892429697, 0.22549826214024549, -0.28640664895524026, 0.07516608738008182, -0.31692805189906265, 0.42050234001046305, -0.49653083143075133, 0.26332523847965916, -0.093835507017278746, 0.43128620163197157, 0.059449728844908303, 0.14376206721065715, 0.12511400935637171, 0.38035867780395199, 0.14482149250063592], [0.28209479177387814, -0.44195760098376641, 0.14731920032792212, 0.14731920032792212, -0.29796775379783974, -0.29796775379783974, -0.22937568382001461, 0.099322584599279895, -0.39729033839711975, 0.29111700462262841, -0.23769603892429697, 0.22549826214024549, -0.28640664895524026, -0.07516608738008182, -0.31692805189906265, -0.42050234001046305, 0.49653083143075133, 0.26332523847965916, 0.093835507017278746, 0.43128620163197157, 0.059449728844908303, -0.14376206721065715, 0.12511400935637171, -0.38035867780395199, 0.14482149250063592], [0.28209479177387814, 0.44195760098376641, -0.14731920032792212, -0.14731920032792212, -0.29796775379783974, -0.29796775379783974, -0.22937568382001461, 0.099322584599279895, -0.39729033839711975, -0.29111700462262841, 0.23769603892429697, -0.22549826214024549, 0.28640664895524026, 0.07516608738008182, 0.31692805189906265, 0.42050234001046305, 0.49653083143075133, 0.26332523847965916, 0.093835507017278746, 0.43128620163197157, 0.059449728844908303, -0.14376206721065715, 0.12511400935637171, -0.38035867780395199, 0.14482149250063592], [0.28209479177387814, 0.44195760098376641, -0.14731920032792212, 0.14731920032792212, 0.29796775379783974, -0.29796775379783974, -0.22937568382001461, -0.099322584599279895, -0.39729033839711975, -0.29111700462262841, -0.23769603892429697, -0.22549826214024549, 0.28640664895524026, -0.07516608738008182, 0.31692805189906265, -0.42050234001046305, -0.49653083143075133, 0.26332523847965916, -0.093835507017278746, 0.43128620163197157, 0.059449728844908303, 0.14376206721065715, 0.12511400935637171, 0.38035867780395199, 0.14482149250063592], [0.28209479177387814, 0.44195760098376641, 0.14731920032792212, -0.14731920032792212, -0.29796775379783974, 0.29796775379783974, -0.22937568382001461, -0.099322584599279895, -0.39729033839711975, -0.29111700462262841, -0.23769603892429697, -0.22549826214024549, -0.28640664895524026, 0.07516608738008182, -0.31692805189906265, 0.42050234001046305, 0.49653083143075133, -0.26332523847965916, 0.093835507017278746, -0.43128620163197157, 0.059449728844908303, 0.14376206721065715, 0.12511400935637171, 0.38035867780395199, 0.14482149250063592], [0.28209479177387814, 0.44195760098376641, 0.14731920032792212, 0.14731920032792212, 0.29796775379783974, 0.29796775379783974, -0.22937568382001461, 0.099322584599279895, -0.39729033839711975, -0.29111700462262841, 0.23769603892429697, -0.22549826214024549, -0.28640664895524026, -0.07516608738008182, -0.31692805189906265, -0.42050234001046305, -0.49653083143075133, -0.26332523847965916, -0.093835507017278746, -0.43128620163197157, 0.059449728844908303, -0.14376206721065715, 0.12511400935637171, -0.38035867780395199, 0.14482149250063592], [0.28209479177387814, -0.14731920032792212, -0.44195760098376641, -0.14731920032792212, 0.099322584599279895, 0.29796775379783974, 0.45875136764002922, 0.29796775379783974, 0.0, -0.032346333846958689, -0.23769603892429694, -0.4259411618204636, -0.36823712008530907, -0.4259411618204636, 0.0, 0.032346333846958689, 3.4694469519536142e-18, 0.087775079493219665, 0.40662053040820756, 0.49763792495996717, 0.19933144377410417, 0.49763792495996717, 0.0, -0.087775079493219665, -0.020688784642947957], [0.28209479177387814, 0.14731920032792212, -0.44195760098376641, -0.14731920032792212, -0.099322584599279895, -0.29796775379783974, 0.45875136764002922, 0.29796775379783974, 0.0, 0.032346333846958689, 0.23769603892429694, 0.4259411618204636, -0.36823712008530907, -0.4259411618204636, 0.0, 0.032346333846958689, -3.4694469519536142e-18, -0.087775079493219665, -0.40662053040820756, -0.49763792495996717, 0.19933144377410417, 0.49763792495996717, 0.0, -0.087775079493219665, -0.020688784642947957], [0.28209479177387814, -0.14731920032792212, -0.44195760098376641, 0.14731920032792212, -0.099322584599279895, 0.29796775379783974, 0.45875136764002922, -0.29796775379783974, 0.0, -0.032346333846958689, 0.23769603892429694, -0.4259411618204636, -0.36823712008530907, 0.4259411618204636, 0.0, -0.032346333846958689, -3.4694469519536142e-18, 0.087775079493219665, -0.40662053040820756, 0.49763792495996717, 0.19933144377410417, -0.49763792495996717, 0.0, 0.087775079493219665, -0.020688784642947957], [0.28209479177387814, 0.14731920032792212, -0.44195760098376641, 0.14731920032792212, 0.099322584599279895, -0.29796775379783974, 0.45875136764002922, -0.29796775379783974, 0.0, 0.032346333846958689, -0.23769603892429694, 0.4259411618204636, -0.36823712008530907, 0.4259411618204636, 0.0, -0.032346333846958689, 3.4694469519536142e-18, -0.087775079493219665, 0.40662053040820756, -0.49763792495996717, 0.19933144377410417, -0.49763792495996717, 0.0, 0.087775079493219665, -0.020688784642947957], [0.28209479177387814, -0.14731920032792212, 0.44195760098376641, -0.14731920032792212, 0.099322584599279895, -0.29796775379783974, 0.45875136764002922, -0.29796775379783974, 0.0, -0.032346333846958689, 0.23769603892429694, -0.4259411618204636, 0.36823712008530907, -0.4259411618204636, 0.0, 0.032346333846958689, 3.4694469519536142e-18, -0.087775079493219665, 0.40662053040820756, -0.49763792495996717, 0.19933144377410417, -0.49763792495996717, 0.0, 0.087775079493219665, -0.020688784642947957], [0.28209479177387814, 0.14731920032792212, 0.44195760098376641, -0.14731920032792212, -0.099322584599279895, 0.29796775379783974, 0.45875136764002922, -0.29796775379783974, 0.0, 0.032346333846958689, -0.23769603892429694, 0.4259411618204636, 0.36823712008530907, -0.4259411618204636, 0.0, 0.032346333846958689, -3.4694469519536142e-18, 0.087775079493219665, -0.40662053040820756, 0.49763792495996717, 0.19933144377410417, -0.49763792495996717, 0.0, 0.087775079493219665, -0.020688784642947957], [0.28209479177387814, -0.14731920032792212, 0.44195760098376641, 0.14731920032792212, -0.099322584599279895, -0.29796775379783974, 0.45875136764002922, 0.29796775379783974, 0.0, -0.032346333846958689, -0.23769603892429694, -0.4259411618204636, 0.36823712008530907, 0.4259411618204636, 0.0, -0.032346333846958689, -3.4694469519536142e-18, -0.087775079493219665, -0.40662053040820756, -0.49763792495996717, 0.19933144377410417, 0.49763792495996717, 0.0, -0.087775079493219665, -0.020688784642947957], [0.28209479177387814, 0.14731920032792212, 0.44195760098376641, 0.14731920032792212, 0.099322584599279895, 0.29796775379783974, 0.45875136764002922, 0.29796775379783974, 0.0, 0.032346333846958689, 0.23769603892429694, 0.4259411618204636, 0.36823712008530907, 0.4259411618204636, 0.0, -0.032346333846958689, 3.4694469519536142e-18, 0.087775079493219665, 0.40662053040820756, 0.49763792495996717, 0.19933144377410417, 0.49763792495996717, 0.0, -0.087775079493219665, -0.020688784642947957]]) R_nv = np.array([[-1.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, -1.0], [0.0, 0.0, 1.0], [0.0, -0.70710678118654757, -0.70710678118654757], [0.0, -0.70710678118654757, 0.70710678118654757], [0.0, 0.70710678118654757, -0.70710678118654757], [0.0, 0.70710678118654757, 0.70710678118654757], [-0.70710678118654757, 0.0, -0.70710678118654757], [0.70710678118654757, 0.0, -0.70710678118654757], [-0.70710678118654757, 0.0, 0.70710678118654757], [0.70710678118654757, 0.0, 0.70710678118654757], [-0.70710678118654757, -0.70710678118654757, 0.0], [-0.70710678118654757, 0.70710678118654757, 0.0], [0.70710678118654757, -0.70710678118654757, 0.0], [0.70710678118654757, 0.70710678118654757, 0.0], [-0.57735026918962573, -0.57735026918962573, -0.57735026918962573], [-0.57735026918962573, -0.57735026918962573, 0.57735026918962573], [-0.57735026918962573, 0.57735026918962573, -0.57735026918962573], [-0.57735026918962573, 0.57735026918962573, 0.57735026918962573], [0.57735026918962573, -0.57735026918962573, -0.57735026918962573], [0.57735026918962573, -0.57735026918962573, 0.57735026918962573], [0.57735026918962573, 0.57735026918962573, -0.57735026918962573], [0.57735026918962573, 0.57735026918962573, 0.57735026918962573], [-0.90453403373329089, -0.30151134457776357, -0.30151134457776357], [-0.90453403373329089, -0.30151134457776357, 0.30151134457776357], [-0.90453403373329089, 0.30151134457776357, -0.30151134457776357], [-0.90453403373329089, 0.30151134457776357, 0.30151134457776357], [0.90453403373329089, -0.30151134457776357, -0.30151134457776357], [0.90453403373329089, -0.30151134457776357, 0.30151134457776357], [0.90453403373329089, 0.30151134457776357, -0.30151134457776357], [0.90453403373329089, 0.30151134457776357, 0.30151134457776357], [-0.30151134457776357, -0.90453403373329089, -0.30151134457776357], [0.30151134457776357, -0.90453403373329089, -0.30151134457776357], [-0.30151134457776357, -0.90453403373329089, 0.30151134457776357], [0.30151134457776357, -0.90453403373329089, 0.30151134457776357], [-0.30151134457776357, 0.90453403373329089, -0.30151134457776357], [0.30151134457776357, 0.90453403373329089, -0.30151134457776357], [-0.30151134457776357, 0.90453403373329089, 0.30151134457776357], [0.30151134457776357, 0.90453403373329089, 0.30151134457776357], [-0.30151134457776357, -0.30151134457776357, -0.90453403373329089], [-0.30151134457776357, 0.30151134457776357, -0.90453403373329089], [0.30151134457776357, -0.30151134457776357, -0.90453403373329089], [0.30151134457776357, 0.30151134457776357, -0.90453403373329089], [-0.30151134457776357, -0.30151134457776357, 0.90453403373329089], [-0.30151134457776357, 0.30151134457776357, 0.90453403373329089], [0.30151134457776357, -0.30151134457776357, 0.90453403373329089], [0.30151134457776357, 0.30151134457776357, 0.90453403373329089]]) gpaw-0.11.0.13004/gpaw/sphere/csh.py0000664000175000017500000002173312553643472017037 0ustar jensjjensj00000000000000from math import factorial as fact import numpy as np from gpaw.sphere import lmfact from gpaw.sphere.legendre import ilegendre, legendre, dlegendre # Define the Heaviside function heaviside = lambda x: (1.0+np.sign(x))/2.0 # Define spherical harmoncics and normalization coefficient C = lambda l,m: (-1)**((m+abs(m))//2)*((2.*l+1.)/(4*np.pi*lmfact(l,m)))**0.5 Y = lambda l,m,theta,phi: C(l,m)*legendre(l,abs(m),np.cos(theta))*np.exp(1j*m*phi) # Define theta-derivative of spherical harmoncics dYdtheta = lambda l,m,theta,phi: C(l,m)*dlegendre(l,abs(m),np.cos(theta))*np.exp(1j*m*phi) # Define phi-derivative of spherical harmoncics dYdphi = lambda l,m,theta,phi: 1j*m*C(l,m)*legendre(l,abs(m),np.cos(theta))*np.exp(1j*m*phi) # ------------------------------------------------------------------- def intYY(l1, m1, l2, m2): """Calculates:: pi 2pi / / * A = | | Y (u,v) Y (u,v) sin(u) dv du LL' / / lm l'm' 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if l1 = l2 and m1 = m2. """ if (l1,m1) == (l2,m2): return C(l1,m1)**2*2*np.pi*ilegendre(l1,m1) # == 1 always, XXX right? else: return 0.0 # ------------------------------------------------------------------- def intYY_ex(l1, m1, l2, m2): """Calculates:: pi 2pi / / * A = | | Y (u,v) sin(u)*cos(v) Y (u,v) sin(u) dv du LL' / / lm l'm' 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if `|l1-l2|` = 1 and `|m1-m2|` = 1. """ if abs(l1-l2) != 1 or abs(m1-m2) != 1: return 0.0 scale = C(l1,m1)*C(l2,m2)*np.pi if abs(m1) == abs(m2)+1: return scale*np.sign(l1-l2)/(2.*l2+1.)*ilegendre(l1,m1) else: assert abs(m1) == abs(m2)-1 return scale*np.sign(l2-l1)/(2.*l1+1.)*ilegendre(l2,m2) def intYY_ey(l1, m1, l2, m2): """Calculates:: pi 2pi / / * A = | | Y (u,v) sin(u)*sin(v) Y (u,v) sin(u) dv du LL' / / lm l'm' 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if `|l1-l2|` = 1 and `|m1-m2|` = 1. """ if abs(l1-l2) != 1 or abs(m1-m2) != 1: return 0.0 scale = C(l1,m1)*C(l2,m2)*np.sign(m1-m2)*np.pi/1j if abs(m1) == abs(m2)+1: return scale*np.sign(l1-l2)/(2.*l2+1.)*ilegendre(l1,m1) else: assert abs(m1) == abs(m2)-1 return scale*np.sign(l2-l1)/(2.*l1+1.)*ilegendre(l2,m2) def intYY_ez(l1, m1, l2, m2): """Calculates:: pi 2pi / / * A = | | Y (u,v) cos(u) Y (u,v) sin(u) dv du LL' / / lm l'm' 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if `|l1-l2|` = 1 and m1 = m2. """ if abs(l1-l2) != 1 or m1 != m2: return 0.0 scale = C(l1,m1)*C(l2,m2)*2*np.pi return scale*(l2-np.sign(l1-l2)*abs(m1)+heaviside(l1-l2))/(2.*l2+1.)*ilegendre(l1,m1) # ------------------------------------------------------------------- def intYdYdtheta_ex(l1, m1, l2, m2): """Calculates:: pi 2pi / / * d Y(u,v) A = | | Y (u,v) cos(u)*cos(v) --- l'm' sin(u) dv du LL' / / lm du 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if `|l1-l2|` is odd and `|m1-m2|` = 1 (stricter rule applies). """ if abs(l1-l2) % 2 != 1 or abs(m1-m2) != 1: return 0.0 scale = -C(l1,m1)*C(l2,m2)*np.pi if abs(m1) == abs(m2)+1: if l1+1 == l2: return scale*2/(2.0*l2+1)*(l2+1)/(2.0*l2-1.0)*fact(l2+abs(m2))/fact(l2-abs(m2)-1)*(l2-abs(m2)-1) elif l1-1 == l2: return scale*2/(2.0*l2+1)*((l2+1)*fact(l2+abs(m2))/fact(l2-abs(m2))*(l2-abs(m2))-l2/(2.0*l2+3.0)*fact(l2+abs(m2)+1)/fact(l2-abs(m2))*(l2-abs(m2)+1)) elif l1-l2 > 2: # and (l1-l2)%2 == 1 which is always true return -scale*2*abs(m2)*fact(l2+abs(m2))/fact(l2-abs(m2)) else: return 0.0 else: assert abs(m1) == abs(m2)-1 if l1 == l2+1: return -scale*2/(2.0*l1+1.0)*(l1-1)/(2.0*l1-1.0)*fact(l1+abs(m1))/fact(l1-abs(m1)-1)*(l1-abs(m1)-1) elif l1 == l2-1: return -scale*2/(2.0*l1+1.0)*((l1+1)/(2.0*l1+3.0)*fact(l1+abs(m1)+1)/fact(l1-abs(m1))*(l1-abs(m1)+1)-(abs(m1)+1)*fact(l1+abs(m1))/fact(l1-abs(m1))*(l1-abs(m1))) elif l2-l1 > 2: # and (l2-l1)%2 == 1 which is always true return scale*2*(abs(m1)+1)*fact(l1+abs(m1))/fact(l1-abs(m1)) else: return 0.0 def intYdYdtheta_ey(l1, m1, l2, m2): """Calculates:: pi 2pi / / * d Y(u,v) A = | | Y (u,v) cos(u)*sin(v) --- l'm' sin(u) dv du LL' / / lm du 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if `|l1-l2|` is odd and `|m1-m2|` = 1 (stricter rule applies). """ if abs(l1-l2) % 2 != 1 or abs(m1-m2) != 1: return 0.0 scale = -C(l1,m1)*C(l2,m2)*np.sign(m1-m2)*np.pi/1j if abs(m1) == abs(m2)+1: if l1+1 == l2: return scale*2/(2.0*l2+1)*(l2+1)/(2.0*l2-1.0)*fact(l2+abs(m2))/fact(l2-abs(m2)-1)*(l2-abs(m2)-1) elif l1-1 == l2: return scale*2/(2.0*l2+1)*((l2+1)*fact(l2+abs(m2))/fact(l2-abs(m2))*(l2-abs(m2))-l2/(2.0*l2+3.0)*fact(l2+abs(m2)+1)/fact(l2-abs(m2))*(l2-abs(m2)+1)) elif l1-l2 > 2: # and (l1-l2)%2 == 1 which is always true return -scale*2*abs(m2)*fact(l2+abs(m2))/fact(l2-abs(m2)) else: return 0.0 else: assert abs(m1) == abs(m2)-1 if l1 == l2+1: return -scale*2/(2.0*l1+1.0)*(l1-1)/(2.0*l1-1.0)*fact(l1+abs(m1))/fact(l1-abs(m1)-1)*(l1-abs(m1)-1) elif l1 == l2-1: return -scale*2/(2.0*l1+1.0)*((l1+1)/(2.0*l1+3.0)*fact(l1+abs(m1)+1)/fact(l1-abs(m1))*(l1-abs(m1)+1)-(abs(m1)+1)*fact(l1+abs(m1))/fact(l1-abs(m1))*(l1-abs(m1))) elif l2-l1 > 2: # and (l2-l1)%2 == 1 which is always true return scale*2*(abs(m1)+1)*fact(l1+abs(m1))/fact(l1-abs(m1)) else: return 0.0 def intYdYdtheta_ez(l1, m1, l2, m2): """Calculates:: pi 2pi / / * d Y(u,v) A = - | | Y (u,v) sin(u) --- l'm' sin(u) dv du LL' / / lm du 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if `|l1-l2|` = 1 and m1 = m2. """ if abs(l1-l2) != 1 or m1 != m2: return 0.0 scale = -C(l1,m1)*C(l2,m2)*2*np.pi return scale*np.sign(l1-l2)*(l2+1-heaviside(l1-l2))*(l2-np.sign(l1-l2)*abs(m1)+heaviside(l1-l2))/(2*l2+1)*ilegendre(l1,m1) # ------------------------------------------------------------------- def intYdYdphi_ex(l1, m1, l2, m2): """Calculates:: pi 2pi / / * -1 d Y(u,v) A = - | | Y (u,v) sin(u)*sin(v) --- l'm' sin(u) dv du LL' / / lm dv 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if `|l1-l2|` is odd and `|m1-m2|` = 1 (stricter rule applies). """ if abs(l1-l2) % 2 != 1 or abs(m1-m2) != 1: return 0.0 scale = -C(l1,m1)*C(l2,m2)*np.sign(m1-m2)*np.pi/1j*1j*m2 if abs(m1) == abs(m2)+1 and l1 > l2: # and (l1-l2)%2 == 1 which is always true return scale*2*lmfact(l2,m2) elif abs(m1) == abs(m2)-1 and l1 < l2: # and (l2-l1)%2 == 1 which is always true return scale*2*lmfact(l1,m1) else: return 0.0 def intYdYdphi_ey(l1, m1, l2, m2): """Calculates:: pi 2pi / / * -1 d Y(u,v) A = | | Y (u,v) sin(u)*cos(v) --- l'm' sin(u) dv du LL' / / lm dv 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if `|l1-l2|` is odd and `|m1-m2|` = 1 (stricter rule applies). """ if abs(l1-l2) % 2 != 1 or abs(m1-m2) != 1: return 0.0 scale = C(l1,m1)*C(l2,m2)*np.pi*1j*m2 if abs(m1) == abs(m2)+1 and l1 > l2: # and (l1-l2)%2 == 1 which is always true return scale*2*lmfact(l2,m2) elif abs(m1) == abs(m2)-1 and l1 < l2: # and (l2-l1)%2 == 1 which is always true return scale*2*lmfact(l1,m1) else: return 0.0 def intYdYdphi_ez(l1, m1, l2, m2): #XXX this is silly return 0.0 gpaw-0.11.0.13004/gpaw/sphere/rsh.py0000664000175000017500000003264212553643472017057 0ustar jensjjensj00000000000000from math import factorial as fact import numpy as np from gpaw.sphere import lmfact from gpaw.sphere.legendre import ilegendre, legendre, dlegendre # Define the Heaviside function heaviside = lambda x: (1.0+np.sign(x))/2.0 # Define spherical harmoncics and normalization coefficient C = lambda l,m: ((2.*l+1.)/(4*np.pi*lmfact(l,m)))**0.5 def Y(l,m,theta,phi): if m == 0: return C(l,m)*legendre(l,abs(m),np.cos(theta)) elif m > 0: return C(l,m)*legendre(l,abs(m),np.cos(theta))*np.cos(m*phi)*2**0.5 else: return C(l,m)*legendre(l,abs(m),np.cos(theta))*np.sin(abs(m)*phi)*2**0.5 # Define theta-derivative of spherical harmoncics def dYdtheta(l,m,theta,phi): if m == 0: return C(l,m)*dlegendre(l,abs(m),np.cos(theta)) elif m > 0: return C(l,m)*dlegendre(l,abs(m),np.cos(theta))*np.cos(m*phi)*2**0.5 else: return C(l,m)*dlegendre(l,abs(m),np.cos(theta))*np.sin(abs(m)*phi)*2**0.5 # Define phi-derivative of spherical harmoncics def dYdphi(l,m,theta,phi): if m == 0: return np.zeros_like(theta) elif m > 0: return -m*C(l,m)*legendre(l,abs(m),np.cos(theta))*np.sin(m*phi)*2**0.5 else: return -m*C(l,m)*legendre(l,abs(m),np.cos(theta))*np.cos(m*phi)*2**0.5 # ------------------------------------------------------------------- def intYY(l1, m1, l2, m2): """Calculates:: pi 2pi / / A = | | y (u,v) y (u,v) sin(u) dv du LL' / / lm l'm' 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if l1 = l2 and m1 = m2. """ if (l1,m1) == (l2,m2): return C(l1,m1)**2*2*np.pi*ilegendre(l1,m1) # == 1 always, XXX right? else: return 0.0 # ------------------------------------------------------------------- from gpaw.sphere.csh import intYY_ex as _intYY_ex, intYY_ey as _intYY_ey, intYY_ez as _intYY_ez #TODO make independent def mix(l1, m1, l2, m2, func): # m1 == 0 if m1 == 0 and m2 == 0: return func(l1,abs(m1),l2,abs(m2)) elif m1 == 0 and m2 > 0: return 1/2**0.5*((-1)**m2*func(l1,abs(m1),l2,abs(m2)) \ +func(l1,abs(m1),l2,-abs(m2))) elif m1 == 0 and m2 < 0: return 1/(2**0.5*1j)*((-1)**m2*func(l1,abs(m1),l2,abs(m2)) \ -func(l1,abs(m1),l2,-abs(m2))) # m1 > 0 elif m1 > 0 and m2 == 0: return 1/2**0.5*((-1)**m1*func(l1,abs(m1),l2,abs(m2)) \ +func(l1,-abs(m1),l2,abs(m2))) elif m1 > 0 and m2 > 0: return 0.5*((-1)**(m1+m2)*func(l1,abs(m1),l2,abs(m2)) \ +(-1)**m1*func(l1,abs(m1),l2,-abs(m2)) \ +(-1)**m2*func(l1,-abs(m1),l2,abs(m2)) \ +func(l1,-abs(m1),l2,-abs(m2))) elif m1 > 0 and m2 < 0: return 1/2j*((-1)**(m1+m2)*func(l1,abs(m1),l2,abs(m2)) \ -(-1)**m1*func(l1,abs(m1),l2,-abs(m2)) \ +(-1)**m2*func(l1,-abs(m1),l2,abs(m2)) \ -func(l1,-abs(m1),l2,-abs(m2))) # m1 < 0 elif m1 < 0 and m2 == 0: return -1/(2**0.5*1j)*((-1)**m1*func(l1,abs(m1),l2,abs(m2)) \ -func(l1,-abs(m1),l2,abs(m2))) elif m1 < 0 and m2 > 0: return -1/2j*((-1)**(m1+m2)*func(l1,abs(m1),l2,abs(m2)) \ +(-1)**m1*func(l1,abs(m1),l2,-abs(m2)) \ -(-1)**m2*func(l1,-abs(m1),l2,abs(m2)) \ -func(l1,-abs(m1),l2,-abs(m2))) elif m1 < 0 and m2 < 0: return 0.5*((-1)**(m1+m2)*func(l1,abs(m1),l2,abs(m2)) \ -(-1)**m1*func(l1,abs(m1),l2,-abs(m2)) \ -(-1)**m2*func(l1,-abs(m1),l2,abs(m2)) \ +func(l1,-abs(m1),l2,-abs(m2))) else: raise ValueError('Invalid arguments (l1=%s, m1=%s, l2=%s, m2=%s)' \ % (l1,m1,l2,m2)) def intYY_ex(l1, m1, l2, m2): """Calculates:: pi 2pi / / A = | | y (u,v) sin(u)*cos(v) y (u,v) sin(u) dv du LL' / / lm l'm' 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if `|l1-l2|` = 1 and `|m1-m2|` = 1. """ #if abs(l1-l2) != 1 or abs(m1-m2) != 1: # return 0.0 #scale = C(l1,m1)*C(l2,m2)*np.pi #if abs(m1) == abs(m2)+1: # return scale*np.sign(l1-l2)/(2.*l2+1.)*ilegendre(l1,m1) #else: # assert abs(m1) == abs(m2)-1 # return scale*np.sign(l2-l1)/(2.*l1+1.)*ilegendre(l2,m2) return mix(l1,m1,l2,m2,_intYY_ex) def intYY_ey(l1, m1, l2, m2): """Calculates:: pi 2pi / / A = | | y (u,v) sin(u)*sin(v) y (u,v) sin(u) dv du LL' / / lm l'm' 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if `|l1-l2|` = 1 and `|m1-m2|` = 1. """ #if abs(l1-l2) != 1 or abs(m1-m2) != 1: # return 0.0 #scale = C(l1,m1)*C(l2,m2)*np.sign(m1-m2)*np.pi/1j #if abs(m1) == abs(m2)+1: # return scale*np.sign(l1-l2)/(2.*l2+1.)*ilegendre(l1,m1) #else: # assert abs(m1) == abs(m2)-1 # return scale*np.sign(l2-l1)/(2.*l1+1.)*ilegendre(l2,m2) return mix(l1,m1,l2,m2,_intYY_ey) def intYY_ez(l1, m1, l2, m2): """Calculates:: pi 2pi / / A = | | y (u,v) cos(u) y (u,v) sin(u) dv du LL' / / lm l'm' 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if `|l1-l2|` = 1 and m1 = m2. """ return mix(l1,m1,l2,m2,_intYY_ez) # ------------------------------------------------------------------- from gpaw.sphere.csh import intYdYdtheta_ex as _intYdYdtheta_ex, intYdYdtheta_ey as _intYdYdtheta_ey, intYdYdtheta_ez as _intYdYdtheta_ez #TODO make independent def intYdYdtheta_ex(l1, m1, l2, m2): """Calculates:: pi 2pi / / d y(u,v) A = | | y (u,v) cos(u)*cos(v) --- l'm' sin(u) dv du LL' / / lm du 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if `|l1-l2|` is odd and `|m1-m2|` = 1 (stricter rule applies). """ #if abs(l1-l2) % 2 != 1 or abs(m1-m2) != 1: # return 0.0 #scale = -C(l1,m1)*C(l2,m2)*np.pi #if abs(m1) == abs(m2)+1: # if l1+1 == l2: # return scale*2/(2.0*l2+1)*(l2+1)/(2.0*l2-1.0)*fact(l2+abs(m2))/fact(l2-abs(m2)-1)*(l2-abs(m2)-1) # elif l1-1 == l2: # return scale*2/(2.0*l2+1)*((l2+1)*fact(l2+abs(m2))/fact(l2-abs(m2))*(l2-abs(m2))-l2/(2.0*l2+3.0)*fact(l2+abs(m2)+1)/fact(l2-abs(m2))*(l2-abs(m2)+1)) # elif l1-l2 > 2: # and (l1-l2)%2 == 1 which is always true # return -scale*2*abs(m2)*fact(l2+abs(m2))/fact(l2-abs(m2)) # else: # return 0.0 #else: # assert abs(m1) == abs(m2)-1 # if l1 == l2+1: # return -scale*2/(2.0*l1+1.0)*(l1-1)/(2.0*l1-1.0)*fact(l1+abs(m1))/fact(l1-abs(m1)-1)*(l1-abs(m1)-1) # elif l1 == l2-1: # return -scale*2/(2.0*l1+1.0)*((l1+1)/(2.0*l1+3.0)*fact(l1+abs(m1)+1)/fact(l1-abs(m1))*(l1-abs(m1)+1)-(abs(m1)+1)*fact(l1+abs(m1))/fact(l1-abs(m1))*(l1-abs(m1))) # elif l2-l1 > 2: # and (l2-l1)%2 == 1 which is always true # return scale*2*(abs(m1)+1)*fact(l1+abs(m1))/fact(l1-abs(m1)) # else: # return 0.0 return mix(l1,m1,l2,m2,_intYdYdtheta_ex) def intYdYdtheta_ey(l1, m1, l2, m2): """Calculates:: pi 2pi / / d y(u,v) A = | | y (u,v) cos(u)*sin(v) --- l'm' sin(u) dv du LL' / / lm du 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if `|l1-l2|` is odd and `|m1-m2|` = 1 (stricter rule applies). """ #if abs(l1-l2) % 2 != 1 or abs(m1-m2) != 1: # return 0.0 #scale = -C(l1,m1)*C(l2,m2)*np.sign(m1-m2)*np.pi/1j #if abs(m1) == abs(m2)+1: # if l1+1 == l2: # return scale*2/(2.0*l2+1)*(l2+1)/(2.0*l2-1.0)*fact(l2+abs(m2))/fact(l2-abs(m2)-1)*(l2-abs(m2)-1) # elif l1-1 == l2: # return scale*2/(2.0*l2+1)*((l2+1)*fact(l2+abs(m2))/fact(l2-abs(m2))*(l2-abs(m2))-l2/(2.0*l2+3.0)*fact(l2+abs(m2)+1)/fact(l2-abs(m2))*(l2-abs(m2)+1)) # elif l1-l2 > 2: # and (l1-l2)%2 == 1 which is always true # return -scale*2*abs(m2)*fact(l2+abs(m2))/fact(l2-abs(m2)) # else: # return 0.0 #else: # assert abs(m1) == abs(m2)-1 # if l1 == l2+1: # return -scale*2/(2.0*l1+1.0)*(l1-1)/(2.0*l1-1.0)*fact(l1+abs(m1))/fact(l1-abs(m1)-1)*(l1-abs(m1)-1) # elif l1 == l2-1: # return -scale*2/(2.0*l1+1.0)*((l1+1)/(2.0*l1+3.0)*fact(l1+abs(m1)+1)/fact(l1-abs(m1))*(l1-abs(m1)+1)-(abs(m1)+1)*fact(l1+abs(m1))/fact(l1-abs(m1))*(l1-abs(m1))) # elif l2-l1 > 2: # and (l2-l1)%2 == 1 which is always true # return scale*2*(abs(m1)+1)*fact(l1+abs(m1))/fact(l1-abs(m1)) # else: # return 0.0 return mix(l1,m1,l2,m2,_intYdYdtheta_ey) def intYdYdtheta_ez(l1, m1, l2, m2): """Calculates:: pi 2pi / / d y(u,v) A = - | | y (u,v) sin(u) --- l'm' sin(u) dv du LL' / / lm du 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if `|l1-l2|` = 1 and m1 = m2. """ #if abs(l1-l2) != 1 or m1 != m2: # return 0.0 #scale = -C(l1,m1)*C(l2,m2)*2*np.pi #return scale*np.sign(l1-l2)*(l2+1-heaviside(l1-l2))*(l2-np.sign(l1-l2)*abs(m1)+heaviside(l1-l2))/(2*l2+1)*ilegendre(l1,m1) return mix(l1,m1,l2,m2,_intYdYdtheta_ez) # ------------------------------------------------------------------- from gpaw.sphere.csh import intYdYdphi_ex as _intYdYdphi_ex, intYdYdphi_ey as _intYdYdphi_ey #TODO make independent def intYdYdphi_ex(l1, m1, l2, m2): """Calculates:: pi 2pi / / -1 d y(u,v) A = - | | y (u,v) sin(u)*sin(v) --- l'm' sin(u) dv du LL' / / lm dv 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if `|l1-l2|` is odd and `|m1-m2|` = 1 (stricter rule applies). """ #if abs(l1-l2) % 2 != 1 or abs(m1-m2) != 1: # return 0.0 #scale = -C(l1,m1)*C(l2,m2)*np.sign(m1-m2)*np.pi/1j*1j*m2 #if abs(m1) == abs(m2)+1 and l1 > l2: # and (l1-l2)%2 == 1 which is always true # return scale*2*lmfact(l2,m2) #elif abs(m1) == abs(m2)-1 and l1 < l2: # and (l2-l1)%2 == 1 which is always true # return scale*2*lmfact(l1,m1) #else: # return 0.0 return mix(l1,m1,l2,m2,_intYdYdphi_ex) def intYdYdphi_ey(l1, m1, l2, m2): """Calculates:: pi 2pi / / -1 d y(u,v) A = | | y (u,v) sin(u)*cos(v) --- l'm' sin(u) dv du LL' / / lm dv 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if `|l1-l2|` is odd and `|m1-m2|` = 1 (stricter rule applies). """ #if abs(l1-l2) % 2 != 1 or abs(m1-m2) != 1: # return 0.0 #scale = C(l1,m1)*C(l2,m2)*np.pi*1j*m2 #if abs(m1) == abs(m2)+1 and l1 > l2: # and (l1-l2)%2 == 1 which is always true # return scale*2*lmfact(l2,m2) #elif abs(m1) == abs(m2)-1 and l1 < l2: # and (l2-l1)%2 == 1 which is always true # return scale*2*lmfact(l1,m1) #else: # return 0.0 return mix(l1,m1,l2,m2,_intYdYdphi_ey) def intYdYdphi_ez(l1, m1, l2, m2): #XXX this is silly return 0.0 # ------------------------------------------------------------------- def intYgradY(l1, m1, l2, m2, r_g, dr_g, A_g, B_g, dBdr_g, v=None): """Calculates:: pi 2pi / / * / __ \ 2 A = | | A(r) y (u,v) | \/ B(r) y (u,v) | r sin(u) dv du dr vLL' / / lm \ v l'm' / 0 0 where u = theta and v = phi in the usual notation. Note that the result is only non-zero if `|l1-l2|` is odd and `|m1-m2|` <= 1 (stricter rule applies). """ if v is None: D = [intYY_ex(l1,m1,l2,m2), \ intYY_ey(l1,m1,l2,m2), \ intYY_ez(l1,m1,l2,m2)] G = [intYdYdtheta_ex(l1,m1,l2,m2) + intYdYdphi_ex(l1,m1,l2,m2), \ intYdYdtheta_ey(l1,m1,l2,m2) + intYdYdphi_ey(l1,m1,l2,m2), \ intYdYdtheta_ez(l1,m1,l2,m2) + intYdYdphi_ez(l1,m1,l2,m2)] D, G = np.array(D), np.array(G) elif v == 0: D = intYY_ex(l1,m1,l2,m2) G = intYdYdtheta_ex(l1,m1,l2,m2) + intYdYdphi_ex(l1,m1,l2,m2) elif v == 1: D = intYY_ey(l1,m1,l2,m2) G = intYdYdtheta_ey(l1,m1,l2,m2) + intYdYdphi_ey(l1,m1,l2,m2) elif v == 2: D = intYY_ez(l1,m1,l2,m2) G = intYdYdtheta_ez(l1,m1,l2,m2) + intYdYdphi_ez(l1,m1,l2,m2) else: raise ValueError return D * np.vdot(A_g, dBdr_g * r_g**2 * dr_g) \ + G * np.vdot(A_g, B_g * r_g * dr_g) gpaw-0.11.0.13004/gpaw/sphere/legendre.py0000664000175000017500000003330612553643472020046 0ustar jensjjensj00000000000000 import numpy as np from gpaw.sphere import lmfact # Highest l for which associated Legendre polynomials are implemented lmax = 9 # Integral norm of the associated Legendre polynomials ilegendre = lambda l,m: 2./(2.*l+1.)*lmfact(l,m) def legendre(l, m, w): if m < 0 or l < m: return np.zeros_like(w) if (l,m) == (0,0): return np.ones_like(w) elif (l,m) == (1,0): return w.copy() elif (l,m) == (1,1): return (1-w**2)**0.5 elif (l,m) == (2,0): return 1.5*w**2-0.5 elif (l,m) == (2,1): return 3*(1-w**2)**0.5*w elif (l,m) == (2,2): return 3*(1-w**2) elif (l,m) == (3,0): return 2.5*w**3-1.5*w elif (l,m) == (3,1): return (1-w**2)**0.5*(7.5*w**2-1.5) elif (l,m) == (3,2): return 15*w-15*w**3 elif (l,m) == (3,3): return 15*(1-w**2)**1.5 elif (l,m) == (4,0): return 4.375*w**4-3.75*w**2+0.375 elif (l,m) == (4,1): return (1-w**2)**0.5*(17.5*w**3-7.5*w) elif (l,m) == (4,2): return (1-w**2)*(52.5*w**2-7.5) elif (l,m) == (4,3): return 105*(1-w**2)**1.5*w elif (l,m) == (4,4): return 105*(1-w**2)**2 elif (l,m) == (5,0): return 7.875*w**5-8.75*w**3+1.875*w elif (l,m) == (5,1): return (1-w**2)**0.5*(39.375*w**4-26.25*w**2+1.875) elif (l,m) == (5,2): return (1-w**2)*(157.5*w**3-52.5*w) elif (l,m) == (5,3): return (1-w**2)**1.5*(472.5*w**2-52.5) elif (l,m) == (5,4): return 945*(1-w**2)**2*w elif (l,m) == (5,5): return 945*(1-w**2)**2.5 elif (l,m) == (6,0): return 14.4375*w**6-19.6875*w**4+6.5625*w**2-0.3125 elif (l,m) == (6,1): return (1-w**2)**0.5*(86.625*w**5-78.75*w**3+13.125*w) elif (l,m) == (6,2): return (1-w**2)*(433.125*w**4-236.25*w**2+13.125) elif (l,m) == (6,3): return (1-w**2)**1.5*(1732.5*w**3-472.5*w) elif (l,m) == (6,4): return (1-w**2)**2*(5197.5*w**2-472.5) elif (l,m) == (6,5): return 10395*(1-w**2)**2.5*w elif (l,m) == (6,6): return 10395*(1-w**2)**3 elif (l,m) == (7,0): return 26.8125*w**7-43.3125*w**5+19.6875*w**3-2.1875*w elif (l,m) == (7,1): return (1-w**2)**0.5*(187.6875*w**6-216.5625*w**4+59.0625*w**2-2.1875) elif (l,m) == (7,2): return (1-w**2)*(1126.125*w**5-866.25*w**3+118.125*w) elif (l,m) == (7,3): return (1-w**2)**1.5*(5630.625*w**4-2598.75*w**2+118.125) elif (l,m) == (7,4): return (1-w**2)**2*(22522.5*w**3-5197.5*w) elif (l,m) == (7,5): return (1-w**2)**2.5*(67567.5*w**2-5197.5) elif (l,m) == (7,6): return 135135*(1-w**2)**3*w elif (l,m) == (7,7): return 135135.*(1-w**2)**3.5 elif (l,m) == (8,0): return 50.2734375*w**8-93.84375*w**6+54.140625*w**4-9.84375*w**2+0.2734375 elif (l,m) == (8,1): return (1-w**2)**0.5*(402.1875*w**7-563.0625*w**5+216.5625*w**3-19.6875*w) elif (l,m) == (8,2): return (1-w**2)*(2815.3125*w**6-2815.3125*w**4+649.6875*w**2-19.6875) elif (l,m) == (8,3): return (1-w**2)**1.5*(16891.875*w**5-11261.25*w**3+1299.375*w) elif (l,m) == (8,4): return (1-w**2)**2*(84459.375*w**4-33783.75*w**2+1299.375) elif (l,m) == (8,5): return (1-w**2)**2.5*(337837.5*w**3-67567.5*w) elif (l,m) == (8,6): return (1-w**2)**3*(1013512.5*w**2-67567.5) elif (l,m) == (8,7): return 2027025*(1-w**2)**3.5*w elif (l,m) == (8,8): return 2027025*(1-w**2)**4 elif (l,m) == (9,0): return 94.9609375*w**9-201.09375*w**7+140.765625*w**5-36.09375*w**3+2.4609375*w elif (l,m) == (9,1): return (1-w**2)**0.5*(854.6484375*w**8-1407.65625*w**6+703.828125*w**4-108.28125*w**2+2.4609375) elif (l,m) == (9,2): return (1-w**2)*(6837.1875*w**7-8445.9375*w**5+2815.3125*w**3-216.5625*w) elif (l,m) == (9,3): return (1-w**2)**1.5*(47860.3125*w**6-42229.6875*w**4+8445.9375*w**2-216.5625) elif (l,m) == (9,4): return (1-w**2)**2*(287161.875*w**5-168918.75*w**3+16891.875*w) elif (l,m) == (9,5): return (1-w**2)**2.5*(1435809.375*w**4-506756.25*w**2+16891.875) elif (l,m) == (9,6): return (1-w**2)**3*(5743237.5*w**3-1013512.5*w) elif (l,m) == (9,7): return (1-w**2)**3.5*(17229712.5*w**2-1013512.5) elif (l,m) == (9,8): return 34459425*(1-w**2)**4*w elif (l,m) == (9,9): return 34459425*(1-w**2)**4.5 else: raise ValueError('Unsupported arguments (l,m)=(%d,%d)' % (l,m)) def dlegendre(l, m, w): # XXX not d/dw but rather -sin(theta)*d/dw if m < 0 or l < m: return np.zeros_like(w) if (l,m) == (0,0): return np.zeros_like(w) elif (l,m) == (1,0): return -(1-w**2)**0.5 elif (l,m) == (1,1): return w.copy() elif (l,m) == (2,0): return -3*w*(1-w**2)**0.5 elif (l,m) == (2,1): return 6*w**2-3 elif (l,m) == (2,2): return 6*(1-w**2)**0.5*w elif (l,m) == (3,0): return (1-w**2)**0.5*(-7.5*w**2+1.5) elif (l,m) == (3,1): return 22.5*w**3-16.5*w elif (l,m) == (3,2): return (1-w**2)**0.5*(45*w**2-15) elif (l,m) == (3,3): return 45*(1-w**2)*w elif (l,m) == (4,0): return (1-w**2)**0.5*(-17.5*w**3+7.5*w) elif (l,m) == (4,1): return 70*w**4-67.5*w**2+7.5 elif (l,m) == (4,2): return (1-w**2)**0.5*(210*w**3-120*w) elif (l,m) == (4,3): return (1-w**2)*(420*w**2-105) elif (l,m) == (4,4): return 420*(1-w**2)**1.5*w elif (l,m) == (5,0): return (1-w**2)**0.5*(-39.375*w**4+26.25*w**2-1.875) elif (l,m) == (5,1): return (196.875*w**5-236.25*w**3+54.375*w) elif (l,m) == (5,2): return (1-w**2)**0.5*(787.5*w**4-630*w**2+52.5) elif (l,m) == (5,3): return (1-w**2)*(2362.5*w**3-1102.5*w) elif (l,m) == (5,4): return (1-w**2)**1.5*(4725*w**2-945) elif (l,m) == (5,5): return 4725*(1-w**2)**2*w elif (l,m) == (6,0): return (1-w**2)**0.5*(-86.625*w**5+78.75*w**3-13.125*w) elif (l,m) == (6,1): return 519.75*w**6-748.125*w**4+262.5*w**2-13.125 elif (l,m) == (6,2): return (1-w**2)**0.5*(2598.75*w**5-2677.5*w**3+498.75*w) elif (l,m) == (6,3): return (1-w**2)*(10395.0*w**4-7087.5*w**2+472.5) elif (l,m) == (6,4): return (1-w**2)**1.5*(31185*w**3-12285*w) elif (l,m) == (6,5): return (1-w**2)**2*(62370*w**2-10395) elif (l,m) == (6,6): return 62370*(1-w**2)**2.5*w elif (l,m) == (7,0): return (1-w**2)**0.5*(-187.6875*w**6+216.5625*w**4-59.0625*w**2+2.1875) elif (l,m) == (7,1): return 1313.8125*w**7-2208.9375*w**5+1043.4375*w**3-120.3125*w elif (l,m) == (7,2): return (1-w**2)**0.5*(7882.875*w**6-9961.875*w**4+2953.125*w**2-118.125) elif (l,m) == (7,3): return (1-w**2)*(39414.375*w**5-35516.25*w**3+5551.875*w) elif (l,m) == (7,4): return (1-w**2)**1.5*(157657.5*w**4-93555*w**2+5197.5) elif (l,m) == (7,5): return (1-w**2)**2*(472972.5*w**3-161122.5*w) elif (l,m) == (7,6): return (1-w**2)**2.5*(945945*w**2-135135) elif (l,m) == (7,7): return 945945*(1-w**2)**3*w elif (l,m) == (8,0): return (1-w**2)**0.5*(-402.1875*w**7+563.0625*w**5-216.5625*w**3+19.6875*w) elif (l,m) == (8,1): return 3217.5*w**8-6193.6875*w**6+3681.5625*w**4-689.0625*w**2+19.6875 elif (l,m) == (8,2): return (1-w**2)**0.5*(22522.5*w**7-33783.75*w**5+13860.0*w**3-1338.75*w) elif (l,m) == (8,3): return (1-w**2)*(135135.0*w**6-152026.875*w**4+38981.25*w**2-1299.375) elif (l,m) == (8,4): return (1-w**2)**1.5*(675675.0*w**5-540540.0*w**3+72765.0*w) elif (l,m) == (8,5): return (1-w**2)**2*(2702700.0*w**4-1418917.5*w**2+67567.5) elif (l,m) == (8,6): return (1-w**2)**2.5*(8108100*w**3-2432430*w) elif (l,m) == (8,7): return (1-w**2)**3*(16216200*w**2-2027025) elif (l,m) == (8,8): return 16216200*(1-w**2)**3.5*w elif (l,m) == (9,0): return (1-w**2)**0.5*(-854.6484375*w**8+1407.65625*w**6-703.828125*w**4+108.28125*w**2-2.4609375) elif (l,m) == (9,1): return 7691.8359375*w**9-16690.78125*w**7+11965.078125*w**5-3140.15625*w**3+219.0234375*w elif (l,m) == (9,2): return (1-w**2)**0.5*(61534.6875*w**8-106981.875*w**6+56306.25*w**4-9095.625*w**2+216.5625) elif (l,m) == (9,3): return (1-w**2)*(430742.8125*w**7-582769.6875*w**5+211148.4375*w**3-17541.5625*w) elif (l,m) == (9,4): return (1-w**2)**1.5*(2584456.875*w**6-2618240.625*w**4+591215.625*w**2-16891.875) elif (l,m) == (9,5): return (1-w**2)**2*(12922284.375*w**5-9290531.25*w**3+1097971.875*w) elif (l,m) == (9,6): return (1-w**2)**2.5*(51689137.5*w**4-24324300*w**2+1013512.5) elif (l,m) == (9,7): return (1-w**2)**3*(155067412.5*w**3-41554012.5*w) elif (l,m) == (9,8): return (1-w**2)**3.5*(310134825*w**2-34459425) elif (l,m) == (9,9): return 310134825*(1-w**2)**4*w else: raise ValueError('Unsupported arguments (l,m)=(%d,%d)' % (l,m)) # ------------------------------------------------------------------- if __name__ == '__main__': from gpaw.mpi import world from gpaw.sphere import lmiter def equal(x, y, tol=0, msg=''): if abs(x-y) > tol: msg = (msg + '(%.9g,%.9g) != (%.9g,%.9g) (error: |%.9g| > %.9g)' % (np.real(x),np.imag(x),np.real(y),np.imag(y),abs(x-y),tol)) raise AssertionError(msg) nw = 10000 dw = 2.0/nw w = np.linspace(-1+dw/2,1-dw/2,nw) equal(w[1]-w[0], dw, 1e-12) tol = 1e-5 # Test orthogonality of the associated Legendre polynomials if world.rank == 0: print('\n%s\nAssociated Legendre orthogonality\n%s' % ('-'*40,'-'*40)) for l1,m1 in lmiter(lmax, False, comm=world): p1 = legendre(l1, m1, w) for l2,m2 in lmiter(lmax, False): p2 = legendre(l2, m2, w) scale = (ilegendre(l1,m1)*ilegendre(l2,m2))**0.5 v = np.dot(p1,p2)*dw / scale if (l1,m1) == (l2,m2): v0 = ilegendre(l1,m1) / scale print('l1=%2d, m1=%2d, l2=%2d, m2=%2d, v=%12.9f, err=%12.9f' % (l1,m1,l2,m2,v,abs(v-v0))) equal(v, v0, tol, 'l1=%2d, m1=%2d, l2=%2d, m=%2d: ' % (l1,m1,l2,m2)) elif m1 == m2: print('l1=%2d, m1=%2d, l2=%2d, m2=%2d, v=%12.9f, err=%12.9f' % (l1,m1,l2,m2,v,abs(v))) equal(v, 0, tol, 'l1=%2d, m1=%2d, l2=%2d, m=%2d: ' % (l1,m1,l2,m2)) del nw, dw, w, tol, p1, p2, v, v0 world.barrier() # ======================= nw = 50000 dw = 1.9/nw w = np.linspace(-0.95+dw/2,0.95-dw/2,nw) tol = 1e-5 # Test theta-derivative of the associated Legendre polynomials if world.rank == 0: print('\n%s\nAssociated Legendre theta-derivative\n%s' % ('-'*40,'-'*40)) for l,m in lmiter(lmax, False, comm=world): scale = l**(-abs(m))*lmfact(l,abs(m)) # scale to fit ~ [-1; 1] p = legendre(l, m, w) / scale dpdtheta = -(1-w[1:-1]**2)**0.5*(p[2:]-p[:-2])/(2.0*dw) dpdtheta0 = dlegendre(l, m, w[1:-1]) / scale e = np.sum((dpdtheta-dpdtheta0)**2)**0.5/(nw-2.0)**0.5 print('l=%2d, m=%2d, err=%12.9f, max=%12.9f' % (l,m,e,np.abs(dpdtheta-dpdtheta0).max())) #if e > tol: # import pylab as pl # w, p = w[1:-1], p[1:-1] # fig = pl.figure(lm_to_L(l,m)) # ax = pl.axes() # ax.plot(w, p,'-r', w, dpdtheta, '-b', w, dpdtheta0, '-g') # fig = pl.figure((lmax+1)**2+lm_to_L(l,m)) # ax = pl.axes() # ax.plot(w, dpdtheta-dpdtheta0, '-k') # pl.show() equal(e, 0, tol, 'l=%2d, m=%2d: ' % (l,m)) del nw, dw, w, tol, p, dpdtheta, dpdtheta0, e world.barrier() # ======================= R = 1.0 npts = 1000 tol = 1e-9 # ((R-dR)/(R+dR))**(lmax+1) = tol # (lmax+1)*np.log((R-dR)/(R+dR)) = np.log(tol) # (R-dR)/(R+dR) = np.exp(np.log(tol)/(lmax+1)) # R-dR = (R+dR) * tol**(1/(lmax+1)) # R * (1-tol**(1/(lmax+1))) = dR * (1+tol**(1/(lmax+1))) dR = R * (1-tol**(1./(lmax+1))) / (1+tol**(1./(lmax+1))) assert abs(((R-dR)/(R+dR))**(lmax+1) - tol) < 1e-12 r_g = np.random.uniform(R+dR, 10*R, size=npts) world.broadcast(r_g, 0) theta_g = np.random.uniform(0, np.pi, size=npts) world.broadcast(theta_g, 0) phi_g = np.random.uniform(0, np.pi, size=npts) world.broadcast(phi_g, 0) r_vg = np.empty((3, npts), dtype=float) r_vg[0] = r_g*np.cos(phi_g)*np.sin(theta_g) r_vg[1] = r_g*np.sin(phi_g)*np.sin(theta_g) r_vg[2] = r_g*np.cos(theta_g) rm_g = np.random.uniform(0, R-dR, size=npts) world.broadcast(rm_g, 0) thetam_g = np.random.uniform(0, np.pi, size=npts) world.broadcast(thetam_g, 0) phim_g = np.random.uniform(0, np.pi, size=npts) world.broadcast(phim_g, 0) rm_vg = np.empty((3, npts), dtype=float) rm_vg[0] = rm_g*np.cos(phim_g)*np.sin(thetam_g) rm_vg[1] = rm_g*np.sin(phim_g)*np.sin(thetam_g) rm_vg[2] = rm_g*np.cos(thetam_g) # Cosine of the angle between r and r' using 1st spherical law of cosines w_g = np.cos(theta_g)*np.cos(thetam_g) \ + np.sin(theta_g)*np.sin(thetam_g)*np.cos(phi_g-phim_g) f0_g = np.sum((r_vg-rm_vg)**2, axis=0)**(-0.5) f_g = np.zeros_like(f0_g) # Test truncated multi-pole expansion using Legendre polynomials if world.rank == 0: print('\n%s\nLegendre multi-pole expansion\n%s' % ('-'*40,'-'*40)) for l in range(lmax+1): f_g += 1/r_g * (rm_g/r_g)**l * legendre(l, 0, w_g) e = np.abs(f_g-f0_g).max() equal(e, 0, tol, 'lmax=%02d, dR=%g: ' % (lmax, dR)) del R, dR, npts, tol, r_g, theta_g, phi_g, r_vg, rm_g, thetam_g, phim_g, rm_vg, w_g, f0_g, f_g, e gpaw-0.11.0.13004/gpaw/sphere/__init__.py0000664000175000017500000000257312553643472020022 0ustar jensjjensj00000000000000 import numpy as np #from gpaw.utilities import ffact # Define (l+|m|)!/(l-|m|)! #lmfact = lambda l,m: ffact(l-abs(m), l+abs(m)) def _lmiter(lmax, full=True): for l in range(lmax+1): for m in range(full and -l or 0,l+1): yield (l,m) raise StopIteration def lmiter(lmax, full=True, comm=None, cost=None): """Utility function to parallelize over (l,m) with load balancing.""" if comm is None or comm.size == 1: return _lmiter(lmax ,full) lm_j = tuple(_lmiter(lmax, full)) if cost is None: cost_j = np.ones(len(lm_j), dtype=float) else: cost_j = np.fromiter((cost(lmax, *lm) for lm in lm_j), dtype=float) assert np.isfinite(cost_j).all() and np.all(cost_j>0) #XXX and np.isreal? a,b = np.array([comm.rank,comm.rank+1], dtype=float) / comm.size if 0: #XXX which one is best? rel_j = np.cumsum(np.hstack((0,cost_j)))/np.sum(cost_j) ja,jb = np.argmin(np.abs(rel_j-a)), np.argmin(np.abs(rel_j-b)) else: rel_j = np.cumsum(cost_j)/np.sum(cost_j) ja,jb = np.take(np.argwhere(np.bitwise_and(a 0: self.A_wgm.append(A_gm) self.G_wb.append(G_b) self.M_w.append(M) self.sdisp_wc.append(sdisp_c) ng += A_gm.shape[0] assert A_gm.shape[0] > 0 M += 2 * l + 1 self.Mmax = M self.rank = gd.get_rank_from_position(spos_c) if ng == 0: self.ranks = None # What about making empty lists instead? self.A_wgm = None self.G_wb = None self.M_w = None self.sdisp_wc = None self.spos_c = spos_c.copy() self.normalized = False return True def spline_to_grid(spline, gd, start_c, end_c, spos_c): dom = gd pos_v = np.dot(spos_c, dom.cell_cv) return _gpaw.spline_to_grid(spline.spline, start_c, end_c, pos_v, np.ascontiguousarray(gd.h_cv), gd.n_c, gd.beg_c) # TODO This belongs in Spline! spline_to_grid = staticmethod(spline_to_grid) def get_function_count(self): return sum([2 * spline.get_angular_momentum_number() + 1 for spline in self.spline_j]) def normalize(self, integral, a, dv, comm): """Normalize localized functions.""" if self.normalized or integral < 1e-15: self.normalized = True yield None yield None yield None return I_M = np.zeros(self.Mmax) nw = len(self.A_wgm) // len(self.spline_j) assert nw * len(self.spline_j) == len(self.A_wgm) for M, A_gm in zip(self.M_w, self.A_wgm): I_m = A_gm.sum(axis=0) I_M[M:M + len(I_m)] += I_m * dv requests = [] if len(self.ranks) > 0: I_rM = np.empty((len(self.ranks), self.Mmax)) for r, J_M in zip(self.ranks, I_rM): requests.append(comm.receive(J_M, r, a, False)) if self.rank != comm.rank: requests.append(comm.send(I_M, self.rank, a, False)) yield None for request in requests: comm.wait(request) requests = [] if len(self.ranks) > 0: I_M += I_rM.sum(axis=0) for r in self.ranks: requests.append(comm.send(I_M, r, a, False)) if self.rank != comm.rank: requests.append(comm.receive(I_M, self.rank, a, False)) yield None for request in requests: comm.wait(request) w = 0 for M, A_gm in zip(self.M_w, self.A_wgm): if M == 0: A_gm *= integral / I_M[0] else: A_gm -= (I_M[M:M + A_gm.shape[1]] / integral * self.A_wgm[w % nw]) w += 1 self.normalized = True self.I_M = I_M yield None def estimate_gridpointcount(self, gd): points = 0.0 for spline in self.spline_j: l = spline.get_angular_momentum_number() rc = spline.get_cutoff() points += 4.0 * np.pi / 3.0 * rc**3 / gd.dv * (2 * l + 1) return points # Quick hack: base class to share basic functionality across LFC classes class BaseLFC: def dict(self, shape=(), derivative=False, zero=False): if isinstance(shape, int): shape = (shape,) if derivative: assert not zero c_axiv = {} for a in self.my_atom_indices: ni = self.get_function_count(a) c_axiv[a] = np.empty(shape + (ni, 3), self.dtype) return c_axiv else: c_axi = {} for a in self.my_atom_indices: ni = self.get_function_count(a) c_axi[a] = np.empty(shape + (ni,), self.dtype) if zero: c_axi[a].fill(0.0) return c_axi def estimate_memory(self, mem): points = 0 for sphere in self.sphere_a: points += sphere.estimate_gridpointcount(self.gd) nbytes = points * mem.floatsize mem.setsize(nbytes / self.gd.comm.size) # Assume equal distribution class NewLocalizedFunctionsCollection(BaseLFC): """New LocalizedFunctionsCollection Utilizes that localized functions can be stored on a spherical subset of the uniform grid, as opposed to LocalizedFunctionsCollection which is just a wrapper around the old localized_functions which use rectangular grids. """ def __init__(self, gd, spline_aj, kd=None, cut=False, dtype=float, integral=None, forces=None): self.gd = gd self.sphere_a = [Sphere(spline_j) for spline_j in spline_aj] self.cut = cut self.dtype = dtype self.Mmax = None if kd is None: self.ibzk_qc = np.zeros((1, 3)) self.gamma = True else: self.ibzk_qc = kd.ibzk_qc self.gamma = kd.gamma # Global or local M-indices? self.use_global_indices = False if integral is not None: if isinstance(integral, (float, int)): self.integral_a = np.empty(len(spline_aj)) self.integral_a[:] = integral else: self.integral_a = np.array(integral) else: self.integral_a = None self.my_atom_indices = None def set_positions(self, spos_ac): assert len(spos_ac) == len(self.sphere_a) spos_ac = np.asarray(spos_ac) movement = False for a, (spos_c, sphere) in enumerate(zip(spos_ac, self.sphere_a)): try: movement |= sphere.set_position(spos_c, self.gd, self.cut) except GridBoundsError as e: e.args = ['Atom %d too close to edge: %s' % (a, str(e))] raise if movement or self.my_atom_indices is None: self._update(spos_ac) def _update(self, spos_ac): nB = 0 nW = 0 self.my_atom_indices = [] self.atom_indices = [] M = 0 self.M_a = [] for a, sphere in enumerate(self.sphere_a): self.M_a.append(M) if sphere.rank == self.gd.comm.rank: self.my_atom_indices.append(a) G_wb = sphere.G_wb if G_wb: nB += sum([len(G_b) for G_b in G_wb]) nW += len(G_wb) self.atom_indices.append(a) if not self.use_global_indices: M += sphere.Mmax if self.use_global_indices: M += sphere.Mmax self.Mmax = M natoms = len(spos_ac) # Holm-Nielsen check: if ((self.gd.comm.sum(float(sum(self.my_atom_indices))) != natoms * (natoms - 1) // 2)): raise ValueError('Holm-Nielsen check failed. Grid might be ' 'too coarse. Use h < %.3f' % (smallest_safe_grid_spacing * Bohr)) self.M_W = np.empty(nW, np.intc) self.G_B = np.empty(nB, np.intc) self.W_B = np.empty(nB, np.intc) self.A_Wgm = [] sdisp_Wc = np.empty((nW, 3), int) self.pos_Wv = np.empty((nW, 3)) B1 = 0 W = 0 for a in self.atom_indices: sphere = self.sphere_a[a] self.A_Wgm.extend(sphere.A_wgm) nw = len(sphere.M_w) self.M_W[W:W + nw] = self.M_a[a] + np.array(sphere.M_w) sdisp_Wc[W:W + nw] = sphere.sdisp_wc self.pos_Wv[W:W + nw] = np.dot(spos_ac[a] - np.array(sphere.sdisp_wc), self.gd.cell_cv) for G_b in sphere.G_wb: B2 = B1 + len(G_b) self.G_B[B1:B2] = G_b self.W_B[B1:B2:2] = W self.W_B[B1 + 1:B2 + 1:2] = -W - 1 B1 = B2 W += 1 assert B1 == nB if self.gamma: if self.dtype == float: self.phase_qW = np.empty((0, nW), complex) else: # TDDFT calculation: self.phase_qW = np.ones((1, nW), complex) else: self.phase_qW = np.exp(2j * pi * np.inner(self.ibzk_qc, sdisp_Wc)) indices = np.argsort(self.G_B, kind='mergesort') self.G_B = self.G_B[indices] self.W_B = self.W_B[indices] self.lfc = _gpaw.LFC(self.A_Wgm, self.M_W, self.G_B, self.W_B, self.gd.dv, self.phase_qW) # Find out which ranks have a piece of the # localized functions: x_a = np.zeros(natoms, bool) x_a[self.atom_indices] = True x_a[self.my_atom_indices] = False x_ra = np.empty((self.gd.comm.size, natoms), bool) self.gd.comm.all_gather(x_a, x_ra) for a in self.atom_indices: sphere = self.sphere_a[a] if sphere.rank == self.gd.comm.rank: sphere.ranks = x_ra[:, a].nonzero()[0] else: sphere.ranks = [] if self.integral_a is not None: iterators = [] for a in self.atom_indices: iterator = self.sphere_a[a].normalize(self.integral_a[a], a, self.gd.dv, self.gd.comm) iterators.append(iterator) for i in range(3): for iterator in iterators: next(iterator) return sdisp_Wc def M_to_ai(self, src_xM, dst_axi): xshape = src_xM.shape[:-1] src_xM = src_xM.reshape(np.prod(xshape), self.Mmax) for a in self.my_atom_indices: M1 = self.M_a[a] M2 = M1 + self.sphere_a[a].Mmax dst_axi[a] = src_xM[:, M1:M2].copy() def ai_to_M(self, src_axi, dst_xM): xshape = dst_xM.shape[:-1] dst_xM = dst_xM.reshape(np.prod(xshape), self.Mmax) for a in self.my_atom_indices: M1 = self.M_a[a] M2 = M1 + self.sphere_a[a].Mmax dst_xM[:, M1:M2] = src_axi[a] def add(self, a_xG, c_axi=1.0, q=-1): """Add localized functions to extended arrays. :: -- a a a (G) += > c Phi (G) x -- xi i a,i """ assert not self.use_global_indices if q == -1: assert self.dtype == float if isinstance(c_axi, float): assert q == -1 and a_xG.ndim == 3 c_xM = np.empty(self.Mmax) c_xM.fill(c_axi) self.lfc.add(c_xM, a_xG, q) return dtype = a_xG.dtype if debug: assert a_xG.ndim >= 3 assert sorted(c_axi.keys()) == self.my_atom_indices for c_xi in c_axi.values(): assert c_xi.dtype == dtype comm = self.gd.comm xshape = a_xG.shape[:-3] requests = [] M1 = 0 b_axi = {} for a in self.atom_indices: c_xi = c_axi.get(a) sphere = self.sphere_a[a] M2 = M1 + sphere.Mmax if c_xi is None: c_xi = np.empty(xshape + (sphere.Mmax,), dtype) b_axi[a] = c_xi requests.append(comm.receive(c_xi, sphere.rank, a, False)) else: for r in sphere.ranks: requests.append(comm.send(c_xi, r, a, False)) M1 = M2 for request in requests: comm.wait(request) c_xM = np.empty(xshape + (self.Mmax,), dtype) M1 = 0 for a in self.atom_indices: c_xi = c_axi.get(a) sphere = self.sphere_a[a] M2 = M1 + sphere.Mmax if c_xi is None: c_xi = b_axi[a] c_xM[..., M1:M2] = c_xi M1 = M2 self.lfc.add(c_xM, a_xG, q) def add_derivative(self, a, v, a_xG, c_axi=1.0, q=-1): """Add derivative of localized functions on atom to extended arrays. Parameters ---------- a: int Atomic index of the derivative v: int Cartesian coordinate of the derivative (0, 1 or 2) This function adds the following sum to the extended arrays:: -- a a a (G) += > c dPhi (G) x -- xi iv i where:: a d a dPhi (G) = -- Phi (g) iv dv i is the derivative of the Phi^a and v is either x, y, or z. """ assert v in [0, 1, 2] assert not self.use_global_indices if q == -1: assert self.dtype == float if isinstance(c_axi, float): assert q == -1 c_xM = np.empty(self.Mmax) c_xM.fill(c_axi) self.lfc.add(c_xM, a_xG, q) return dtype = a_xG.dtype if debug: assert a_xG.ndim >= 3 assert dtype == self.dtype if isinstance(c_axi, dict): assert sorted(c_axi.keys()) == self.my_atom_indices for c_xi in c_axi.values(): assert c_xi.dtype == dtype cspline_M = [] for a_ in self.atom_indices: for spline in self.sphere_a[a_].spline_j: nm = 2 * spline.get_angular_momentum_number() + 1 cspline_M.extend([spline.spline] * nm) # Temp solution - set all coefficient to zero except for those at # atom a # Coefficient indices for atom a M1 = self.M_a[a] M2 = M1 + self.sphere_a[a].Mmax if isinstance(c_axi, float): assert q == -1 c_xM = np.zeros(self.Mmax) c_xM[..., M1:M2] = c_axi else: xshape = a_xG.shape[:-3] c_xM = np.zeros(xshape + (self.Mmax,), dtype) c_xM[..., M1:M2] = c_axi[a] gd = self.gd self.lfc.add_derivative(c_xM, a_xG, np.ascontiguousarray(gd.h_cv), gd.n_c, cspline_M, gd.beg_c, self.pos_Wv, a, v, q) def integrate(self, a_xG, c_axi, q=-1): """Calculate integrals of arrays times localized functions. :: / a* c_axi = | dG a (G) Phi (G) / x i """ assert not self.use_global_indices if q == -1: assert self.dtype == float xshape = a_xG.shape[:-3] if debug: assert a_xG.ndim >= 3 assert sorted(c_axi.keys()) == self.my_atom_indices for c_xi in c_axi.values(): assert c_xi.shape[:-1] == xshape dtype = a_xG.dtype c_xM = np.zeros(xshape + (self.Mmax,), dtype) self.lfc.integrate(a_xG, c_xM, q) comm = self.gd.comm rank = comm.rank srequests = [] rrequests = [] c_arxi = {} b_axi = {} M1 = 0 for a in self.atom_indices: sphere = self.sphere_a[a] M2 = M1 + sphere.Mmax if sphere.rank != rank: c_xi = c_xM[..., M1:M2].copy() b_axi[a] = c_xi srequests.append(comm.send(c_xi, sphere.rank, a, False)) else: if len(sphere.ranks) > 0: c_rxi = np.empty(sphere.ranks.shape + xshape + (M2 - M1,), dtype) c_arxi[a] = c_rxi for r, b_xi in zip(sphere.ranks, c_rxi): rrequests.append(comm.receive(b_xi, r, a, False)) M1 = M2 for request in rrequests: comm.wait(request) M1 = 0 for a in self.atom_indices: c_xi = c_axi.get(a) sphere = self.sphere_a[a] M2 = M1 + sphere.Mmax if c_xi is not None: if len(sphere.ranks) > 0: c_xi[:] = c_xM[..., M1:M2] + c_arxi[a].sum(axis=0) else: c_xi[:] = c_xM[..., M1:M2] M1 = M2 for request in srequests: comm.wait(request) def derivative(self, a_xG, c_axiv, q=-1): """Calculate x-, y-, and z-derivatives of localized function integrals. :: / a* c_axiv = | dG a (G) dPhi (G) / x iv where:: a d a dPhi (G) = -- Phi (g) iv dv i and v is either x, y, or z, and R^a_v is the center of Phi^a. Notice that d Phi^a_i / dR^a_v == - d Phi^a_i / d v. """ assert not self.use_global_indices if debug: assert a_xG.ndim >= 3 assert sorted(c_axiv.keys()) == self.my_atom_indices if self.integral_a is not None: assert q == -1 assert a_xG.ndim == 3 assert a_xG.dtype == float self._normalized_derivative(a_xG, c_axiv) return dtype = a_xG.dtype xshape = a_xG.shape[:-3] c_xMv = np.zeros(xshape + (self.Mmax, 3), dtype) cspline_M = [] for a in self.atom_indices: for spline in self.sphere_a[a].spline_j: nm = 2 * spline.get_angular_momentum_number() + 1 cspline_M.extend([spline.spline] * nm) gd = self.gd self.lfc.derivative(a_xG, c_xMv, np.ascontiguousarray(gd.h_cv), gd.n_c, cspline_M, gd.beg_c, self.pos_Wv, q) comm = self.gd.comm rank = comm.rank srequests = [] rrequests = [] c_arxiv = {} # see also http://arXiv.org b_axiv = {} M1 = 0 for a in self.atom_indices: sphere = self.sphere_a[a] M2 = M1 + sphere.Mmax if sphere.rank != rank: c_xiv = c_xMv[..., M1:M2, :].copy() b_axiv[a] = c_xiv srequests.append(comm.send(c_xiv, sphere.rank, a, False)) else: if len(sphere.ranks) > 0: c_rxiv = np.empty(sphere.ranks.shape + xshape + (M2 - M1, 3), dtype) c_arxiv[a] = c_rxiv for r, b_xiv in zip(sphere.ranks, c_rxiv): rrequests.append(comm.receive(b_xiv, r, a, False)) M1 = M2 for request in rrequests: comm.wait(request) M1 = 0 for a in self.atom_indices: c_xiv = c_axiv.get(a) sphere = self.sphere_a[a] M2 = M1 + sphere.Mmax if c_xiv is not None: if len(sphere.ranks) > 0: c_xiv[:] = c_xMv[..., M1:M2, :] + c_arxiv[a].sum(axis=0) else: c_xiv[:] = c_xMv[..., M1:M2, :] M1 = M2 for request in srequests: comm.wait(request) def _normalized_derivative(self, a_G, c_aiv): """Calculate x-, y-, and z-derivatives of localized function integrals. Calculates the derivatives of this integral:: a / _ _ a - _a A = | dr a(r) f (r - R ), lm / lm a dA lm c_aiv = ----, a R v where v is either x, y, or z and i=l**2+m. Note that the actual integrals used are normalized:: a ~a a I f = f ---, 00 00 a I 00 and for l > 0:: a I ~a a a lm f = f - f ---, lm lm 00 a I 00 where :: a / _ -a _ _a I = | dr f (r - R ), lm / lm so the derivative look pretty ugly! """ c_Mv = np.zeros((self.Mmax, 7)) cspline_M = [] for a in self.atom_indices: for spline in self.sphere_a[a].spline_j: nm = 2 * spline.get_angular_momentum_number() + 1 cspline_M.extend([spline.spline] * nm) gd = self.gd self.lfc.normalized_derivative(a_G, c_Mv, np.ascontiguousarray(gd.h_cv), gd.n_c, cspline_M, gd.beg_c, self.pos_Wv) comm = self.gd.comm rank = comm.rank srequests = [] rrequests = [] c_ariv = {} b_aiv = {} M1 = 0 for a in self.atom_indices: sphere = self.sphere_a[a] M2 = M1 + sphere.Mmax if sphere.rank != rank: c_iv = c_Mv[M1:M2].copy() b_aiv[a] = c_iv srequests.append(comm.send(c_iv, sphere.rank, a, False)) else: if len(sphere.ranks) > 0: c_riv = np.empty((len(sphere.ranks), M2 - M1, 7)) c_ariv[a] = c_riv for r, b_iv in zip(sphere.ranks, c_riv): rrequests.append(comm.receive(b_iv, r, a, False)) M1 = M2 for request in rrequests: comm.wait(request) M1 = 0 for a in self.atom_indices: c_iv = c_aiv.get(a) sphere = self.sphere_a[a] M2 = M1 + sphere.Mmax if c_iv is not None: I = self.integral_a[a] if I > 1e-15: if len(sphere.ranks) > 0: c_Mv[M1:M2] += c_ariv[a].sum(axis=0) I_L = sphere.I_M I0 = I_L[0] c_Lv = c_Mv[M1:M2, :3] b_Lv = c_Mv[M1:M2, 3:6] A0 = c_Mv[M1, 6] c_iv[0, :] = (I / I0 * c_Lv[0] - I / I0**2 * b_Lv[0] * A0) c_iv[1:, :] = (c_Lv[1:] - np.outer(I_L[1:] / I0, c_Lv[0]) - A0 / I0 * b_Lv[1:] + A0 / I0**2 * np.outer(I_L[1:], b_Lv[0])) else: c_iv[:] = 0.0 M1 = M2 for request in srequests: comm.wait(request) def second_derivative(self, a_xG, c_axivv, q=-1): """Calculate second derivatives. Works only for this type of input for now:: second_derivative(self, a_G, c_avv, q=-1) :: 2 a _ _a / _ _ d f (r-R ) c_avv = | dr a(r) ---------- / a a dR dR i j """ assert not self.use_global_indices if debug: assert a_xG.ndim == 3 assert a_xG.dtype == self.dtype assert sorted(c_axivv.keys()) == self.my_atom_indices dtype = a_xG.dtype c_Mvv = np.zeros((self.Mmax, 3, 3), dtype) cspline_M = [] for a in self.atom_indices: # Works only for atoms with a single function assert len(self.sphere_a[a].spline_j) == 1 spline = self.sphere_a[a].spline_j[0] # that is spherical symmetric assert spline.get_angular_momentum_number() == 0 cspline_M.append(spline.spline) gd = self.gd self.lfc.second_derivative(a_xG, c_Mvv, np.ascontiguousarray(gd.h_cv), gd.n_c, cspline_M, gd.beg_c, self.pos_Wv, q) comm = self.gd.comm rank = comm.rank srequests = [] rrequests = [] c_arvv = {} b_avv = {} M1 = 0 for a in self.atom_indices: sphere = self.sphere_a[a] M2 = M1 + sphere.Mmax if sphere.rank != rank: c_vv = c_Mvv[M1:M2].copy() b_avv[a] = c_vv srequests.append(comm.send(c_vv, sphere.rank, a, False)) else: if len(sphere.ranks) > 0: c_rvv = np.empty(sphere.ranks.shape + (3, 3), dtype) c_arvv[a] = c_rvv for r, b_vv in zip(sphere.ranks, c_rvv): rrequests.append(comm.receive(b_vv, r, a, False)) M1 = M2 for request in rrequests: comm.wait(request) M1 = 0 for a in self.atom_indices: c_vv = c_axivv.get(a) sphere = self.sphere_a[a] M2 = M1 + sphere.Mmax if c_vv is not None: if len(sphere.ranks) > 0: c_vv[:] = c_Mvv[M1] + c_arvv[a].sum(axis=0) else: c_vv[:] = c_Mvv[M1] M1 = M2 for request in srequests: comm.wait(request) def griditer(self): """Iterate over grid points.""" self.g_W = np.zeros(len(self.M_W), np.intc) self.current_lfindices = [] G1 = 0 for W, G in zip(self.W_B, self.G_B): G2 = G yield G1, G2 self.g_W[self.current_lfindices] += G2 - G1 if W >= 0: self.current_lfindices.append(W) else: self.current_lfindices.remove(-1 - W) G1 = G2 def get_function_count(self, a): return self.sphere_a[a].get_function_count() class BasisFunctions(NewLocalizedFunctionsCollection): def __init__(self, gd, spline_aj, kd=None, cut=False, dtype=float, integral=None, forces=None): NewLocalizedFunctionsCollection.__init__(self, gd, spline_aj, kd, cut, dtype, integral, forces) self.use_global_indices = True self.Mstart = None self.Mstop = None def set_positions(self, spos_ac): NewLocalizedFunctionsCollection.set_positions(self, spos_ac) self.Mstart = 0 self.Mstop = self.Mmax def _update(self, spos_ac): sdisp_Wc = NewLocalizedFunctionsCollection._update(self, spos_ac) if not self.gamma or self.dtype == complex: self.x_W, self.sdisp_xc = self.create_displacement_arrays(sdisp_Wc) return sdisp_Wc def create_displacement_arrays(self, sdisp_Wc=None): if sdisp_Wc is None: sdisp_Wc = np.empty((len(self.M_W), 3), int) W = 0 for a in self.atom_indices: sphere = self.sphere_a[a] nw = len(sphere.M_w) sdisp_Wc[W:W + nw] = sphere.sdisp_wc W += nw if len(sdisp_Wc) > 0: n_c = sdisp_Wc.max(0) - sdisp_Wc.min(0) else: n_c = np.zeros(3, int) N_c = 2 * n_c + 1 stride_c = np.array([N_c[1] * N_c[2], N_c[2], 1]) x_W = np.dot(sdisp_Wc, stride_c).astype(np.intc) # use a neighbor list instead? x1 = np.dot(n_c, stride_c) sdisp_xc = np.zeros((x1 + 1, 3), int) r_x, sdisp_xc[:, 2] = divmod(np.arange(x1, 2 * x1 + 1), N_c[2]) sdisp_xc.T[:2] = divmod(r_x, N_c[1]) sdisp_xc -= n_c return x_W, sdisp_xc def set_matrix_distribution(self, Mstart, Mstop): assert self.Mmax is not None self.Mstart = Mstart self.Mstop = Mstop def add_to_density(self, nt_sG, f_asi): """Add linear combination of squared localized functions to density. :: ~ -- a / a \2 n (r) += > f | Phi (r) | s -- si \ i / a,i """ nspins = len(nt_sG) f_sM = np.empty((nspins, self.Mmax)) for a in self.atom_indices: sphere = self.sphere_a[a] M1 = self.M_a[a] M2 = M1 + sphere.Mmax f_sM[:, M1:M2] = f_asi[a] for nt_G, f_M in zip(nt_sG, f_sM): self.lfc.construct_density1(f_M, nt_G) def construct_density(self, rho_MM, nt_G, q): """Calculate electron density from density matrix. rho_MM: ndarray Density matrix. nt_G: ndarray Pseudo electron density. :: ~ -- * n(r) += > Phi (r) rho Phi (r) -- M1 M1M2 M2 M1,M2 """ self.lfc.construct_density(rho_MM, nt_G, q, self.Mstart, self.Mstop) def integrate2(self, a_xG, c_xM, q=-1): """Calculate integrals of arrays times localized functions. :: / * c_xM += = | dG Phi (G) a (G) M x / M x """ xshape, Gshape = a_xG.shape[:-3], a_xG.shape[-3:] Nx = int(np.prod(xshape)) a_xG = a_xG.reshape((Nx,) + Gshape) c_xM = c_xM.reshape(Nx, -1) for a_G, c_M in zip(a_xG, c_xM): self.lfc.integrate(a_G, c_M, q) def calculate_potential_matrices(self, vt_G): """Calculate lower part of potential matrix. :: / ~ | * _ ~ _ _ _ V = | Phi (r) v(r) Phi (r) dr for mu >= nu mu nu | mu nu / Overwrites the elements of the target matrix Vt_MM. """ if self.gamma and self.dtype == float: Vt_xMM = np.zeros((1, self.Mstop - self.Mstart, self.Mmax)) self.lfc.calculate_potential_matrix(vt_G, Vt_xMM[0], -1, self.Mstart, self.Mstop) else: Vt_xMM = np.zeros((len(self.sdisp_xc), self.Mstop - self.Mstart, self.Mmax)) self.lfc.calculate_potential_matrices(vt_G, Vt_xMM, self.x_W, self.Mstart, self.Mstop) return Vt_xMM def calculate_potential_matrix(self, vt_G, Vt_MM, q): """Calculate lower part of potential matrix. :: / ~ | * _ ~ _ _ _ V = | Phi (r) v(r) Phi (r) dr for mu >= nu mu nu | mu nu / Overwrites the elements of the target matrix Vt_MM. """ Vt_MM[:] = 0.0 self.lfc.calculate_potential_matrix(vt_G, Vt_MM, q, self.Mstart, self.Mstop) def lcao_to_grid(self, C_xM, psit_xG, q): """Deploy basis functions onto grids according to coefficients. :: ---- ~ _ \ _ psi (r) += ) C Phi (r) n / n mu mu ---- mu """ if C_xM.size == 0: return C_xM = C_xM.reshape((-1,) + C_xM.shape[-1:]) psit_xG = psit_xG.reshape((-1,) + psit_xG.shape[-3:]) if self.gamma or len(C_xM) == 1: for C_M, psit_G in zip(C_xM, psit_xG): self.lfc.lcao_to_grid(C_M, psit_G, q) else: # Do sum over unit cells first followed by sum over bands # in blocks of 10 orbitals at the time: assert C_xM.flags.contiguous assert psit_xG.flags.contiguous self.lfc.lcao_to_grid_k(C_xM, psit_xG, q, 10) def calculate_potential_matrix_derivative(self, vt_G, DVt_vMM, q): """Calculate derivatives of potential matrix elements. :: / * _ | Phi (r) ~c | mu ~ _ _ _ DV += | -------- v(r) Phi (r) dr mu nu | dr nu / c Results are added to DVt_vMM. """ cspline_M = [] for a, sphere in enumerate(self.sphere_a): for j, spline in enumerate(sphere.spline_j): nm = 2 * spline.get_angular_momentum_number() + 1 cspline_M.extend([spline.spline] * nm) gd = self.gd for v in range(3): self.lfc.calculate_potential_matrix_derivative( vt_G, DVt_vMM[v], np.ascontiguousarray(gd.h_cv), gd.n_c, q, v, np.array(cspline_M), gd.beg_c, self.pos_Wv, self.Mstart, self.Mstop) def calculate_force_contribution(self, vt_G, rhoT_MM, q): """Calculate derivatives of potential matrix elements. :: / * _ | Phi (r) ~c | mu ~ _ _ _ DV += | -------- v(r) Phi (r) dr mu nu | dr nu / c Results are added to DVt_vMM. """ cspline_M = [] for a, sphere in enumerate(self.sphere_a): for j, spline in enumerate(sphere.spline_j): nm = 2 * spline.get_angular_momentum_number() + 1 cspline_M.extend([spline.spline] * nm) gd = self.gd Mstart = self.Mstart Mstop = self.Mstop F_vM = np.zeros((3, Mstop - Mstart)) assert self.Mmax == rhoT_MM.shape[1] assert Mstop - Mstart == rhoT_MM.shape[0] for v in range(3): self.lfc.calculate_potential_matrix_force_contribution( vt_G, rhoT_MM, F_vM[v], np.ascontiguousarray(gd.h_cv), gd.n_c, q, v, np.array(cspline_M), gd.beg_c, self.pos_Wv, Mstart, Mstop) F_av = np.zeros((len(self.M_a), 3)) a = 0 for a, M1 in enumerate(self.M_a): M1 -= Mstart M2 = M1 + self.sphere_a[a].Mmax if M2 < 0: continue M1 = max(0, M1) F_av[a, :] = 2.0 * F_vM[:, M1:M2].sum(axis=1) return F_av from gpaw.localized_functions import LocFuncs, LocFuncBroadcaster from gpaw.mpi import run class LocalizedFunctionsCollection(BaseLFC): def __init__(self, gd, spline_aj, kpt_comm=None, cut=False, dtype=float, integral=None, forces=False): self.gd = gd self.spline_aj = spline_aj self.cut = cut self.forces = forces self.dtype = dtype self.integral_a = integral self.spos_ac = None self.lfs_a = {} self.ibzk_qc = None self.gamma = True self.kpt_comm = kpt_comm self.my_atom_indices = None def set_positions(self, spos_ac): if self.kpt_comm: lfbc = LocFuncBroadcaster(self.kpt_comm) else: lfbc = None for a, spline_j in enumerate(self.spline_aj): if self.spos_ac is None or (self.spos_ac[a] != spos_ac[a]).any(): lfs = LocFuncs(spline_j, self.gd, spos_ac[a], self.dtype, self.cut, self.forces, lfbc) if len(lfs.box_b) > 0: if not self.gamma: lfs.set_phase_factors(self.ibzk_qc) self.lfs_a[a] = lfs elif a in self.lfs_a: del self.lfs_a[a] if lfbc: lfbc.broadcast() rank = self.gd.comm.rank self.my_atom_indices = [a for a, lfs in self.lfs_a.items() if lfs.root == rank] self.my_atom_indices.sort() self.atom_indices = [a for a, lfs in self.lfs_a.items()] self.atom_indices.sort() if debug: # Holm-Nielsen check: natoms = len(spos_ac) assert (self.gd.comm.sum(float(sum(self.my_atom_indices))) == natoms * (natoms - 1) // 2) if self.integral_a is not None: if isinstance(self.integral_a, (float, int)): integral = self.integral_a for a in self.atom_indices: self.lfs_a[a].normalize(integral) else: for a in self.atom_indices: lfs = self.lfs_a[a] integral = self.integral_a[a] if abs(integral) > 1e-15: lfs.normalize(integral) self.spos_ac = spos_ac def get_dtype(self): # old LFC uses the dtype attribute for dicts return self.dtype def add(self, a_xG, c_axi=1.0, q=-1): if isinstance(c_axi, float): assert q == -1 c_xi = np.array([c_axi]) run([lfs.iadd(a_xG, c_xi) for lfs in self.lfs_a.values()]) else: run([self.lfs_a[a].iadd(a_xG, c_axi.get(a), q, True) for a in self.atom_indices]) def integrate(self, a_xG, c_axi, q=-1): for c_xi in c_axi.values(): c_xi.fill(0.0) run([self.lfs_a[a].iintegrate(a_xG, c_axi.get(a), q) for a in self.atom_indices]) def derivative(self, a_xG, c_axiv, q=-1): for c_xiv in c_axiv.values(): c_xiv.fill(0.0) run([self.lfs_a[a].iderivative(a_xG, c_axiv.get(a), q) for a in self.atom_indices]) def add1(self, n_g, scale, I_a): scale_i = np.array([scale], float) for lfs in self.lfs_a.values(): lfs.add(n_g, scale_i) for a, lfs in self.lfs_a.items(): I_ic = np.zeros((1, 4)) for box in lfs.box_b: box.norm(I_ic) I_a[a] += I_ic[0, 0] * scale def add2(self, n_g, D_asp, s, scale, I_a): for a, lfs in self.lfs_a.items(): I_a[a] += lfs.add_density2(n_g, scale * D_asp[a][s]) def get_function_count(self, a): return self.lfs_a[a].ni def estimate_memory(self, mem): count = 0 for spline_j in self.spline_aj: for spline in spline_j: l = spline.get_angular_momentum_number() sidelength = 2 * spline.get_cutoff() count += (2 * l + 1) * sidelength**3 / self.gd.dv bytes = count * mem.floatsize / self.gd.comm.size mem.subnode('Boxes', bytes) if self.forces: mem.subnode('Derivatives', 3 * bytes) mem.subnode('Work', bytes) if extra_parameters.get('usenewlfc', True): LocalizedFunctionsCollection = NewLocalizedFunctionsCollection def LFC(gd, spline_aj, kd=None, cut=False, dtype=float, integral=None, forces=False): if isinstance(gd, GridDescriptor): return LocalizedFunctionsCollection(gd, spline_aj, kd, cut, dtype, integral, forces) else: return gd.get_lfc(gd, spline_aj) def test(): from gpaw.grid_descriptor import GridDescriptor ngpts = 40 h = 1.0 / ngpts N_c = (ngpts, ngpts, ngpts) a = h * ngpts gd = GridDescriptor(N_c, (a, a, a)) from gpaw.spline import Spline a = np.array([1, 0.9, 0.8, 0.0]) s = Spline(0, 0.2, a) x = LocalizedFunctionsCollection(gd, [[s], [s]]) x.set_positions([(0.5, 0.45, 0.5), (0.5, 0.55, 0.5)]) n_G = gd.zeros() x.add(n_G) import pylab as plt plt.contourf(n_G[20, :, :]) plt.axis('equal') plt.show() if __name__ == '__main__': test() gpaw-0.11.0.13004/gpaw/helmholtz.py0000664000175000017500000001443312553643470016777 0ustar jensjjensj00000000000000from math import pi, sqrt import numpy as np from numpy import exp from gpaw.poisson import PoissonSolver from gpaw.utilities import cerf, erf from gpaw.utilities.gauss import Gaussian from gpaw.fd_operators import FDOperator, laplace from gpaw.transformers import Transformer class HelmholtzGaussian(Gaussian): def get_phi(self, k2): """Get the solution of the Helmholtz equation for a Gaussian.""" # This should lead to very big errors r = np.sqrt(self.r2) k = sqrt(k2) sigma = 1. / sqrt(2 * self.a) p = sigma * k / sqrt(2) i = 1j rhop = r / sqrt(2) / sigma + i * p rhom = r / sqrt(2) / sigma - i * p # h = np.sin(k * r) # the gpaw-Gaussian is sqrt(4 * pi) times a 3D normalized Gaussian return sqrt(4 * pi) * exp(-p**2) / r / 2 * ( np.cos(k * r) * (cerf(rhop) + cerf(rhom)) + i * np.sin(k * r) * (2 + cerf(rhop) - cerf(rhom))) class ScreenedPoissonGaussian(Gaussian): def get_phi(self, mu2): """Get the solution of the screened Poisson equation for a Gaussian. The Gaussian is centered to middle of grid-descriptor.""" r = np.sqrt(self.r2) mu = sqrt(mu2) sigma = 1. / sqrt(2 * self.a) sig2 = sigma**2 mrho = (sig2 * mu - r) / (sqrt(2) * sigma) prho = (sig2 * mu + r) / (sqrt(2) * sigma) def erfc(values): return 1. - erf(values) # the gpaw-Gaussian is sqrt(4 * pi) times a 3D normalized Gaussian return sqrt(4 * pi) * exp(sig2 * mu2 / 2.0) / (2 * r) * ( exp(-mu * r) * erfc(mrho) - exp(mu * r) * erfc(prho)) class HelmholtzOperator(FDOperator): def __init__(self, gd, scale=1.0, n=1, dtype=float, k2=0.0): """Helmholtz for general non orthorhombic grid. gd: GridDescriptor Descriptor for grid. scale: float Scaling factor. Use scale=-0.5 for a kinetic energy operator. n: int Range of stencil. Stencil has O(h^(2n)) error. dtype: float or complex Datatype to work on. """ # Order the 13 neighbor grid points: M_ic = np.indices((3, 3, 3)).reshape((3, -3)).T[-13:] - 1 u_cv = gd.h_cv / (gd.h_cv**2).sum(1)[:, np.newaxis]**0.5 u2_i = (np.dot(M_ic, u_cv)**2).sum(1) i_d = u2_i.argsort() m_mv = np.array([(2, 0, 0), (0, 2, 0), (0, 0, 2), (0, 1, 1), (1, 0, 1), (1, 1, 0)]) # Try 3, 4, 5 and 6 directions: for D in range(3, 7): h_dv = np.dot(M_ic[i_d[:D]], gd.h_cv) A_md = (h_dv**m_mv[:, np.newaxis, :]).prod(2) a_d, residual, rank, s = np.linalg.lstsq(A_md, [1, 1, 1, 0, 0, 0]) if residual.sum() < 1e-14: assert rank == D, 'You have a weird unit cell!' # D directions was OK break a_d *= scale offsets = [(0, 0, 0)] coefs = [laplace[n][0] * a_d.sum()] coefs[0] += k2 * scale for d in range(D): M_c = M_ic[i_d[d]] offsets.extend(np.arange(1, n + 1)[:, np.newaxis] * M_c) coefs.extend(a_d[d] * np.array(laplace[n][1:])) offsets.extend(np.arange(-1, -n - 1, -1)[:, np.newaxis] * M_c) coefs.extend(a_d[d] * np.array(laplace[n][1:])) FDOperator.__init__(self, coefs, offsets, gd, dtype) self.description = ( '%d*%d+1=%d point O(h^%d) finite-difference Helmholtz' % ((self.npoints - 1) // n, n, self.npoints, 2 * n)) class HelmholtzSolver(PoissonSolver): """Solve the Helmholtz or screened Poisson equations. The difference between the Helmholtz equation: (Laplace + k^2) phi = n and the screened Poisson equation: (Laplace - mu^2) phi = n is only the sign of the added inhomogenity. Because of this we can use one class to solve both. So if k2 is greater zero we'll try to solve the Helmhlotz equation, otherwise we'll try to solve the screened Poisson equation. """ def __init__(self, k2=0.0, nn='M', relax='GS', eps=2e-10, use_charge_center=True): assert k2 <= 0, 'Currently only defined for k^2<=0' PoissonSolver.__init__(self, nn, relax, eps, use_charge_center=use_charge_center) self.k2 = k2 def set_grid_descriptor(self, gd): # Should probably be renamed initialize self.gd = gd self.dv = gd.dv gd = self.gd scale = -0.25 / pi if self.nn == 'M': raise ValueError( 'Helmholtz not defined for Mehrstellen stencil') self.operators = [HelmholtzOperator(gd, scale, self.nn, k2=self.k2)] self.B = None self.interpolators = [] self.restrictors = [] level = 0 self.presmooths = [2] self.postsmooths = [1] # Weights for the relaxation, # only used if 'J' (Jacobi) is chosen as method self.weights = [2.0 / 3.0] while level < 4: try: gd2 = gd.coarsen() except ValueError: break self.operators.append(HelmholtzOperator(gd2, scale, 1, k2=self.k2)) self.interpolators.append(Transformer(gd2, gd)) self.restrictors.append(Transformer(gd, gd2)) self.presmooths.append(4) self.postsmooths.append(4) self.weights.append(1.0) level += 1 gd = gd2 self.levels = level if self.relax_method == 1: self.description = 'Gauss-Seidel' else: self.description = 'Jacobi' self.description += ' solver with %d multi-grid levels' % (level + 1) self.description += '\nStencil: ' + self.operators[0].description def load_gauss(self, center=None): """Load the gaussians.""" if not hasattr(self, 'rho_gauss') or center is not None: if self.k2 > 0: gauss = HelmholtzGaussian(self.gd, center=center) else: gauss = ScreenedPoissonGaussian(self.gd, center=center) self.rho_gauss = gauss.get_gauss(0) self.phi_gauss = gauss.get_phi(abs(self.k2)) gpaw-0.11.0.13004/gpaw/coulomb.py0000664000175000017500000003032512553643472016431 0ustar jensjjensj00000000000000from math import pi, sqrt from ase.units import Hartree import numpy as np from numpy.fft import fftn from gpaw.lfc import LocalizedFunctionsCollection as LFC from gpaw.pair_density import PairDensity2 as PairDensity from gpaw.poisson import PoissonSolver, FFTPoissonSolver from gpaw.utilities import unpack, packed_index, unpack2 from gpaw.utilities.ewald import madelung from gpaw.utilities.tools import construct_reciprocal, tri2full, symmetrize from gpaw.utilities.gauss import Gaussian from gpaw.utilities.blas import r2k def get_vxc(paw, spin=0, U=None): """Calculate matrix elements of the xc-potential.""" assert not paw.hamiltonian.xc.xcfunc.orbital_dependent, "LDA/GGA's only" assert paw.wfs.dtype == float, 'Complex waves not implemented' if U is not None: # Rotate xc matrix return np.dot(U.T.conj(), np.dot(get_vxc(paw, spin), U)) gd = paw.hamiltonian.gd psit_nG = paw.wfs.kpt_u[spin].psit_nG[:] if paw.density.nt_sg is None: paw.density.interpolate_pseudo_density() nt_g = paw.density.nt_sg[spin] vxct_g = paw.density.finegd.zeros() paw.hamiltonian.xc.get_energy_and_potential(nt_g, vxct_g) vxct_G = gd.empty() paw.hamiltonian.restrict(vxct_g, vxct_G) Vxc_nn = np.zeros((paw.wfs.bd.nbands, paw.wfs.bd.nbands)) # Apply pseudo part r2k(.5 * gd.dv, psit_nG, vxct_G * psit_nG, .0, Vxc_nn) # lower triangle tri2full(Vxc_nn, 'L') # Fill in upper triangle from lower gd.comm.sum(Vxc_nn) # Add atomic PAW corrections for a, P_ni in paw.wfs.kpt_u[spin].P_ani.items(): D_sp = paw.density.D_asp[a][:] H_sp = np.zeros_like(D_sp) paw.wfs.setups[a].xc_correction.calculate_energy_and_derivatives( D_sp, H_sp) H_ii = unpack(H_sp[spin]) Vxc_nn += np.dot(P_ni, np.dot(H_ii, P_ni.T)) return Vxc_nn * Hartree class Coulomb: """Class used to evaluate two index coulomb integrals.""" def __init__(self, gd, poisson=None): """Class should be initialized with a grid_descriptor 'gd' from the gpaw module. """ self.gd = gd self.poisson = poisson def load(self, method): """Make sure all necessary attributes have been initialized""" assert method in ('real', 'recip_gauss', 'recip_ewald'),\ str(method) + ' is an invalid method name,\n' +\ 'use either real, recip_gauss, or recip_ewald' if method.startswith('recip'): if self.gd.comm.size > 1: raise RuntimeError("Cannot do parallel FFT, use method='real'") if not hasattr(self, 'k2'): self.k2, self.N3 = construct_reciprocal(self.gd) if method.endswith('ewald') and not hasattr(self, 'ewald'): # cutoff radius assert self.gd.orthogonal rc = 0.5 * np.average(self.gd.cell_cv.diagonal()) # ewald potential: 1 - cos(k rc) self.ewald = (np.ones(self.gd.n_c) - np.cos(np.sqrt(self.k2) * rc)) # lim k -> 0 ewald / k2 self.ewald[0, 0, 0] = 0.5 * rc**2 elif method.endswith('gauss') and not hasattr(self, 'ng'): gauss = Gaussian(self.gd) self.ng = gauss.get_gauss(0) / sqrt(4 * pi) self.vg = gauss.get_gauss_pot(0) / sqrt(4 * pi) else: # method == 'real' if not hasattr(self, 'solve'): if self.poisson is not None: self.solve = self.poisson.solve else: solver = PoissonSolver(nn=2) solver.set_grid_descriptor(self.gd) solver.initialize(load_gauss=True) self.solve = solver.solve def coulomb(self, n1, n2=None, Z1=None, Z2=None, method='recip_gauss'): """Evaluates the coulomb integral of n1 and n2 The coulomb integral is defined by:: * / / n1(r) n2(r') (n1 | n2) = | dr | dr' -------------, / / |r - r'| where n1 and n2 could be complex. real: Evaluate directly in real space using gaussians to neutralize density n2, such that the potential can be generated by standard procedures recip_ewald: Evaluate by Fourier transform. Divergence at division by k^2 is avoided by utilizing the Ewald / Tuckermann trick, which formaly requires the densities to be localized within half of the unit cell. recip_gauss: Evaluate by Fourier transform. Divergence at division by k^2 is avoided by removing total charge of n1 and n2 with gaussian density ng:: * * * (n1|n2) = (n1 - Z1 ng|n2 - Z2 ng) + (Z2 n1 + Z1 n2 - Z1 Z2 ng | ng) The evaluation of the integral (n1 - Z1 ng|n2 - Z2 ng) is done in k-space using FFT techniques. """ self.load(method) # determine integrand using specified method if method == 'real': I = self.gd.zeros() if n2 is None: n2 = n1 Z2 = Z1 self.solve(I, n2, charge=Z2, eps=1e-12, zero_initial_phi=True) I += madelung(self.gd.cell_cv) * self.gd.integrate(n2) I *= n1.conj() elif method == 'recip_ewald': n1k = fftn(n1) if n2 is None: n2k = n1k else: n2k = fftn(n2) I = n1k.conj() * n2k * self.ewald * 4 * pi / (self.k2 * self.N3) else: # method == 'recip_gauss': # Determine total charges if Z1 is None: Z1 = self.gd.integrate(n1) if Z2 is None and n2 is not None: Z2 = self.gd.integrate(n2) # Determine the integrand of the neutral system # (n1 - Z1 ng)* int dr' (n2 - Z2 ng) / |r - r'| nk1 = fftn(n1 - Z1 * self.ng) if n2 is None: I = abs(nk1)**2 * 4 * pi / (self.k2 * self.N3) else: nk2 = fftn(n2 - Z2 * self.ng) I = nk1.conj() * nk2 * 4 * pi / (self.k2 * self.N3) # add the corrections to the integrand due to neutralization if n2 is None: I += (2 * np.real(np.conj(Z1) * n1) - abs(Z1)**2 * self.ng) * self.vg else: I += (np.conj(Z1) * n2 + Z2 * n1.conj() - np.conj(Z1) * Z2 * self.ng) * self.vg if n1.dtype == float and (n2 is None or n2.dtype == float): return np.real(self.gd.integrate(I)) else: return self.gd.integrate(I) class CoulombNEW: def __init__(self, gd, setups, spos_ac, fft=False): assert gd.comm.size == 1 self.rhot1_G = gd.empty() self.rhot2_G = gd.empty() self.pot_G = gd.empty() self.dv = gd.dv if fft: self.poisson = FFTPoissonSolver() else: self.poisson = PoissonSolver(nn=3) self.poisson.set_grid_descriptor(gd) self.poisson.initialize() self.setups = setups # Set coarse ghat self.Ghat = LFC(gd, [setup.ghat_l for setup in setups], integral=sqrt(4 * pi)) self.Ghat.set_positions(spos_ac) def calculate(self, nt1_G, nt2_G, P1_ap, P2_ap): I = 0.0 self.rhot1_G[:] = nt1_G self.rhot2_G[:] = nt2_G Q1_aL = {} Q2_aL = {} for a, P1_p in P1_ap.items(): P2_p = P2_ap[a] setup = self.setups[a] # Add atomic corrections to integral I += 2 * np.dot(P1_p, np.dot(setup.M_pp, P2_p)) # Add compensation charges to pseudo densities Q1_aL[a] = np.dot(P1_p, setup.Delta_pL) Q2_aL[a] = np.dot(P2_p, setup.Delta_pL) self.Ghat.add(self.rhot1_G, Q1_aL) self.Ghat.add(self.rhot2_G, Q2_aL) # Add coulomb energy of compensated pseudo densities to integral self.poisson.solve(self.pot_G, self.rhot2_G, charge=None, eps=1e-12, zero_initial_phi=True) I += np.vdot(self.rhot1_G, self.pot_G) * self.dv return I * Hartree class HF: def __init__(self, paw): paw.initialize_positions() self.nspins = paw.wfs.nspins self.nbands = paw.wfs.bd.nbands self.restrict = paw.hamiltonian.restrict self.pair_density = PairDensity(paw.density, paw.atoms, finegrid=True) self.dv = paw.wfs.gd.dv self.dtype = paw.wfs.dtype self.setups = paw.wfs.setups # Allocate space for matrices self.nt_G = paw.wfs.gd.empty() self.rhot_g = paw.density.finegd.empty() self.vt_G = paw.wfs.gd.empty() self.vt_g = paw.density.finegd.empty() self.poisson_solve = paw.hamiltonian.poisson.solve def apply(self, paw, u=0): H_nn = np.zeros((self.nbands, self.nbands), self.dtype) self.soft_pseudo(paw, H_nn, u=u) self.atomic_val_val(paw, H_nn, u=u) self.atomic_val_core(paw, H_nn, u=u) return H_nn * Hartree def soft_pseudo(self, paw, H_nn, h_nn=None, u=0): if h_nn is None: h_nn = H_nn kpt = paw.wfs.kpt_u[u] pd = self.pair_density deg = 2 / self.nspins fmin = 1e-9 Htpsit_nG = np.zeros(kpt.psit_nG.shape, self.dtype) for n1 in range(self.nbands): psit1_G = kpt.psit_nG[n1] f1 = kpt.f_n[n1] / deg for n2 in range(n1, self.nbands): psit2_G = kpt.psit_nG[n2] f2 = kpt.f_n[n2] / deg if f1 < fmin and f2 < fmin: continue pd.initialize(kpt, n1, n2) pd.get_coarse(self.nt_G) pd.add_compensation_charges(self.nt_G, self.rhot_g) self.poisson_solve(self.vt_g, -self.rhot_g, charge=-float(n1 == n2), eps=1e-12, zero_initial_phi=True) self.restrict(self.vt_g, self.vt_G) Htpsit_nG[n1] += f2 * self.vt_G * psit2_G if n1 != n2: Htpsit_nG[n2] += f1 * self.vt_G * psit1_G v_aL = paw.density.ghat.dict() paw.density.ghat.integrate(self.vt_g, v_aL) for a, v_L in v_aL.items(): v_ii = unpack(np.dot(paw.wfs.setups[a].Delta_pL, v_L)) P_ni = kpt.P_ani[a] h_nn[:, n1] += f2 * np.dot(P_ni, np.dot(v_ii, P_ni[n2])) if n1 != n2: h_nn[:, n2] += f1 * np.dot(P_ni, np.dot(v_ii, P_ni[n1])) symmetrize(h_nn) # Grrrr why!!! XXX # Fill in lower triangle r2k(0.5 * self.dv, kpt.psit_nG[:], Htpsit_nG, 1.0, H_nn) # Fill in upper triangle from lower tri2full(H_nn, 'L') def atomic_val_val(self, paw, H_nn, u=0): deg = 2 / self.nspins kpt = paw.wfs.kpt_u[u] for a, P_ni in kpt.P_ani.items(): # Add atomic corrections to the valence-valence exchange energy # -- # > D C D # -- ii iiii ii setup = paw.wfs.setups[a] D_p = paw.density.D_asp[a][kpt.s] H_p = np.zeros_like(D_p) D_ii = unpack2(D_p) ni = len(D_ii) for i1 in range(ni): for i2 in range(ni): A = 0.0 for i3 in range(ni): p13 = packed_index(i1, i3, ni) for i4 in range(ni): p24 = packed_index(i2, i4, ni) A += setup.M_pp[p13, p24] * D_ii[i3, i4] p12 = packed_index(i1, i2, ni) H_p[p12] -= 2 / deg * A / ((i1 != i2) + 1) H_nn += np.dot(P_ni, np.inner(unpack(H_p), P_ni.conj())) def atomic_val_core(self, paw, H_nn, u=0): kpt = paw.wfs.kpt_u[u] for a, P_ni in kpt.P_ani.items(): dH_ii = unpack(-paw.wfs.setups[a].X_p) H_nn += np.dot(P_ni, np.inner(dH_ii, P_ni.conj())) gpaw-0.11.0.13004/gpaw/svnversion_io.py0000664000175000017500000000247412553643472017700 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. from os import path try: from subprocess import Popen, PIPE except ImportError: from os import popen3 else: def popen3(cmd): p = Popen(cmd, shell=True, close_fds=True, stdin=PIPE, stdout=PIPE, stderr=PIPE) return p.stdin, p.stdout, p.stderr def write_svnversion(svnversion, dir): svnversionfile = path.join(dir, 'svnversion.py') f = open(svnversionfile,'w') f.write('svnversion = "%s"\n' % svnversion) f.close() print('svnversion = ' +svnversion+' written to '+svnversionfile) # assert svn:ignore property if the installation is under svn control # because svnversion.py has to be ignored by svn! cmd = popen3('svn propset svn:ignore svnversion.py '+dir)[1] output = cmd.read() cmd.close() def get_svnversion_from_svn(dir): # try to get the last svn version number from svnversion cmd = popen3('svnversion -n '+dir)[1] # assert we are in the project dir output = cmd.read().strip() cmd.close() if not (output + ' ')[0].isdigit(): # we build from exported source (e.g. rpmbuild) output = None return output svnversion = get_svnversion_from_svn(dir='gpaw') if svnversion: write_svnversion(svnversion, dir='gpaw') gpaw-0.11.0.13004/gpaw/kpt_descriptor.py0000664000175000017500000004645612553643470020037 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. """K-point/spin combination-descriptors This module contains classes for defining combinations of two indices: * Index k for irreducible kpoints in the 1st Brillouin zone. * Index s for spin up/down if spin-polarized (otherwise ignored). """ import numpy as np from ase.dft.kpoints import monkhorst_pack, get_monkhorst_pack_size_and_offset from gpaw.kpoint import KPoint import gpaw.mpi as mpi import _gpaw def to1bz(bzk_kc, cell_cv): """Wrap k-points to 1. BZ. Return k-points wrapped to the 1. BZ. bzk_kc: (n,3) ndarray Array of k-points in units of the reciprocal lattice vectors. cell_cv: (3,3) ndarray Unit cell. """ B_cv = 2.0 * np.pi * np.linalg.inv(cell_cv).T K_kv = np.dot(bzk_kc, B_cv) N_xc = np.indices((3, 3, 3)).reshape((3, 27)).T - 1 G_xv = np.dot(N_xc, B_cv) bz1k_kc = bzk_kc.copy() # Find the closest reciprocal lattice vector: for k, K_v in enumerate(K_kv): # If a k-point has the same distance to several reciprocal # lattice vectors, we don't want to pick a random one on the # basis of numerical noise, so we round off the differences # between the shortest distances to 6 decimals and chose the # one with the lowest index. d = ((G_xv - K_v)**2).sum(1) x = (d - d.min()).round(6).argmin() bz1k_kc[k] -= N_xc[x] return bz1k_kc class KPointDescriptor: """Descriptor-class for k-points.""" def __init__(self, kpts, nspins=1, collinear=True): """Construct descriptor object for kpoint/spin combinations (ks-pair). Parameters ---------- kpts: None, sequence of 3 ints, or (n,3)-shaped array Specification of the k-point grid. None=Gamma, list of ints=Monkhorst-Pack, ndarray=user specified. nspins: int Number of spins. Attributes =================== ================================================= ``N_c`` Number of k-points in the different directions. ``nspins`` Number of spins in total. ``mynspins`` Number of spins on this CPU. ``nibzkpts`` Number of irreducible kpoints in 1st BZ. ``nks`` Number of k-point/spin combinations in total. ``mynks`` Number of k-point/spin combinations on this CPU. ``gamma`` Boolean indicator for gamma point calculation. ``comm`` MPI-communicator for kpoint distribution. ``weight_k`` Weights of each k-point ``ibzk_kc`` Unknown ``ibzk_qc`` Unknown ``sym_k`` Unknown ``time_reversal_k`` Unknown ``bz2ibz_k`` Unknown ``ibz2bz_k`` Unknown ``bz2bz_ks`` Unknown ``symmetry`` Object representing symmetries =================== ================================================= """ if kpts is None: self.bzk_kc = np.zeros((1, 3)) self.N_c = np.array((1, 1, 1), dtype=int) self.offset_c = np.zeros(3) else: kpts = np.asarray(kpts) if kpts.ndim == 1: self.N_c = np.array(kpts, dtype=int) self.bzk_kc = monkhorst_pack(self.N_c) self.offset_c = np.zeros(3) else: self.bzk_kc = np.array(kpts, dtype=float) try: self.N_c, self.offset_c = \ get_monkhorst_pack_size_and_offset(self.bzk_kc) except ValueError: self.N_c = None self.offset_c = None self.collinear = collinear self.nspins = nspins self.nbzkpts = len(self.bzk_kc) # Gamma-point calculation? self.gamma = self.nbzkpts == 1 and np.allclose(self.bzk_kc, 0) # Point group and time-reversal symmetry neglected: self.weight_k = np.ones(self.nbzkpts) / self.nbzkpts self.ibzk_kc = self.bzk_kc.copy() self.sym_k = np.zeros(self.nbzkpts, int) self.time_reversal_k = np.zeros(self.nbzkpts, bool) self.bz2ibz_k = np.arange(self.nbzkpts) self.ibz2bz_k = np.arange(self.nbzkpts) self.bz2bz_ks = np.arange(self.nbzkpts)[:, np.newaxis] self.nibzkpts = self.nbzkpts self.nks = self.nibzkpts * self.nspins self.set_communicator(mpi.serial_comm) if self.gamma: self.description = '1 k-point (Gamma)' else: self.description = '%d k-points' % self.nbzkpts if self.N_c is not None: self.description += (': %d x %d x %d Monkhorst-Pack grid' % tuple(self.N_c)) if self.offset_c.any(): self.description += ' + [' for x in self.offset_c: if x != 0 and abs(round(1 / x) - 1 / x) < 1e-12: self.description += '1/%d,' % round(1 / x) else: self.description += '%f,' % x self.description = self.description[:-1] + ']' def __len__(self): """Return number of k-point/spin combinations of local CPU.""" return self.mynks def set_symmetry(self, atoms, symmetry, comm=None): """Create symmetry object and construct irreducible Brillouin zone. atoms: Atoms object Defines atom positions and types and also unit cell and boundary conditions. symmetry: Symmetry object Symmetry object. """ self.symmetry = symmetry for c, periodic in enumerate(atoms.pbc): if not periodic and not np.allclose(self.bzk_kc[:, c], 0.0): raise ValueError('K-points can only be used with PBCs!') # Find symmetry operations of atoms: symmetry.analyze(atoms.get_scaled_positions()) if symmetry.time_reversal or symmetry.point_group: (self.ibzk_kc, self.weight_k, self.sym_k, self.time_reversal_k, self.bz2ibz_k, self.ibz2bz_k, self.bz2bz_ks) = symmetry.reduce(self.bzk_kc, comm) # Number of irreducible k-points and k-point/spin combinations. self.nibzkpts = len(self.ibzk_kc) if self.collinear: self.nks = self.nibzkpts * self.nspins else: self.nks = self.nibzkpts def set_communicator(self, comm): """Set k-point communicator.""" # Ranks < self.rank0 have mynks0 k-point/spin combinations and # ranks >= self.rank0 have mynks0+1 k-point/spin combinations. mynks0, x = divmod(self.nks, comm.size) self.rank0 = comm.size - x self.comm = comm # My number and offset of k-point/spin combinations self.mynks = self.get_count() self.ks0 = self.get_offset() if self.nspins == 2 and comm.size == 1: # NCXXXXXXXX # Avoid duplicating k-points in local list of k-points. self.ibzk_qc = self.ibzk_kc.copy() self.weight_q = self.weight_k else: self.ibzk_qc = np.vstack((self.ibzk_kc, self.ibzk_kc))[self.get_slice()] self.weight_q = np.hstack((self.weight_k, self.weight_k))[self.get_slice()] def copy(self, comm=mpi.serial_comm): """Create a copy with shared symmetry object.""" kd = KPointDescriptor(self.bzk_kc, self.nspins) kd.weight_k = self.weight_k kd.ibzk_kc = self.ibzk_kc kd.sym_k = self.sym_k kd.time_reversal_k = self.time_reversal_k kd.bz2ibz_k = self.bz2ibz_k kd.ibz2bz_k = self.ibz2bz_k kd.bz2bz_ks = self.bz2bz_ks kd.symmetry = self.symmetry kd.nibzkpts = self.nibzkpts kd.nks = self.nks kd.set_communicator(comm) return kd def create_k_points(self, gd): """Return a list of KPoints.""" sdisp_cd = gd.sdisp_cd kpt_u = [] for ks in range(self.ks0, self.ks0 + self.mynks): s, k = divmod(ks, self.nibzkpts) q = (ks - self.ks0) % self.nibzkpts if self.collinear: weight = self.weight_k[k] * 2 / self.nspins else: weight = self.weight_k[k] if self.gamma: phase_cd = np.ones((3, 2), complex) else: phase_cd = np.exp(2j * np.pi * sdisp_cd * self.ibzk_kc[k, :, np.newaxis]) kpt_u.append(KPoint(weight, s, k, q, phase_cd)) return kpt_u def collect(self, a_ux, broadcast=True): """Collect distributed data to all.""" if self.comm.rank == 0 or broadcast: xshape = a_ux.shape[1:] a_skx = np.empty((self.nspins, self.nibzkpts) + xshape, a_ux.dtype) a_Ux = a_skx.reshape((-1,) + xshape) else: a_skx = None if self.comm.rank > 0: self.comm.send(a_ux, 0) else: u1 = self.get_count(0) a_Ux[0:u1] = a_ux requests = [] for rank in range(1, self.comm.size): u2 = u1 + self.get_count(rank) requests.append(self.comm.receive(a_Ux[u1:u2], rank, block=False)) u1 = u2 assert u1 == len(a_Ux) self.comm.waitall(requests) if broadcast: self.comm.broadcast(a_Ux, 0) return a_skx def transform_wave_function(self, psit_G, k, index_G=None, phase_G=None): """Transform wave function from IBZ to BZ. k is the index of the desired k-point in the full BZ. """ s = self.sym_k[k] time_reversal = self.time_reversal_k[k] op_cc = np.linalg.inv(self.symmetry.op_scc[s]).round().astype(int) # Identity if (np.abs(op_cc - np.eye(3, dtype=int)) < 1e-10).all(): if time_reversal: return psit_G.conj() else: return psit_G # General point group symmetry else: ik = self.bz2ibz_k[k] kibz_c = self.ibzk_kc[ik] b_g = np.zeros_like(psit_G) kbz_c = np.dot(self.symmetry.op_scc[s], kibz_c) if index_G is not None: assert index_G.shape == psit_G.shape == phase_G.shape,\ 'Shape mismatch %s vs %s vs %s' % (index_G.shape, psit_G.shape, phase_G.shape) _gpaw.symmetrize_with_index(psit_G, b_g, index_G, phase_G) else: _gpaw.symmetrize_wavefunction(psit_G, b_g, op_cc.copy(), np.ascontiguousarray(kibz_c), kbz_c) if time_reversal: return b_g.conj() else: return b_g def get_transform_wavefunction_index(self, nG, k): """Get the "wavefunction transform index". This is a permutation of the numbers 1, 2, .. N which associates k + q to some k, and where N is the total number of grid points as specified by nG which is a 3D tuple. Returns index_G and phase_G which are one-dimensional arrays on the grid.""" s = self.sym_k[k] op_cc = np.linalg.inv(self.symmetry.op_scc[s]).round().astype(int) # General point group symmetry if (np.abs(op_cc - np.eye(3, dtype=int)) < 1e-10).all(): nG0 = np.prod(nG) index_G = np.arange(nG0).reshape(nG) phase_G = np.ones(nG) else: ik = self.bz2ibz_k[k] kibz_c = self.ibzk_kc[ik] index_G = np.zeros(nG, dtype=int) phase_G = np.zeros(nG, dtype=complex) kbz_c = np.dot(self.symmetry.op_scc[s], kibz_c) _gpaw.symmetrize_return_index(index_G, phase_G, op_cc.copy(), np.ascontiguousarray(kibz_c), kbz_c) return index_G, phase_G def find_k_plus_q(self, q_c, kpts_k=None): """Find the indices of k+q for all kpoints in the Brillouin zone. In case that k+q is outside the BZ, the k-point inside the BZ corresponding to k+q is given. Parameters ---------- q_c: ndarray Coordinates for the q-vector in units of the reciprocal lattice vectors. kpts_k: list of ints Restrict search to specified k-points. """ k_x = kpts_k if k_x is None: return self.find_k_plus_q(q_c, range(self.nbzkpts)) i_x = [] for k in k_x: kpt_c = self.bzk_kc[k] + q_c d_kc = kpt_c - self.bzk_kc d_k = abs(d_kc - d_kc.round()).sum(1) i = d_k.argmin() if d_k[i] > 1e-8: raise RuntimeError('Could not find k+q!') i_x.append(i) return i_x def get_bz_q_points(self, first=False): """Return the q=k1-k2. q-mesh is always Gamma-centered.""" shift_c = 0.5 * ((self.N_c + 1) % 2) / self.N_c bzq_qc = monkhorst_pack(self.N_c) + shift_c if first: return to1bz(bzq_qc, self.symmetry.cell_cv) else: return bzq_qc def get_ibz_q_points(self, bzq_qc, op_scc): """Return ibz q points and the corresponding symmetry operations that work for k-mesh as well.""" ibzq_qc_tmp = [] ibzq_qc_tmp.append(bzq_qc[-1]) weight_tmp = [0] for i, op_cc in enumerate(op_scc): if np.abs(op_cc - np.eye(3)).sum() < 1e-8: identity_iop = i break ibzq_q_tmp = {} iop_q = {} timerev_q = {} diff_qc = {} for i in range(len(bzq_qc) - 1, -1, -1): # loop opposite to kpoint try: ibzk, iop, timerev, diff_c = self.find_ibzkpt( op_scc, ibzq_qc_tmp, bzq_qc[i]) find = False for ii, iop1 in enumerate(self.sym_k): if iop1 == iop and self.time_reversal_k[ii] == timerev: find = True break if find is False: raise ValueError('cant find k!') ibzq_q_tmp[i] = ibzk weight_tmp[ibzk] += 1. iop_q[i] = iop timerev_q[i] = timerev diff_qc[i] = diff_c except ValueError: ibzq_qc_tmp.append(bzq_qc[i]) weight_tmp.append(1.) ibzq_q_tmp[i] = len(ibzq_qc_tmp) - 1 iop_q[i] = identity_iop timerev_q[i] = False diff_qc[i] = np.zeros(3) # reverse the order. nq = len(ibzq_qc_tmp) ibzq_qc = np.zeros((nq, 3)) ibzq_q = np.zeros(len(bzq_qc), dtype=int) for i in range(nq): ibzq_qc[i] = ibzq_qc_tmp[nq - i - 1] for i in range(len(bzq_qc)): ibzq_q[i] = nq - ibzq_q_tmp[i] - 1 self.q_weights = np.array(weight_tmp[::-1]) / len(bzq_qc) return ibzq_qc, ibzq_q, iop_q, timerev_q, diff_qc def find_ibzkpt(self, symrel, ibzk_kc, bzk_c): """Find index in IBZ and related symmetry operations.""" find = False ibzkpt = 0 iop = 0 timerev = False for sign in (1, -1): for ioptmp, op in enumerate(symrel): for i, ibzk in enumerate(ibzk_kc): diff_c = bzk_c - sign * np.dot(op, ibzk) if (np.abs(diff_c - diff_c.round()) < 1e-8).all(): ibzkpt = i iop = ioptmp find = True if sign == -1: timerev = True break if find: break if find: break if not find: raise ValueError('Cant find corresponding IBZ kpoint!') return ibzkpt, iop, timerev, diff_c.round() def where_is_q(self, q_c, bzq_qc): """Find the index of q points in BZ.""" d_qc = q_c - bzq_qc d_q = abs(d_qc - d_qc.round()).sum(1) q = d_q.argmin() if d_q[q] > 1e-8: raise RuntimeError('Could not find q!') return q def get_count(self, rank=None): """Return the number of ks-pairs which belong to a given rank.""" if rank is None: rank = self.comm.rank assert rank in range(self.comm.size) mynks0 = self.nks // self.comm.size mynks = mynks0 if rank >= self.rank0: mynks += 1 return mynks def get_offset(self, rank=None): """Return the offset of the first ks-pair on a given rank.""" if rank is None: rank = self.comm.rank assert rank in range(self.comm.size) mynks0 = self.nks // self.comm.size ks0 = rank * mynks0 if rank >= self.rank0: ks0 += rank - self.rank0 return ks0 def get_rank_and_index(self, s, k): """Find rank and local index of k-point/spin combination.""" u = self.where_is(s, k) rank, myu = self.who_has(u) return rank, myu def get_slice(self, rank=None): """Return the slice of global ks-pairs which belong to a given rank.""" if rank is None: rank = self.comm.rank assert rank in range(self.comm.size) mynks, ks0 = self.get_count(rank), self.get_offset(rank) uslice = slice(ks0, ks0 + mynks) return uslice def get_indices(self, rank=None): """Return the global ks-pair indices which belong to a given rank.""" uslice = self.get_slice(rank) return np.arange(*uslice.indices(self.nks)) def get_ranks(self): """Return array of ranks as a function of global ks-pair indices.""" ranks = np.empty(self.nks, dtype=int) for rank in range(self.comm.size): uslice = self.get_slice(rank) ranks[uslice] = rank assert (ranks >= 0).all() and (ranks < self.comm.size).all() return ranks def who_has(self, u): """Convert global index to rank information and local index.""" mynks0 = self.nks // self.comm.size if u < mynks0 * self.rank0: rank, myu = divmod(u, mynks0) else: rank, myu = divmod(u - mynks0 * self.rank0, mynks0 + 1) rank += self.rank0 return rank, myu def global_index(self, myu, rank=None): """Convert rank information and local index to global index.""" if rank is None: rank = self.comm.rank assert rank in range(self.comm.size) ks0 = self.get_offset(rank) u = ks0 + myu return u def what_is(self, u): """Convert global index to corresponding kpoint/spin combination.""" s, k = divmod(u, self.nibzkpts) return s, k def where_is(self, s, k): """Convert kpoint/spin combination to the global index thereof.""" u = k + self.nibzkpts * s return u gpaw-0.11.0.13004/gpaw/density.py0000664000175000017500000005306012553643470016447 0ustar jensjjensj00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. """This module defines a density class.""" from math import pi, sqrt import numpy as np from gpaw import debug from gpaw.mixer import BaseMixer, Mixer, MixerSum from gpaw.transformers import Transformer from gpaw.lfc import LFC, BasisFunctions from gpaw.wavefunctions.lcao import LCAOWaveFunctions from gpaw.utilities import unpack2 from gpaw.utilities.partition import AtomPartition from gpaw.utilities.timing import nulltimer from gpaw.io import read_atomic_matrices from gpaw.mpi import SerialCommunicator from gpaw.arraydict import ArrayDict class Density(object): """Density object. Attributes: =============== ===================================================== ``gd`` Grid descriptor for coarse grids. ``finegd`` Grid descriptor for fine grids. ``interpolate`` Function for interpolating the electron density. ``mixer`` ``DensityMixer`` object. =============== ===================================================== Soft and smooth pseudo functions on uniform 3D grids: ========== ========================================= ``nt_sG`` Electron density on the coarse grid. ``nt_sg`` Electron density on the fine grid. ``nt_g`` Electron density on the fine grid. ``rhot_g`` Charge density on the fine grid. ``nct_G`` Core electron-density on the coarse grid. ========== ========================================= """ def __init__(self, gd, finegd, nspins, charge, collinear=True): """Create the Density object.""" self.gd = gd self.finegd = finegd self.nspins = nspins self.charge = float(charge) self.collinear = collinear self.ncomp = 1 if collinear else 2 self.ns = self.nspins * self.ncomp**2 self.charge_eps = 1e-7 self.D_asp = None self.Q_aL = None self.nct_G = None self.nt_sG = None self.rhot_g = None self.nt_sg = None self.nt_g = None self.atom_partition = None self.mixer = BaseMixer() self.timer = nulltimer def initialize(self, setups, timer, magmom_av, hund): self.timer = timer self.setups = setups self.hund = hund self.magmom_av = magmom_av def reset(self): # TODO: reset other parameters? self.nt_sG = None def set_positions(self, spos_ac, atom_partition): rank_a = atom_partition.rank_a self.nct.set_positions(spos_ac) self.ghat.set_positions(spos_ac) self.mixer.reset() #self.nt_sG = None self.nt_sg = None self.nt_g = None self.rhot_g = None self.Q_aL = None # If both old and new atomic ranks are present, start a blank dict if # it previously didn't exist but it will needed for the new atoms. if (self.atom_partition is not None and self.D_asp is None and (rank_a == self.gd.comm.rank).any()): self.D_asp = self.setups.empty_atomic_matrix(self.ns, self.atom_partition) if (self.atom_partition is not None and self.D_asp is not None and not isinstance(self.gd.comm, SerialCommunicator)): self.timer.start('Redistribute') self.D_asp.redistribute(atom_partition) self.timer.stop('Redistribute') self.atom_partition = atom_partition def calculate_pseudo_density(self, wfs): """Calculate nt_sG from scratch. nt_sG will be equal to nct_G plus the contribution from wfs.add_to_density(). """ wfs.calculate_density_contribution(self.nt_sG) self.nt_sG[:self.nspins] += self.nct_G @property def D_asp(self): if self._D_asp is not None: assert isinstance(self._D_asp, ArrayDict), type(self._D_asp) self._D_asp.check_consistency() return self._D_asp @D_asp.setter def D_asp(self, value): if isinstance(value, dict): tmp = self.setups.empty_atomic_matrix(self.ns, self.atom_partition) tmp.update(value) value = tmp assert isinstance(value, ArrayDict) or value is None, type(value) if value is not None: value.check_consistency() self._D_asp = value def update(self, wfs): self.timer.start('Density') self.timer.start('Pseudo density') self.calculate_pseudo_density(wfs) self.timer.stop('Pseudo density') self.timer.start('Atomic density matrices') wfs.calculate_atomic_density_matrices(self.D_asp) self.timer.stop('Atomic density matrices') self.timer.start('Multipole moments') comp_charge = self.calculate_multipole_moments() self.timer.stop('Multipole moments') if isinstance(wfs, LCAOWaveFunctions): self.timer.start('Normalize') self.normalize(comp_charge) self.timer.stop('Normalize') self.timer.start('Mix') self.mix(comp_charge) self.timer.stop('Mix') self.timer.stop('Density') def normalize(self, comp_charge=None): """Normalize pseudo density.""" if comp_charge is None: comp_charge = self.calculate_multipole_moments() pseudo_charge = self.gd.integrate(self.nt_sG[:self.nspins]).sum() if pseudo_charge + self.charge + comp_charge != 0: if pseudo_charge != 0: x = -(self.charge + comp_charge) / pseudo_charge self.nt_sG *= x else: # Use homogeneous background: volume = self.gd.get_size_of_global_array().prod() * self.gd.dv self.nt_sG[:self.nspins] = -(self.charge + comp_charge) / volume def mix(self, comp_charge): if not self.mixer.mix_rho: self.mixer.mix(self) comp_charge = None self.interpolate_pseudo_density(comp_charge) self.calculate_pseudo_charge() if self.mixer.mix_rho: self.mixer.mix(self) def calculate_multipole_moments(self): """Calculate multipole moments of compensation charges. Returns the total compensation charge in units of electron charge, so the number will be negative because of the dominating contribution from the nuclear charge.""" comp_charge = 0.0 self.Q_aL = {} for a, D_sp in self.D_asp.items(): Q_L = self.Q_aL[a] = np.dot(D_sp[:self.nspins].sum(0), self.setups[a].Delta_pL) Q_L[0] += self.setups[a].Delta0 comp_charge += Q_L[0] return self.gd.comm.sum(comp_charge) * sqrt(4 * pi) def initialize_from_atomic_densities(self, basis_functions): """Initialize D_asp, nt_sG and Q_aL from atomic densities. nt_sG is initialized from atomic orbitals, and will be constructed with the specified magnetic moments and obeying Hund's rules if ``hund`` is true.""" # XXX does this work with blacs? What should be distributed? # Apparently this doesn't use blacs at all, so it's serial # with respect to the blacs distribution. That means it works # but is not particularly efficient (not that this is a time # consuming step) self.D_asp = self.setups.empty_atomic_matrix(self.ns, self.atom_partition) f_asi = {} for a in basis_functions.atom_indices: c = self.charge / len(self.setups) # distribute on all atoms M_v = self.magmom_av[a] M = (M_v**2).sum()**0.5 f_si = self.setups[a].calculate_initial_occupation_numbers( M, self.hund, charge=c, nspins=self.nspins * self.ncomp) if self.collinear: if M_v[2] < 0: f_si = f_si[::-1].copy() else: f_i = f_si.sum(axis=0) fm_i = f_si[0] - f_si[1] f_si = np.zeros((4, len(f_i))) f_si[0] = f_i if M > 0: f_si[1:4] = np.outer(M_v / M, fm_i) if a in basis_functions.my_atom_indices: self.D_asp[a] = self.setups[a].initialize_density_matrix(f_si) f_asi[a] = f_si self.nt_sG = self.gd.zeros(self.ns) basis_functions.add_to_density(self.nt_sG, f_asi) self.nt_sG[:self.nspins] += self.nct_G self.calculate_normalized_charges_and_mix() def initialize_from_wavefunctions(self, wfs): """Initialize D_asp, nt_sG and Q_aL from wave functions.""" self.timer.start("Density initialize from wavefunctions") self.nt_sG = self.gd.empty(self.ns) self.calculate_pseudo_density(wfs) self.D_asp = self.setups.empty_atomic_matrix(self.ns, self.atom_partition) wfs.calculate_atomic_density_matrices(self.D_asp) self.calculate_normalized_charges_and_mix() self.timer.stop("Density initialize from wavefunctions") def initialize_directly_from_arrays(self, nt_sG, D_asp): """Set D_asp and nt_sG directly.""" self.nt_sG = nt_sG self.D_asp = D_asp D_asp.check_consistency() #self.calculate_normalized_charges_and_mix() # No calculate multipole moments? Tests will fail because of # improperly initialized mixer def calculate_normalized_charges_and_mix(self): comp_charge = self.calculate_multipole_moments() self.normalize(comp_charge) self.mix(comp_charge) def set_mixer(self, mixer): if mixer is not None: if self.nspins == 1 and isinstance(mixer, MixerSum): raise RuntimeError('Cannot use MixerSum with nspins==1') self.mixer = mixer else: if self.gd.pbc_c.any(): beta = 0.05 history = 5 weight = 50.0 else: beta = 0.25 history = 3 weight = 1.0 if self.nspins == 2: self.mixer = MixerSum(beta, history, weight) else: self.mixer = Mixer(beta, history, weight) self.mixer.initialize(self) def estimate_magnetic_moments(self): magmom_av = np.zeros_like(self.magmom_av) if self.nspins == 2 or not self.collinear: for a, D_sp in self.D_asp.items(): if self.collinear: magmom_av[a, 2] = np.dot(D_sp[0] - D_sp[1], self.setups[a].N0_p) else: magmom_av[a] = np.dot(D_sp[1:4], self.setups[a].N0_p) self.gd.comm.sum(magmom_av) return magmom_av def get_correction(self, a, spin): """Integrated atomic density correction. Get the integrated correction to the pseuso density relative to the all-electron density. """ setup = self.setups[a] return sqrt(4 * pi) * ( np.dot(self.D_asp[a][spin], setup.Delta_pL[:, 0]) + setup.Delta0 / self.nspins) def get_all_electron_density(self, atoms=None, gridrefinement=2, spos_ac=None): """Return real all-electron density array. Usage: Either get_all_electron_density(atoms) or get_all_electron_density(spos_ac=spos_ac) """ if spos_ac is None: spos_ac = atoms.get_scaled_positions() % 1.0 # Refinement of coarse grid, for representation of the AE-density if gridrefinement == 1: gd = self.gd n_sg = self.nt_sG.copy() elif gridrefinement == 2: gd = self.finegd if self.nt_sg is None: self.interpolate_pseudo_density() n_sg = self.nt_sg.copy() elif gridrefinement == 4: # Extra fine grid gd = self.finegd.refine() # Interpolation function for the density: interpolator = Transformer(self.finegd, gd, 3) # Transfer the pseudo-density to the fine grid: n_sg = gd.empty(self.nspins) if self.nt_sg is None: self.interpolate_pseudo_density() for s in range(self.nspins): interpolator.apply(self.nt_sg[s], n_sg[s]) else: raise NotImplementedError # Add corrections to pseudo-density to get the AE-density splines = {} phi_aj = [] phit_aj = [] nc_a = [] nct_a = [] for a, id in enumerate(self.setups.id_a): if id in splines: phi_j, phit_j, nc, nct = splines[id] else: # Load splines: phi_j, phit_j, nc, nct = self.setups[a].get_partial_waves()[:4] splines[id] = (phi_j, phit_j, nc, nct) phi_aj.append(phi_j) phit_aj.append(phit_j) nc_a.append([nc]) nct_a.append([nct]) # Create localized functions from splines phi = BasisFunctions(gd, phi_aj) phit = BasisFunctions(gd, phit_aj) nc = LFC(gd, nc_a) nct = LFC(gd, nct_a) phi.set_positions(spos_ac) phit.set_positions(spos_ac) nc.set_positions(spos_ac) nct.set_positions(spos_ac) I_sa = np.zeros((self.nspins, len(spos_ac))) a_W = np.empty(len(phi.M_W), np.intc) W = 0 for a in phi.atom_indices: nw = len(phi.sphere_a[a].M_w) a_W[W:W + nw] = a W += nw x_W = phi.create_displacement_arrays()[0] rho_MM = np.zeros((phi.Mmax, phi.Mmax)) for s, I_a in enumerate(I_sa): M1 = 0 for a, setup in enumerate(self.setups): ni = setup.ni D_sp = self.D_asp.get(a) if D_sp is None: D_sp = np.empty((self.nspins, ni * (ni + 1) // 2)) else: I_a[a] = ((setup.Nct - setup.Nc) / self.nspins - sqrt(4 * pi) * np.dot(D_sp[s], setup.Delta_pL[:, 0])) if gd.comm.size > 1: gd.comm.broadcast(D_sp, self.atom_partition.rank_a[a]) M2 = M1 + ni rho_MM[M1:M2, M1:M2] = unpack2(D_sp[s]) M1 = M2 phi.lfc.ae_valence_density_correction(rho_MM, n_sg[s], a_W, I_a, x_W) phit.lfc.ae_valence_density_correction(-rho_MM, n_sg[s], a_W, I_a, x_W) a_W = np.empty(len(nc.M_W), np.intc) W = 0 for a in nc.atom_indices: nw = len(nc.sphere_a[a].M_w) a_W[W:W + nw] = a W += nw scale = 1.0 / self.nspins for s, I_a in enumerate(I_sa): nc.lfc.ae_core_density_correction(scale, n_sg[s], a_W, I_a) nct.lfc.ae_core_density_correction(-scale, n_sg[s], a_W, I_a) gd.comm.sum(I_a) N_c = gd.N_c g_ac = np.around(N_c * spos_ac).astype(int) % N_c - gd.beg_c for I, g_c in zip(I_a, g_ac): if (g_c >= 0).all() and (g_c < gd.n_c).all(): n_sg[s][tuple(g_c)] -= I / gd.dv return n_sg, gd def estimate_memory(self, mem): nspins = self.nspins nbytes = self.gd.bytecount() nfinebytes = self.finegd.bytecount() arrays = mem.subnode('Arrays') for name, size in [('nt_sG', nbytes * nspins), ('nt_sg', nfinebytes * nspins), ('nt_g', nfinebytes), ('rhot_g', nfinebytes), ('nct_G', nbytes)]: arrays.subnode(name, size) lfs = mem.subnode('Localized functions') for name, obj in [('nct', self.nct), ('ghat', self.ghat)]: obj.estimate_memory(lfs.subnode(name)) self.mixer.estimate_memory(mem.subnode('Mixer'), self.gd) # TODO # The implementation of interpolator memory use is not very # accurate; 20 MiB vs 13 MiB estimated in one example, probably # worse for parallel calculations. def get_spin_contamination(self, atoms, majority_spin=0): """Calculate the spin contamination. Spin contamination is defined as the integral over the spin density difference, where it is negative (i.e. the minority spin density is larger than the majority spin density. """ if majority_spin == 0: smaj = 0 smin = 1 else: smaj = 1 smin = 0 nt_sg, gd = self.get_all_electron_density(atoms) dt_sg = nt_sg[smin] - nt_sg[smaj] dt_sg = np.where(dt_sg > 0, dt_sg, 0.0) return gd.integrate(dt_sg) def read(self, reader, parallel, kptband_comm): if reader['version'] > 0.3: density_error = reader['DensityError'] if density_error is not None: self.mixer.set_charge_sloshing(density_error) if not reader.has_array('PseudoElectronDensity'): return hdf5 = hasattr(reader, 'hdf5') nt_sG = self.gd.empty(self.nspins) if hdf5: # Read pseudoelectron density on the coarse grid # and broadcast on kpt_comm and band_comm: indices = [slice(0, self.nspins)] + self.gd.get_slice() do_read = (kptband_comm.rank == 0) reader.get('PseudoElectronDensity', out=nt_sG, parallel=parallel, read=do_read, *indices) # XXX read=? kptband_comm.broadcast(nt_sG, 0) else: for s in range(self.nspins): self.gd.distribute(reader.get('PseudoElectronDensity', s), nt_sG[s]) # Read atomic density matrices natoms = len(self.setups) atom_partition = AtomPartition(self.gd.comm, np.zeros(natoms, int)) D_asp = self.setups.empty_atomic_matrix(self.ns, atom_partition) self.atom_partition = atom_partition # XXXXXX all_D_sp = reader.get('AtomicDensityMatrices', broadcast=True) if self.gd.comm.rank == 0: D_asp.update(read_atomic_matrices(all_D_sp, self.setups)) D_asp.check_consistency() self.initialize_directly_from_arrays(nt_sG, D_asp) class RealSpaceDensity(Density): def __init__(self, gd, finegd, nspins, charge, collinear=True, stencil=3): Density.__init__(self, gd, finegd, nspins, charge, collinear) self.stencil = stencil def initialize(self, setups, timer, magmom_av, hund): Density.initialize(self, setups, timer, magmom_av, hund) # Interpolation function for the density: self.interpolator = Transformer(self.gd, self.finegd, self.stencil) spline_aj = [] for setup in setups: if setup.nct is None: spline_aj.append([]) else: spline_aj.append([setup.nct]) self.nct = LFC(self.gd, spline_aj, integral=[setup.Nct for setup in setups], forces=True, cut=True) self.ghat = LFC(self.finegd, [setup.ghat_l for setup in setups], integral=sqrt(4 * pi), forces=True) def set_positions(self, spos_ac, rank_a=None): Density.set_positions(self, spos_ac, rank_a) self.nct_G = self.gd.zeros() self.nct.add(self.nct_G, 1.0 / self.nspins) def interpolate_pseudo_density(self, comp_charge=None): """Interpolate pseudo density to fine grid.""" if comp_charge is None: comp_charge = self.calculate_multipole_moments() self.nt_sg = self.interpolate(self.nt_sG, self.nt_sg) # With periodic boundary conditions, the interpolation will # conserve the number of electrons. if not self.gd.pbc_c.all(): # With zero-boundary conditions in one or more directions, # this is not the case. pseudo_charge = -(self.charge + comp_charge) if abs(pseudo_charge) > 1.0e-14: x = (pseudo_charge / self.finegd.integrate(self.nt_sg[:self.nspins]).sum()) self.nt_sg *= x def interpolate(self, in_xR, out_xR=None): """Interpolate array(s).""" # ndim will be 3 in finite-difference mode and 1 when working # with the AtomPAW class (spherical atoms and 1d grids) ndim = self.gd.ndim if out_xR is None: out_xR = self.finegd.empty(in_xR.shape[:-ndim]) a_xR = in_xR.reshape((-1,) + in_xR.shape[-ndim:]) b_xR = out_xR.reshape((-1,) + out_xR.shape[-ndim:]) for in_R, out_R in zip(a_xR, b_xR): self.interpolator.apply(in_R, out_R) return out_xR def calculate_pseudo_charge(self): self.nt_g = self.nt_sg[:self.nspins].sum(axis=0) self.rhot_g = self.nt_g.copy() self.ghat.add(self.rhot_g, self.Q_aL) if debug: charge = self.finegd.integrate(self.rhot_g) + self.charge if abs(charge) > self.charge_eps: raise RuntimeError('Charge not conserved: excess=%.9f' % charge) def get_pseudo_core_kinetic_energy_density_lfc(self): return LFC(self.gd, [[setup.tauct] for setup in self.setups], forces=True, cut=True) def calculate_dipole_moment(self): return self.finegd.calculate_dipole_moment(self.rhot_g) gpaw-0.11.0.13004/gpaw/scf.py0000664000175000017500000000654712553643472015555 0ustar jensjjensj00000000000000import numpy as np class SCFLoop: """Self-consistent field loop. converged: Do we have a self-consistent solution? """ def __init__(self, eigenstates=0.1, energy=0.1, density=0.1, maxiter=100, fixdensity=False, niter_fixdensity=None, force=None): self.max_eigenstates_error = max(eigenstates, 1e-20) self.max_energy_error = energy self.max_force_error = force self.max_density_error = max(density, 1e-20) self.maxiter = maxiter self.fixdensity = fixdensity if niter_fixdensity is None: niter_fixdensity = 2 self.niter_fixdensity = niter_fixdensity if fixdensity: self.fix_density() self.reset() def fix_density(self): self.fixdensity = True self.niter_fixdensity = 10000000 self.max_density_error = np.inf def reset(self): self.energies = [] self.eigenstates_error = None self.energy_error = None self.density_error = None self.force_error = None self.force_last = None self.converged = False def run(self, wfs, hamiltonian, density, occupations, forces): if self.converged: return for iter in range(1, self.maxiter + 1): wfs.eigensolver.iterate(hamiltonian, wfs) occupations.calculate(wfs) # XXX ortho, dens, wfs? energy = hamiltonian.get_energy(occupations) self.energies.append(energy) self.check_convergence(density, wfs.eigensolver, wfs, hamiltonian, forces) yield iter if self.converged: break if iter > self.niter_fixdensity: density.update(wfs) hamiltonian.update(density) else: hamiltonian.npoisson = 0 # Don't fix the density in the next step: self.niter_fixdensity = 0 def check_convergence(self, density, eigensolver, wfs=None, hamiltonian=None, forces=None): """Check convergence of eigenstates, energy and density.""" if self.converged: return True self.eigenstates_error = eigensolver.error if len(self.energies) < 3: self.energy_error = self.max_energy_error else: self.energy_error = np.ptp(self.energies[-3:]) self.density_error = density.mixer.get_charge_sloshing() if self.density_error is None: self.density_error = 1000000.0 if self.max_force_error is not None: forces.reset() F_av = forces.calculate(wfs, density, hamiltonian) if self.force_last is None: self.force_last = F_av else: F_av_diff = ((F_av - self.force_last)**2).sum(axis=1) self.force_error = abs(F_av_diff).max() self.force_last = F_av self.converged = ( (self.eigenstates_error or 0.0) < self.max_eigenstates_error and self.energy_error < self.max_energy_error and self.density_error < self.max_density_error and (self.force_error or 0) < ((self.max_force_error) or float('Inf'))) return self.converged gpaw-0.11.0.13004/gpaw/output.py0000664000175000017500000005202512553643470016330 0ustar jensjjensj00000000000000from __future__ import print_function import os import sys import time import platform from math import log import numpy as np import ase from ase.units import Bohr, Hartree from ase.data import chemical_symbols from ase.version import version as ase_version from ase.utils import devnull from ase.parallel import get_txt import gpaw import _gpaw from gpaw.version import version from gpaw.utilities.memory import maxrss from gpaw import dry_run, extra_parameters class PAWTextOutput: """Class for handling all text output.""" def __init__(self): self.txt = devnull def set_txt(self, txt): """Set the stream for text output. If `txt` is not a stream-object, then it must be one of: * None: Throw output away. * '-': Use stdout (``sys.stdout``) on master, elsewhere throw away. * A filename: Open a new file on master, elsewhere throw away. """ self.txt = get_txt(txt, self.wfs.world.rank) self.print_header() def text(self, *args, **kwargs): print(*args, file=self.txt, **kwargs) def print_header(self): self.text() self.text(' ___ ___ ___ _ _ _ ') self.text(' | | |_ | | | | ') self.text(' | | | | | . | | | | ') self.text(' |__ | _|___|_____| ', version) self.text(' |___|_| ') self.text() uname = platform.uname() self.text('User: ', os.getenv('USER', '???') + '@' + uname[1]) self.text('Date: ', time.asctime()) self.text('Arch: ', uname[4]) self.text('Pid: ', os.getpid()) self.text('gpaw: ', os.path.dirname(gpaw.__file__)) # Find C-code: c = getattr(_gpaw, '__file__', None) if not c: c = sys.executable self.text('_gpaw:', os.path.normpath(c)) self.text('ase: %s (version %s)' % (os.path.dirname(ase.__file__), ase_version)) self.text('numpy: %s (version %s)' % (os.path.dirname(np.__file__), np.version.version)) try: import scipy as sp self.text('scipy: %s (version %s)' % (os.path.dirname(sp.__file__), sp.version.version)) # Explicitly deleting SciPy seems to remove garbage collection # problem of unknown cause del sp except ImportError: self.text('scipy: Not available') self.text('units: Angstrom and eV') self.text('cores:', self.wfs.world.size) if gpaw.debug: self.text('DEBUG MODE') if extra_parameters: self.text('Extra parameters:', extra_parameters) def print_cell_and_parameters(self): self.plot_atoms(self.atoms) self.print_unit_cell(self.atoms.get_positions() / Bohr) self.print_parameters() def print_unit_cell(self, pos_ac): self.text() self.text('Unit Cell:') self.text(' Periodic X Y Z' + ' Points Spacing') self.text(' -----------------------------------------------' + '---------------------') gd = self.wfs.gd h_c = gd.get_grid_spacings() pbc_c = self.atoms.pbc for c in range(3): self.text(' %d. axis: %s %10.6f %10.6f %10.6f %3d %8.4f' % ((c + 1, ['no ', 'yes'][int(pbc_c[c])]) + tuple(Bohr * gd.cell_cv[c]) + (gd.N_c[c], Bohr * h_c[c]))) self.text() def print_positions(self): t = self.text t() t('Positions:') symbols = self.atoms.get_chemical_symbols() for a, pos_c in enumerate(self.atoms.get_positions()): symbol = symbols[a] t('%3d %-2s %9.4f %9.4f %9.4f' % ((a, symbol) + tuple(pos_c))) t() def print_parameters(self): t = self.text p = self.input_parameters # Write PAW setup information in order of appearance: ids = set() for id in self.wfs.setups.id_a: if id in ids: continue ids.add(id) setup = self.wfs.setups.setups[id] setup.print_info(self.text) basis_descr = setup.get_basis_description() t(basis_descr) t() t('Using the %s Exchange-Correlation Functional.' % self.hamiltonian.xc.name) if self.wfs.nspins == 2: t('Spin-Polarized Calculation.') t('Magnetic Moment: (%.6f, %.6f, %.6f)' % tuple(self.density.magmom_av.sum(0)), end='') if self.occupations.fixmagmom: t('(fixed)') else: t() else: t('Spin-Paired Calculation') t('Total Charge: %.6f' % p['charge']) t('Fermi Temperature: %.6f' % (self.occupations.width * Hartree)) self.wfs.summary(self.txt) t('Eigensolver: %s' % self.wfs.eigensolver) self.hamiltonian.summary(self.txt) t('Reference Energy: %.6f' % (self.wfs.setups.Eref * Hartree)) t() nibzkpts = self.wfs.kd.nibzkpts # Print parallelization details t('Total number of cores used: %d' % self.wfs.world.size) if self.wfs.kd.comm.size > 1: # kpt/spin parallization if self.wfs.nspins == 2 and nibzkpts == 1: t('Parallelization over spin') elif self.wfs.nspins == 2: t('Parallelization over k-points and spin: %d' % self.wfs.kd.comm.size) else: t('Parallelization over k-points: %d' % self.wfs.kd.comm.size) if self.wfs.gd.comm.size > 1: # domain parallelization t('Domain Decomposition: %d x %d x %d' % tuple(self.wfs.gd.parsize_c)) if self.wfs.bd.comm.size > 1: # band parallelization t('Parallelization over states: %d' % self.wfs.bd.comm.size) if self.wfs.mode == 'fd': # XXX Why is this not in wfs summary? -askhl # Also, why wouldn't PW mode use the diagonalizer? if self.wfs.diagksl.buffer_size is not None: t('MatrixOperator buffer_size (KiB): %d' % self.wfs.diagksl.buffer_size) else: t('MatrixOperator buffer_size: default value or \n' + ' %s see value of nblock in input file' % (26 * ' ')) diagonalizer_layout = self.wfs.diagksl.get_description() t('Diagonalizer layout: ' + diagonalizer_layout) orthonormalizer_layout = self.wfs.orthoksl.get_description() t('Orthonormalizer layout: ' + orthonormalizer_layout) t() self.wfs.kd.symmetry.print_symmetries(self.txt) t(self.wfs.kd.description) t(('%d k-point%s in the Irreducible Part of the Brillouin Zone') % (nibzkpts, ' s'[1:nibzkpts])) kd = self.wfs.kd w_k = kd.weight_k * kd.nbzkpts assert np.allclose(w_k, w_k.round()) w_k = w_k.round() t() t(' k-points in crystal coordinates weights') for k in range(nibzkpts): if k < 10 or k == nibzkpts - 1: t('%4d: %12.8f %12.8f %12.8f %6d/%d' % ((k,) + tuple(kd.ibzk_kc[k]) + (w_k[k], kd.nbzkpts))) elif k == 10: t(' ...') t() if self.scf.fixdensity > self.scf.maxiter: t('Fixing the initial density') else: mixer = self.density.mixer t('Mixer Type:', mixer.__class__.__name__) t('Linear Mixing Parameter: %g' % mixer.beta) t('Mixing with %d Old Densities' % mixer.nmaxold) if mixer.weight == 1: t('No Damping of Long Wave Oscillations') else: t('Damping of Long Wave Oscillations: %g' % mixer.weight) cc = p['convergence'] t() t('Convergence Criteria:') t(' Total Energy Change: %g eV / electron' % (cc['energy'])) t(' Integral of Absolute Density Change: %g electrons' % cc['density']) t(' Integral of Absolute Eigenstate Change: %g eV^2' % cc['eigenstates']) t('Number of Atoms: %d' % len(self.wfs.setups)) t('Number of Atomic Orbitals: %d' % self.wfs.setups.nao) if self.nbands_parallelization_adjustment != 0: t('Adjusting Number of Bands by %+d to Match Parallelization' % self.nbands_parallelization_adjustment) t('Number of Bands in Calculation: %d' % self.wfs.bd.nbands) t('Bands to Converge: ', end='') if cc['bands'] == 'occupied': t('Occupied States Only') elif cc['bands'] == 'all': t('All') else: t('%d Lowest Bands' % cc['bands']) t('Number of Valence Electrons: %g' % (self.wfs.setups.nvalence - p.charge)) def print_converged(self, iter): t = self.text t('------------------------------------') t('Converged After %d Iterations.' % iter) t() self.print_all_information() def print_all_information(self): t = self.text if len(self.atoms) == 1: t('Energy Contributions Relative to Reference Atom:', end='') else: t('Energy Contributions Relative to Reference Atoms:', end='') t('(reference = %.6f)' % (self.wfs.setups.Eref * Hartree)) t('-------------------------') energies = [('Kinetic: ', self.hamiltonian.Ekin), ('Potential: ', self.hamiltonian.Epot), ('External: ', self.hamiltonian.Eext), ('XC: ', self.hamiltonian.Exc), ('Entropy (-ST):', -self.hamiltonian.S), ('Local: ', self.hamiltonian.Ebar)] for name, e in energies: t('%-14s %+11.6f' % (name, Hartree * e)) t('-------------------------') t('Free Energy: %+11.6f' % (Hartree * self.hamiltonian.Etot)) t('Zero Kelvin: %+11.6f' % (Hartree * (self.hamiltonian.Etot + 0.5 * self.hamiltonian.S))) t() self.occupations.print_fermi_level(self.txt) self.print_eigenvalues() self.hamiltonian.xc.summary(self.txt) t() try: dipole = self.get_dipole_moment() except NotImplementedError: pass else: if self.density.charge == 0: t('Dipole Moment: %s' % dipole) else: t('Center of Charge: %s' % (dipole / self.density.charge)) try: correction = self.hamiltonian.poisson.corrector.correction epsF = self.occupations.fermilevel except AttributeError: pass else: wf1 = (-epsF + correction) * Hartree wf2 = (-epsF - correction) * Hartree t('Dipole-corrected work function: %f, %f' % (wf1, wf2)) if self.wfs.nspins == 2: t() magmom = self.occupations.magmom t('Total Magnetic Moment: %f' % magmom) try: # XXX This doesn't always work, HGH, SIC, ... sc = self.density.get_spin_contamination(self.atoms, int(magmom < 0)) t('Spin contamination: %f electrons' % sc) except (TypeError, AttributeError): pass t('Local Magnetic Moments:') for a, mom in enumerate(self.get_magnetic_moments()): t(a, mom) t() elif not self.wfs.collinear: self.txt.write('Local Magnetic Moments:\n') for a, mom_v in enumerate(self.get_magnetic_moments()): self.txt.write('%4d (%.3f, %.3f, %.3f)\n' % (a, mom_v[0], mom_v[1], mom_v[2])) def print_iteration(self, iter): # Output from each iteration: t = self.text nvalence = self.wfs.setups.nvalence - self.input_parameters.charge if nvalence > 0: eigerr = self.scf.eigenstates_error * Hartree**2 / nvalence else: eigerr = 0.0 if self.verbose != 0: T = time.localtime() t() t('------------------------------------') t('iter: %d %d:%02d:%02d' % (iter, T[3], T[4], T[5])) t() t('Poisson Solver Converged in %d Iterations' % self.hamiltonian.npoisson) t('Fermi Level Found in %d Iterations' % self.occupations.niter) t('Error in Wave Functions: %.13f' % eigerr) t() self.print_all_information() else: if iter == 1: header = """\ log10-error: Total Iterations: Time WFS Density Energy Fermi Poisson""" if self.wfs.nspins == 2: header += ' MagMom' if self.scf.max_force_error is not None: l1 = header.find('Total') header = header[:l1] + ' ' + header[l1:] l2 = header.find('Energy') header = header[:l2] + 'Force ' + header[l2:] t(header) T = time.localtime() if eigerr == 0.0: eigerr = '' else: eigerr = '%+.2f' % (log(eigerr) / log(10)) denserr = self.density.mixer.get_charge_sloshing() if denserr is None or denserr == 0 or nvalence == 0: denserr = '' else: denserr = '%+.2f' % (log(denserr / nvalence) / log(10)) niterocc = self.occupations.niter if niterocc == -1: niterocc = '' else: niterocc = '%d' % niterocc if self.hamiltonian.npoisson == 0: niterpoisson = '' else: niterpoisson = str(self.hamiltonian.npoisson) t('iter: %3d %02d:%02d:%02d %6s %6s ' % (iter, T[3], T[4], T[5], eigerr, denserr), end='') if self.scf.max_force_error is not None: if self.scf.force_error is not None: t(' %+.2f' % (log(self.scf.force_error) / log(10)), end='') else: t(' ', end='') t('%11.6f %-5s %-7s' % (Hartree * (self.hamiltonian.Etot + 0.5 * self.hamiltonian.S), niterocc, niterpoisson), end='') if self.wfs.nspins == 2: t(' %+.4f' % self.occupations.magmom, end='') t() self.txt.flush() def print_forces(self): if self.forces.F_av is None: return t = self.text t() t('Forces in eV/Ang:') c = Hartree / Bohr symbols = self.atoms.get_chemical_symbols() for a, symbol in enumerate(symbols): t('%3d %-2s %10.5f %10.5f %10.5f' % ((a, symbol) + tuple(self.forces.F_av[a] * c))) def print_eigenvalues(self): """Print eigenvalues and occupation numbers.""" self.text(eigenvalue_string(self)) def plot_atoms(self, atoms): self.text(plot(atoms)) def __del__(self): """Destructor: Write timing output before closing.""" if not dry_run: mr = maxrss() if mr > 0: if mr < 1024.0**3: self.text('Memory usage: %.2f MiB' % (mr / 1024.0**2)) else: self.text('Memory usage: %.2f GiB' % (mr / 1024.0**3)) self.timer.write(self.txt) def eigenvalue_string(paw, comment=' '): """ Write eigenvalues and occupation numbers into a string. The parameter comment can be used to comment out non-numers, for example to escape it for gnuplot. """ tokens = [] def add(*line): for token in line: tokens.append(token) tokens.append('\n') if len(paw.wfs.kd.ibzk_kc) == 1: if paw.wfs.nspins == 1: add(comment, 'Band Eigenvalues Occupancy') eps_n = paw.get_eigenvalues(kpt=0, spin=0) f_n = paw.get_occupation_numbers(kpt=0, spin=0) if paw.wfs.world.rank == 0: for n in range(paw.wfs.bd.nbands): add('%5d %11.5f %9.5f' % (n, eps_n[n], f_n[n])) else: add(comment, ' Up Down') add(comment, 'Band Eigenvalues Occupancy Eigenvalues ' 'Occupancy') epsa_n = paw.get_eigenvalues(kpt=0, spin=0, broadcast=False) epsb_n = paw.get_eigenvalues(kpt=0, spin=1, broadcast=False) fa_n = paw.get_occupation_numbers(kpt=0, spin=0, broadcast=False) fb_n = paw.get_occupation_numbers(kpt=0, spin=1, broadcast=False) if paw.wfs.world.rank == 0: for n in range(paw.wfs.bd.nbands): add('%5d %11.5f %9.5f %11.5f %9.5f' % (n, epsa_n[n], fa_n[n], epsb_n[n], fb_n[n])) return ''.join(tokens) if len(paw.wfs.kd.ibzk_kc) > 10: add('Warning: Showing only first 10 kpts') print_range = 10 else: add('Showing all kpts') print_range = len(paw.wfs.kd.ibzk_kc) if paw.wfs.nvalence / 2. > 10: m = int(paw.wfs.nvalence / 2. - 10) else: m = 0 if paw.wfs.bd.nbands - paw.wfs.nvalence / 2. > 10: j = int(paw.wfs.nvalence / 2. + 10) else: j = int(paw.wfs.bd.nbands) if paw.wfs.nspins == 1: add(comment, 'Kpt Band Eigenvalues Occupancy') for i in range(print_range): eps_n = paw.get_eigenvalues(kpt=i, spin=0) f_n = paw.get_occupation_numbers(kpt=i, spin=0) if paw.wfs.world.rank == 0: for n in range(m, j): add('%3i %5d %11.5f %9.5f' % (i, n, eps_n[n], f_n[n])) add() else: add(comment, ' Up Down') add(comment, 'Kpt Band Eigenvalues Occupancy Eigenvalues ' 'Occupancy') for i in range(print_range): epsa_n = paw.get_eigenvalues(kpt=i, spin=0, broadcast=False) epsb_n = paw.get_eigenvalues(kpt=i, spin=1, broadcast=False) fa_n = paw.get_occupation_numbers(kpt=i, spin=0, broadcast=False) fb_n = paw.get_occupation_numbers(kpt=i, spin=1, broadcast=False) if paw.wfs.world.rank == 0: for n in range(m, j): add('%3i %5d %11.5f %9.5f %11.5f %9.5f' % (i, n, epsa_n[n], fa_n[n], epsb_n[n], fb_n[n])) add() return ''.join(tokens) def plot(atoms): """Ascii-art plot of the atoms.""" # y # | # .-- x # / # z cell_cv = atoms.get_cell() if (cell_cv - np.diag(cell_cv.diagonal())).any(): atoms = atoms.copy() atoms.cell = [1, 1, 1] atoms.center(vacuum=2.0) cell_cv = atoms.get_cell() plot_box = False else: plot_box = True cell = np.diagonal(cell_cv) / Bohr positions = atoms.get_positions() / Bohr numbers = atoms.get_atomic_numbers() s = 1.3 nx, ny, nz = n = (s * cell * (1.0, 0.25, 0.5) + 0.5).astype(int) sx, sy, sz = n / cell grid = Grid(nx + ny + 4, nz + ny + 1) positions = (positions % cell + cell) % cell ij = np.dot(positions, [(sx, 0), (sy, sy), (0, sz)]) ij = np.around(ij).astype(int) for a, Z in enumerate(numbers): symbol = chemical_symbols[Z] i, j = ij[a] depth = positions[a, 1] for n, c in enumerate(symbol): grid.put(c, i + n + 1, j, depth) if plot_box: k = 0 for i, j in [(1, 0), (1 + nx, 0)]: grid.put('*', i, j) grid.put('.', i + ny, j + ny) if k == 0: grid.put('*', i, j + nz) grid.put('.', i + ny, j + nz + ny) for y in range(1, ny): grid.put('/', i + y, j + y, y / sy) if k == 0: grid.put('/', i + y, j + y + nz, y / sy) for z in range(1, nz): if k == 0: grid.put('|', i, j + z) grid.put('|', i + ny, j + z + ny) k = 1 for i, j in [(1, 0), (1, nz)]: for x in range(1, nx): if k == 1: grid.put('-', i + x, j) grid.put('-', i + x + ny, j + ny) k = 0 return '\n'.join([''.join([chr(x) for x in line]) for line in np.transpose(grid.grid)[::-1]]) class Grid: def __init__(self, i, j): self.grid = np.zeros((i, j), np.int8) self.grid[:] = ord(' ') self.depth = np.zeros((i, j)) self.depth[:] = 1e10 def put(self, c, i, j, depth=1e9): if depth < self.depth[i, j]: self.grid[i, j] = ord(c) self.depth[i, j] = depth gpaw-0.11.0.13004/gpaw/elph/0000775000175000017500000000000012553644063015341 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/elph/electronphonon.py0000664000175000017500000010451712553643470020761 0ustar jensjjensj00000000000000"""Module for calculating electron-phonon couplings. Electron-phonon interaction:: __ \ l + + H = ) g c c ( a + a ), el-ph /_ ij i j l l l,ij where the electron phonon coupling is given by:: ______ l / hbar ___ g = /------- < i | \ / V * e | j > . ij \/ 2 M w 'u eff l l Here, l denotes the vibrational mode, w_l and e_l is the frequency and mass-scaled polarization vector, respectively, M is an effective mass, i, j are electronic state indices and nabla_u denotes the gradient wrt atomic displacements. The implementation supports calculations of the el-ph coupling in both finite and periodic systems, i.e. expressed in a basis of molecular orbitals or Bloch states. The implementation is based on finite-difference calculations of the the atomic gradients of the effective potential expressed on a real-space grid. The el-ph couplings are obtained from LCAO representations of the atomic gradients of the effective potential and the electronic states. In PAW the matrix elements of the derivative of the effective potential is given by the sum of the following contributions:: d d < i | -- V | j > = < i | -- V | j> du eff du _ \ ~a d . ~a + ) < i | p > -- /_\H < p | j > /_ i du ij j a,ij _ \ d ~a . ~a + ) < i | -- p > /_\H < p | j > /_ du i ij j a,ij _ \ ~a . d ~a + ) < i | p > /_\H < -- p | j > /_ i ij du j a,ij where the first term is the derivative of the potential (Hartree + XC) and the last three terms originate from the PAW (pseudopotential) part of the effective DFT Hamiltonian. """ import pickle from math import pi import numpy as np import numpy.fft as fft import numpy.linalg as la import ase.units as units from ase.phonons import Displacement from gpaw.utilities import unpack2 from gpaw.utilities.tools import tri2full from gpaw.utilities.timing import StepTimer, nulltimer from gpaw.lcao.overlap import ManySiteDictionaryWrapper, \ TwoCenterIntegralCalculator from gpaw.lcao.tightbinding import TightBinding from gpaw.kpt_descriptor import KPointDescriptor class ElectronPhononCoupling(Displacement): """Class for calculating the electron-phonon coupling in an LCAO basis. The derivative of the effective potential wrt atomic displacements is obtained from a finite difference approximation to the derivative by doing a self-consistent calculation for atomic displacements in the +/- directions. These calculations are carried out in the ``run`` member function. The subsequent calculation of the coupling matrix in the basis of atomic orbitals (or Bloch-sums hereof for periodic systems) is handled by the ``calculate_matrix`` member function. """ def __init__(self, atoms, calc=None, supercell=(1, 1, 1), name='elph', delta=0.01, phonons=None): """Initialize with base class args and kwargs. Parameters ---------- atoms: Atoms object The atoms to work on. calc: Calculator Calculator for the supercell calculation. supercell: tuple Size of supercell given by the number of repetitions (l, m, n) of the small unit cell in each direction. name: str Name to use for files (default: 'elph'). delta: float Magnitude of displacements. phonons: Phonons object If provided, the ``__call__`` member function of the ``Phonons`` class in ASE will be called in the ``__call__`` member function of this class. """ # Init base class and make the center cell in the supercell the # reference cell Displacement.__init__(self, atoms, calc=calc, supercell=supercell, name=name, delta=delta, refcell='center') # Store ``Phonons`` object in attribute self.phonons = phonons # Log self.set_log() # LCAO calculator self.calc_lcao = None # Supercell matrix self.g_xNNMM = None def __call__(self, atoms_N): """Extract effective potential and projector coefficients.""" # Do calculation atoms_N.get_potential_energy() # Call phonons class if provided if self.phonons is not None: forces = self.phonons.__call__(atoms_N) # Get calculator calc = atoms_N.get_calculator() # Effective potential (in Hartree) and projector coefficients Vt_G = calc.hamiltonian.vt_sG[0] Vt_G = calc.wfs.gd.collect(Vt_G, broadcast=True) dH_asp = calc.hamiltonian.dH_asp setups = calc.wfs.setups nspins = calc.wfs.nspins gd_comm = calc.wfs.gd.comm dH_all_asp = {} for a, setup in enumerate(setups): ni = setup.ni nii = ni * (ni + 1) // 2 dH_tmp_sp = np.zeros((nspins, nii)) if a in dH_asp: dH_tmp_sp[:] = dH_asp[a] gd_comm.sum(dH_tmp_sp) dH_all_asp[a] = dH_tmp_sp return Vt_G, dH_all_asp def set_lcao_calculator(self, calc): """Set LCAO calculator for the calculation of the supercell matrix.""" # Add parameter checks here # - check that gamma # - check that no symmetries are used # - ... assert calc.input_parameters['mode'] == 'lcao', 'LCAO mode required.' symmetry = calc.input_parameters['symmetry'] assert not symmetry['point_group'], 'Symmetries not supported.' self.calc_lcao = calc def set_basis_info(self, *args): """Store lcao basis info for atoms in reference cell in attribute. Parameters ---------- args: tuple If the LCAO calculator is not available (e.g. if the supercell is loaded from file), the ``load_supercell_matrix`` member function provides the required info as arguments. """ if len(args) == 0: calc = self.calc_lcao setups = calc.wfs.setups bfs = calc.wfs.basis_functions nao_a = [setups[a].nao for a in range(len(self.atoms))] M_a = [bfs.M_a[a] for a in range(len(self.atoms))] else: M_a = args[0] nao_a = args[1] self.basis_info = {'M_a': M_a, 'nao_a': nao_a} def set_log(self, log=None): """Set output log.""" if log is None: self.timer = nulltimer elif log == '-': self.timer = StepTimer(name='elph') else: self.timer = StepTimer(name='elph', out=open(log, 'w')) def calculate_supercell_matrix(self, dump=0, name=None, filter=None, include_pseudo=True, atoms=None): """Calculate matrix elements of the el-ph coupling in the LCAO basis. This function calculates the matrix elements between LCAOs and local atomic gradients of the effective potential. The matrix elements are calculated for the supercell used to obtain finite-difference approximations to the derivatives of the effective potential wrt to atomic displacements. Parameters ---------- dump: int Dump supercell matrix to pickle file (default: 0). 0: Supercell matrix not saved 1: Supercell matrix saved in a single pickle file. 2: Dump matrix for different gradients in separate files. Useful for large systems where the total array gets too large for a single pickle file. name: string User specified name of the generated pickle file(s). If not provided, the string in the ``name`` attribute is used. filter: str Fourier filter atomic gradients of the effective potential. The specified components (``normal`` or ``umklapp``) are removed (default: None). include_pseudo: bool Include the contribution from the psedupotential in the atomic gradients. If ``False``, only the gradient of the effective potential is included (default: True). atoms: Atoms object Calculate supercell for an ``Atoms`` object different from the one provided in the ``__init__`` method (WARNING, NOT working!). """ assert self.calc_lcao is not None, "Set LCAO calculator" # Supercell atoms if atoms is None: atoms_N = self.atoms * self.N_c else: atoms_N = atoms # Initialize calculator if required and extract useful quantities calc = self.calc_lcao if not hasattr(calc.wfs, 'S_qMM'): calc.initialize(atoms_N) calc.initialize_positions(atoms_N) self.set_basis_info() basis = calc.input_parameters['basis'] # Extract useful objects from the calculator wfs = calc.wfs gd = calc.wfs.gd kd = calc.wfs.kd kpt_u = wfs.kpt_u setups = wfs.setups nao = setups.nao bfs = wfs.basis_functions dtype = wfs.dtype spin = 0 # XXX # If gamma calculation, overlap with neighboring cell cannot be removed if kd.gamma: print("WARNING: Gamma-point calculation.") else: # Bloch to real-space converter tb = TightBinding(atoms_N, calc) self.timer.write_now("Calculating supercell matrix") self.timer.write_now("Calculating real-space gradients") # Calculate finite-difference gradients (in Hartree / Bohr) V1t_xG, dH1_xasp = self.calculate_gradient() self.timer.write_now("Finished real-space gradients") # Fourier filter the atomic gradients of the effective potential if filter is not None: self.timer.write_now("Fourier filtering gradients") V1_xG = V1t_xG.copy() self.fourier_filter(V1t_xG, components=filter) self.timer.write_now("Finished Fourier filtering") # For the contribution from the derivative of the projectors dP_aqvMi = self.calculate_dP_aqvMi(wfs) # Equilibrium atomic Hamiltonian matrix (projector coefficients) dH_asp = pickle.load(open(self.name + '.eq.pckl'))[1] # Check that the grid is the same as in the calculator assert np.all(V1t_xG.shape[-3:] == (gd.N_c + gd.pbc_c - 1)), \ "Mismatch in grids." # Calculate < i k | grad H | j k >, i.e. matrix elements in Bloch basis # List for supercell matrices; g_xNNMM = [] self.timer.write_now("Calculating gradient of PAW Hamiltonian") # Do each cartesian component separately for i, a in enumerate(self.indices): for v in range(3): # Corresponding array index x = 3 * i + v V1t_G = V1t_xG[x] self.timer.write_now("%s-gradient of atom %u" % (['x','y','z'][v], a)) # Array for different k-point components g_qMM = np.zeros((len(kpt_u), nao, nao), dtype) # 1) Gradient of effective potential self.timer.write_now("Starting gradient of effective potential") for kpt in kpt_u: # Matrix elements geff_MM = np.zeros((nao, nao), dtype) bfs.calculate_potential_matrix(V1t_G, geff_MM, q=kpt.q) tri2full(geff_MM, 'L') # Insert in array g_qMM[kpt.q] += geff_MM self.timer.write_now("Finished gradient of effective potential") if include_pseudo: self.timer.write_now("Starting gradient of pseudo part") # 2) Gradient of non-local part (projectors) self.timer.write_now("Starting gradient of dH^a") P_aqMi = calc.wfs.P_aqMi # 2a) dH^a part has contributions from all other atoms for kpt in kpt_u: # Matrix elements gp_MM = np.zeros((nao, nao), dtype) dH1_asp = dH1_xasp[x] for a_, dH1_sp in dH1_asp.items(): dH1_ii = unpack2(dH1_sp[spin]) gp_MM += np.dot(P_aqMi[a_][kpt.q], np.dot(dH1_ii, P_aqMi[a_][kpt.q].T.conjugate())) g_qMM[kpt.q] += gp_MM self.timer.write_now("Finished gradient of dH^a") self.timer.write_now("Starting gradient of projectors") # 2b) dP^a part has only contributions from the same atoms dP_qvMi = dP_aqvMi[a] dH_ii = unpack2(dH_asp[a][spin]) for kpt in kpt_u: #XXX Sort out the sign here; conclusion -> sign = +1 ! P1HP_MM = +1 * np.dot(dP_qvMi[kpt.q][v], np.dot(dH_ii, P_aqMi[a][kpt.q].T.conjugate())) # Matrix elements gp_MM = P1HP_MM + P1HP_MM.T.conjugate() g_qMM[kpt.q] += gp_MM self.timer.write_now("Finished gradient of projectors") self.timer.write_now("Finished gradient of pseudo part") # Extract R_c=(0, 0, 0) block by Fourier transforming if kd.gamma or kd.N_c is None: g_MM = g_qMM[0] else: # Convert to array g_MM = tb.bloch_to_real_space(g_qMM, R_c=(0, 0, 0))[0] # Reshape to global unit cell indices N = np.prod(self.N_c) # Number of basis function in the primitive cell assert (nao % N) == 0, "Alarm ...!" nao_cell = nao / N g_NMNM = g_MM.reshape((N, nao_cell, N, nao_cell)) g_NNMM = g_NMNM.swapaxes(1, 2).copy() self.timer.write_now("Finished supercell matrix") if dump != 2: g_xNNMM.append(g_NNMM) else: if name is not None: fname = '%s.supercell_matrix_x_%2.2u.%s.pckl' % (name, x, basis) else: fname = self.name + \ '.supercell_matrix_x_%2.2u.%s.pckl' % (x, basis) if kd.comm.rank == 0: fd = open(fname, 'w') M_a = self.basis_info['M_a'] nao_a = self.basis_info['nao_a'] pickle.dump((g_NNMM, M_a, nao_a), fd, 2) fd.close() self.timer.write_now("Finished gradient of PAW Hamiltonian") if dump != 2: # Collect gradients in one array self.g_xNNMM = np.array(g_xNNMM) # Dump to pickle file using binary mode together with basis info if dump and kd.comm.rank == 0: if name is not None: fname = '%s.supercell_matrix.%s.pckl' % (name, basis) else: fname = self.name + '.supercell_matrix.%s.pckl' % basis fd = open(fname, 'w') M_a = self.basis_info['M_a'] nao_a = self.basis_info['nao_a'] pickle.dump((self.g_xNNMM, M_a, nao_a), fd, 2) fd.close() def load_supercell_matrix(self, basis=None, name=None, multiple=False): """Load supercell matrix from pickle file. Parameters ---------- basis: string String specifying the LCAO basis used to calculate the supercell matrix, e.g. 'dz(dzp)'. name: string User specified name of the pickle file. multiple: bool Load each derivative from individual files. """ assert (basis is not None) or (name is not None), \ "Provide basis or name." if self.g_xNNMM is not None: self.g_xNNMM = None if not multiple: # File name if name is not None: fname = name else: fname = self.name + '.supercell_matrix.%s.pckl' % basis fd = open(fname) self.g_xNNMM, M_a, nao_a = pickle.load(fd) fd.close() else: g_xNNMM = [] for x in range(len(self.indices)*3): if name is not None: fname = name else: fname = self.name + \ '.supercell_matrix_x_%2.2u.%s.pckl' % (x, basis) fd = open(fname, 'r') g_NNMM, M_a, nao_a = pickle.load(fd) fd.close() g_xNNMM.append(g_NNMM) self.g_xNNMM = np.array(g_xNNMM) self.set_basis_info(M_a, nao_a) def apply_cutoff(self, cutmax=None, cutmin=None): """Zero matrix element inside/beyond the specified cutoffs. Parameters ---------- cutmax: float Zero matrix elements for basis functions with a distance to the atomic gradient that is larger than the cutoff. cutmin: float Zero matrix elements where both basis functions have distances to the atomic gradient that is smaller than the cutoff. """ if cutmax is not None: cutmax = float(cutmax) if cutmin is not None: cutmin = float(cutmin) # Reference to supercell matrix attribute g_xNNMM = self.g_xNNMM # Number of atoms and primitive cells N_atoms = len(self.indices) N = np.prod(self.N_c) nao = g_xNNMM.shape[-1] # Reshape array g_avNNMM = g_xNNMM.reshape(N_atoms, 3, N, N, nao, nao) # Make slices for orbitals on atoms M_a = self.basis_info['M_a'] nao_a = self.basis_info['nao_a'] slice_a = [] for a in range(len(self.atoms)): start = M_a[a] ; stop = start + nao_a[a] s = slice(start, stop) slice_a.append(s) # Lattice vectors R_cN = self.lattice_vectors() # Unit cell vectors cell_vc = self.atoms.cell.transpose() # Atomic positions in reference cell pos_av = self.atoms.get_positions() # Create a mask array to zero the relevant matrix elements if cutmin is not None: mask_avNNMM = np.zeros(g_avNNMM.shape, dtype=bool) # Zero elements where one of the basis orbitals has a distance to atoms # (atomic gradients) in the reference cell larger than the cutoff for n in range(N): # Lattice vector to cell R_v = np.dot(cell_vc, R_cN[:, n]) # Atomic positions in cell posn_av = pos_av + R_v for i, a in enumerate(self.indices): # Atomic distances wrt to the position of the gradient dist_a = np.sqrt(np.sum((pos_av[a] - posn_av)**2, axis=-1)) if cutmax is not None: # Atoms indices where the distance is larger than the max # cufoff j_a = np.where(dist_a > cutmax)[0] # Zero elements for j in j_a: g_avNNMM[a, :, n, :, slice_a[j], :] = 0.0 g_avNNMM[a, :, :, n, :, slice_a[j]] = 0.0 if cutmin is not None: # Atoms indices where the distance is larger than the min # cufoff j_a = np.where(dist_a > cutmin)[0] # Update mask to keep elements where one LCAO is outside # the min cutoff for j in j_a: mask_avNNMM[a, :, n, :, slice_a[j], :] = True mask_avNNMM[a, :, :, n, :, slice_a[j]] = True # Zero elements where both LCAOs are located within the min cutoff if cutmin is not None: g_avNNMM[~mask_avNNMM] = 0.0 def lcao_matrix(self, u_l, omega_l): """Calculate the el-ph coupling in the electronic LCAO basis. For now, only works for Gamma-point phonons. Parameters ---------- u_l: ndarray Mass-scaled polarization vectors (in units of 1 / sqrt(amu)) of the phonons. omega_l: ndarray Vibrational frequencies in eV. """ # Supercell matrix (Hartree / Bohr) assert self.g_xNNMM is not None, "Load supercell matrix." assert self.g_xNNMM.shape[1:3] == (1, 1) g_xMM = self.g_xNNMM[:, 0, 0, :, :] # Number of atomic orbitals nao = g_xMM.shape[-1] # Number of phonon modes nmodes = u_l.shape[0] # u_lx = u_l.reshape(nmodes, 3 * len(self.atoms)) g_lMM = np.dot(u_lx, g_xMM.transpose(1, 0, 2)) # Multiply prefactor sqrt(hbar / 2 * M * omega) in units of Bohr amu = units._amu # atomic mass unit me = units._me # electron mass g_lMM /= np.sqrt(2 * amu / me / units.Hartree * \ omega_l[:, np.newaxis, np.newaxis]) # Convert to eV g_lMM *= units.Hartree return g_lMM def bloch_matrix(self, kpts, qpts, c_kn, u_ql, omega_ql=None, kpts_from=None): """Calculate el-ph coupling in the Bloch basis for the electrons. This function calculates the electron-phonon coupling between the specified Bloch states, i.e.:: ______ mnl / hbar ^ g = /------- < m k + q | e . grad V | n k > kq \/ 2 M w ql q ql In case the ``omega_ql`` keyword argument is not given, the bare matrix element (in units of eV / Ang) without the sqrt prefactor is returned. Parameters ---------- kpts: ndarray or tuple. k-vectors of the Bloch states. When a tuple of integers is given, a Monkhorst-Pack grid with the specified number of k-points along the directions of the reciprocal lattice vectors is generated. qpts: ndarray or tuple. q-vectors of the phonons. c_kn: ndarray Expansion coefficients for the Bloch states. The ordering must be the same as in the ``kpts`` argument. u_ql: ndarray Mass-scaled polarization vectors (in units of 1 / sqrt(amu)) of the phonons. Again, the ordering must be the same as in the corresponding ``qpts`` argument. omega_ql: ndarray Vibrational frequencies in eV. kpts_from: list of ints or int Calculate only the matrix element for the k-vectors specified by their index in the ``kpts`` argument (default: all). In short, phonon frequencies and mode vectors must be given in ase units. """ assert self.g_xNNMM is not None, "Load supercell matrix." assert len(c_kn.shape) == 3 assert len(u_ql.shape) == 4 if omega_ql is not None: assert np.all(u_ql.shape[:2] == omega_ql.shape[:2]) # Translate k-points into 1. BZ (required by ``find_k_plus_q``` member # function of the ```KPointDescriptor``). if isinstance(kpts, np.ndarray): assert kpts.shape[1] == 3, "kpts_kc array must be given" # XXX This does not seem to cause problems! kpts -= kpts.round() # Use the KPointDescriptor to keep track of the k and q-vectors kd_kpts = KPointDescriptor(kpts) kd_qpts = KPointDescriptor(qpts) # Check that number of k- and q-points agree with the number of Bloch # functions and polarization vectors assert kd_kpts.nbzkpts == len(c_kn) assert kd_qpts.nbzkpts == len(u_ql) # Include all k-point per default if kpts_from is None: kpts_kc = kd_kpts.bzk_kc kpts_k = range(kd_kpts.nbzkpts) else: kpts_kc = kd_kpts.bzk_kc[kpts_from] if isinstance(kpts_from, int): kpts_k = list([kpts_from]) else: kpts_k = list(kpts_from) # Supercell matrix (real matrix in Hartree / Bohr) g_xNNMM = self.g_xNNMM # Number of phonon modes and electronic bands nmodes = u_ql.shape[1] nbands = c_kn.shape[1] # Number of atoms displacements and basis functions ndisp = np.prod(u_ql.shape[2:]) assert ndisp == (3 * len(self.indices)) nao = c_kn.shape[2] assert ndisp == g_xNNMM.shape[0] assert nao == g_xNNMM.shape[-1] # Lattice vectors R_cN = self.lattice_vectors() # Number of unit cell in supercell N = np.prod(self.N_c) # Allocate array for couplings g_qklnn = np.zeros((kd_qpts.nbzkpts, len(kpts_kc), nmodes, nbands, nbands), dtype=complex) self.timer.write_now("Calculating coupling matrix elements") for q, q_c in enumerate(kd_qpts.bzk_kc): # Find indices of k+q for the k-points kplusq_k = kd_kpts.find_k_plus_q(q_c, kpts_k=kpts_k) # Here, ``i`` is counting from 0 and ``k`` is the global index of # the k-point for i, (k, k_c) in enumerate(zip(kpts_k, kpts_kc)): # Check the wave vectors (adapted to the ``KPointDescriptor`` class) kplusq_c = k_c + q_c kplusq_c -= kplusq_c.round() assert np.allclose(kplusq_c, kd_kpts.bzk_kc[kplusq_k[i]] ), \ (i, k, k_c, q_c, kd_kpts.bzk_kc[kplusq_k[i]]) # Allocate array g_xMM = np.zeros((ndisp, nao, nao), dtype=complex) # Multiply phase factors for m in range(N): for n in range(N): Rm_c = R_cN[:, m] Rn_c = R_cN[:, n] phase = np.exp(2.j * pi * (np.dot(k_c, Rm_c - Rn_c) + np.dot(q_c, Rm_c))) # Sum contributions from different cells g_xMM += g_xNNMM[:, m, n, :, :] * phase # LCAO coefficient for Bloch states ck_nM = c_kn[k] ckplusq_nM = c_kn[kplusq_k[i]] # Mass scaled polarization vectors u_lx = u_ql[q].reshape(nmodes, 3 * len(self.atoms)) g_nxn = np.dot(ckplusq_nM.conj(), np.dot(g_xMM, ck_nM.T)) g_lnn = np.dot(u_lx, g_nxn) # Insert value g_qklnn[q, i] = g_lnn # XXX Temp if np.all(q_c == 0.0): # These should be real print(g_qklnn[q].imag.min(), g_qklnn[q].imag.max()) self.timer.write_now("Finished calculation of coupling matrix elements") # Return the bare matrix element if frequencies are not given if omega_ql is None: # Convert to eV / Ang g_qklnn *= units.Hartree / units.Bohr else: # Multiply prefactor sqrt(hbar / 2 * M * omega) in units of Bohr amu = units._amu # atomic mass unit me = units._me # electron mass g_qklnn /= np.sqrt(2 * amu / me / units.Hartree * \ omega_ql[:, np.newaxis, :, np.newaxis, np.newaxis]) # Convert to eV g_qklnn *= units.Hartree # Return couplings in eV (or eV / Ang) return g_qklnn def fourier_filter(self, V1t_xG, components='normal', criteria=1): """Fourier filter atomic gradients of the effective potential. Parameters ---------- V1t_xG: ndarray Array representation of atomic gradients of the effective potential in the supercell grid. components: str Fourier components to filter out (``normal`` or ``umklapp``). """ assert components in ['normal', 'umklapp'] # Grid shape shape = V1t_xG.shape[-3:] # Primitive unit cells in Bohr/Bohr^-1 cell_cv = self.atoms.get_cell() / units.Bohr reci_vc = 2 * pi * la.inv(cell_cv) norm_c = np.sqrt(np.sum(reci_vc**2, axis=0)) # Periodic BC array pbc_c = np.array(self.atoms.get_pbc(), dtype=bool) # Supercell atoms and cell atoms_N = self.atoms * self.N_c supercell_cv = atoms_N.get_cell() / units.Bohr # q-grid in units of the grid spacing (FFT ordering) q_cG = np.indices(shape).reshape(3, -1) q_c = np.array(shape)[:, np.newaxis] q_cG += q_c // 2 q_cG %= q_c q_cG -= q_c // 2 # Locate q-points inside the Brillouin zone if criteria == 0: # Works for all cases # Grid spacing in direction of reciprocal lattice vectors h_c = np.sqrt(np.sum((2 * pi * la.inv(supercell_cv))**2, axis=0)) # XXX Why does a "*=" operation on q_cG not work here ?? q1_cG = q_cG * h_c[:, np.newaxis] / (norm_c[:, np.newaxis] / 2) mask_G = np.ones(np.prod(shape), dtype=bool) for i, pbc in enumerate(pbc_c): if not pbc: continue mask_G &= (-1. < q1_cG[i]) & (q1_cG[i] <= 1.) else: # 2D hexagonal lattice # Projection of q points onto the periodic directions. Only in # these directions do normal and umklapp processees make sense. q_vG = np.dot(q_cG[pbc_c].T, 2 * pi * la.inv(supercell_cv).T[pbc_c]).T.copy() # Parametrize the BZ boundary in terms of the angle theta theta_G = np.arctan2(q_vG[1], q_vG[0]) % (pi / 3) phi_G = pi / 6 - np.abs(theta_G) qmax_G = norm_c[0] / 2 / np.cos(phi_G) norm_G = np.sqrt(np.sum(q_vG**2, axis=0)) # Includes point on BZ boundary with +1e-2 mask_G = (norm_G <= qmax_G + 1e-2) # & (q_vG[1] < (norm_c[0] / 2 - 1e-3)) if components != 'normal': mask_G = ~mask_G # Reshape to grid shape mask_G.shape = shape for V1t_G in V1t_xG: # Fourier transform atomic gradient V1tq_G = fft.fftn(V1t_G) # Zero normal/umklapp components V1tq_G[mask_G] = 0.0 # Fourier transform back V1t_G[:] = fft.ifftn(V1tq_G).real def calculate_gradient(self): """Calculate gradient of effective potential and projector coefs. This function loads the generated pickle files and calculates finite-difference derivatives. """ # Array and dict for finite difference derivatives V1t_xG = [] dH1_xasp = [] x = 0 for a in self.indices: for v in range(3): name = '%s.%d%s' % (self.name, a, 'xyz'[v]) # Potential and atomic density matrix for atomic displacement try: Vtm_G, dHm_asp = pickle.load(open(name + '-.pckl')) Vtp_G, dHp_asp = pickle.load(open(name + '+.pckl')) except (IOError, EOFError): raise IOError('%s(-/+).pckl' % name) # FD derivatives in Hartree / Bohr V1t_G = (Vtp_G - Vtm_G) / (2 * self.delta / units.Bohr) V1t_xG.append(V1t_G) dH1_asp = {} for atom in dHm_asp.keys(): dH1_asp[atom] = (dHp_asp[atom] - dHm_asp[atom]) / \ (2 * self.delta / units.Bohr) dH1_xasp.append(dH1_asp) x += 1 return np.array(V1t_xG), dH1_xasp def calculate_dP_aqvMi(self, wfs): """Overlap between LCAO basis functions and gradient of projectors. Only the gradient wrt the atomic positions in the reference cell is computed. """ nao = wfs.setups.nao nq = len(wfs.ibzk_qc) atoms = [self.atoms[i] for i in self.indices] # Derivatives in reference cell dP_aqvMi = {} for atom, setup in zip(atoms, wfs.setups): a = atom.index dP_aqvMi[a] = np.zeros((nq, 3, nao, setup.ni), wfs.dtype) # Calculate overlap between basis function and gradient of projectors # NOTE: the derivative is calculated wrt the atomic position and not # the real-space coordinate calc = TwoCenterIntegralCalculator(wfs.ibzk_qc, derivative=True) expansions = ManySiteDictionaryWrapper(wfs.tci.P_expansions, dP_aqvMi) calc.calculate(wfs.tci.atompairs, [expansions], [dP_aqvMi]) # Extract derivatives in the reference unit cell # dP_aqvMi = {} # for atom in self.atoms: # dP_aqvMi[atom.index] = dPall_aqvMi[atom.index] return dP_aqvMi gpaw-0.11.0.13004/gpaw/elph/__init__.py0000664000175000017500000000000012553643470017441 0ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/grid_descriptor.py0000664000175000017500000005577212553643470020167 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. """Grid-descriptors This module contains a classes defining uniform 3D grids. For radial grid descriptors, look atom/radialgd.py. """ import numbers from math import pi import numpy as np import _gpaw import gpaw.mpi as mpi from gpaw.domain import Domain from gpaw.utilities import mlsqr from gpaw.utilities.blas import rk, r2k, gemv, gemm # Remove this: XXX assert (-1) % 3 == 2 assert (np.array([-1]) % 3)[0] == 2 NONBLOCKING = False class GridBoundsError(ValueError): pass class GridDescriptor(Domain): """Descriptor-class for uniform 3D grid A ``GridDescriptor`` object holds information on how functions, such as wave functions and electron densities, are discreticed in a certain domain in space. The main information here is how many grid points are used in each direction of the unit cell. There are methods for tasks such as allocating arrays, performing symmetry operations and integrating functions over space. All methods work correctly also when the domain is parallelized via domain decomposition. This is how a 2x2x2 3D array is laid out in memory:: 3-----7 |\ |\ | \ | \ | 1-----5 z 2--|--6 | y | \ | \ | \ | \| \| \| 0-----4 +-----x Example: >>> a = np.zeros((2, 2, 2)) >>> a.ravel()[:] = range(8) >>> a array([[[0, 1], [2, 3]], [[4, 5], [6, 7]]]) """ ndim = 3 # dimension of ndarrays def __init__(self, N_c, cell_cv=(1, 1, 1), pbc_c=True, comm=None, parsize=None): """Construct grid-descriptor object. parameters: N_c: 3 ints Number of grid points along axes. cell_cv: 3 float's or 3x3 floats Unit cell. pbc_c: one or three bools Periodic boundary conditions flag(s). comm: MPI-communicator Communicator for domain-decomposition. parsize: tuple of 3 ints, a single int or None Number of domains. Note that if pbc_c[c] is True, then the actual number of gridpoints along axis c is one less than N_c[c]. Attributes: ========== ======================================================== ``dv`` Volume per grid point. ``h_cv`` Array of the grid spacing along the three axes. ``N_c`` Array of the number of grid points along the three axes. ``n_c`` Number of grid points on this CPU. ``beg_c`` Beginning of grid-point indices (inclusive). ``end_c`` End of grid-point indices (exclusive). ``comm`` MPI-communicator for domain decomposition. ========== ======================================================== The length unit is Bohr. """ if isinstance(pbc_c, int): pbc_c = (pbc_c,) * 3 if comm is None: comm = mpi.world self.N_c = np.array(N_c, int) if (self.N_c != N_c).any(): raise ValueError('Non-int number of grid points %s' % N_c) Domain.__init__(self, cell_cv, pbc_c, comm, parsize, self.N_c) self.rank = self.comm.rank parsize_c = self.parsize_c n_c, remainder_c = divmod(self.N_c, parsize_c) self.beg_c = np.empty(3, int) self.end_c = np.empty(3, int) self.n_cp = [] for c in range(3): n_p = (np.arange(parsize_c[c] + 1) * float(self.N_c[c]) / parsize_c[c]) n_p = np.around(n_p + 0.4999).astype(int) if not self.pbc_c[c]: n_p[0] = 1 if not np.alltrue(n_p[1:] - n_p[:-1]): raise ValueError('Grid too small!') self.beg_c[c] = n_p[self.parpos_c[c]] self.end_c[c] = n_p[self.parpos_c[c] + 1] self.n_cp.append(n_p) self.n_c = self.end_c - self.beg_c self.h_cv = self.cell_cv / self.N_c[:, np.newaxis] self.volume = abs(np.linalg.det(self.cell_cv)) self.dv = self.volume / self.N_c.prod() self.orthogonal = not (self.cell_cv - np.diag(self.cell_cv.diagonal())).any() # Sanity check for grid spacings: h_c = self.get_grid_spacings() if max(h_c) / min(h_c) > 1.3: raise ValueError('Very anisotropic grid spacings: %s' % h_c) def new_descriptor(self, N_c=None, cell_cv=None, pbc_c=None, comm=None, parsize=None): """Create new descriptor based on this one. The new descriptor will use the same class (possibly a subclass) and all arguments will be equal to those of this descriptor unless new arguments are provided.""" if N_c is None: N_c = self.N_c if cell_cv is None: cell_cv = self.cell_cv if pbc_c is None: pbc_c = self.pbc_c if comm is None: comm = self.comm if parsize is None: parsize = self.parsize_c return self.__class__(N_c, cell_cv, pbc_c, comm, parsize) def get_grid_spacings(self): L_c = (np.linalg.inv(self.cell_cv)**2).sum(0)**-0.5 return L_c / self.N_c def get_size_of_global_array(self, pad=False): if pad: return self.N_c else: return self.N_c - 1 + self.pbc_c def flat_index(self, G_c): g1, g2, g3 = G_c - self.beg_c return g3 + self.n_c[2] * (g2 + g1 * self.n_c[1]) def get_slice(self): return [slice(b - 1 + p, e - 1 + p) for b, e, p in zip(self.beg_c, self.end_c, self.pbc_c)] def zeros(self, n=(), dtype=float, global_array=False, pad=False): """Return new zeroed 3D array for this domain. The type can be set with the ``dtype`` keyword (default: ``float``). Extra dimensions can be added with ``n=dim``. A global array spanning all domains can be allocated with ``global_array=True``.""" return self._new_array(n, dtype, True, global_array, pad) def empty(self, n=(), dtype=float, global_array=False, pad=False): """Return new uninitialized 3D array for this domain. The type can be set with the ``dtype`` keyword (default: ``float``). Extra dimensions can be added with ``n=dim``. A global array spanning all domains can be allocated with ``global_array=True``.""" return self._new_array(n, dtype, False, global_array, pad) def _new_array(self, n=(), dtype=float, zero=True, global_array=False, pad=False): if global_array: shape = self.get_size_of_global_array(pad) else: shape = self.n_c if isinstance(n, numbers.Integral): n = (n,) shape = n + tuple(shape) if zero: return np.zeros(shape, dtype) else: return np.empty(shape, dtype) def integrate(self, a_xg, b_yg=None, global_integral=True, hermitian=False, _transposed_result=None): """Integrate function(s) over domain. a_xg: ndarray Function(s) to be integrated. b_yg: ndarray If present, integrate a_xg.conj() * b_yg. global_integral: bool If the array(s) are distributed over several domains, then the total sum will be returned. To get the local contribution only, use global_integral=False. hermitian: bool Result is hermitian. _transposed_result: ndarray Long story. Don't use this unless you are a method of the MatrixOperator class ...""" xshape = a_xg.shape[:-3] if b_yg is None: # Only one array: result = a_xg.reshape(xshape + (-1,)).sum(axis=-1) * self.dv if global_integral: if result.ndim == 0: result = self.comm.sum(result) else: self.comm.sum(result) return result A_xg = np.ascontiguousarray(a_xg.reshape((-1,) + a_xg.shape[-3:])) B_yg = np.ascontiguousarray(b_yg.reshape((-1,) + b_yg.shape[-3:])) if _transposed_result is None: result_yx = np.zeros((len(B_yg), len(A_xg)), A_xg.dtype) else: result_yx = _transposed_result global_integral = False if a_xg is b_yg: rk(self.dv, A_xg, 0.0, result_yx) elif hermitian: r2k(0.5 * self.dv, A_xg, B_yg, 0.0, result_yx) else: gemm(self.dv, A_xg, B_yg, 0.0, result_yx, 'c') if global_integral: self.comm.sum(result_yx) yshape = b_yg.shape[:-3] result = result_yx.T.reshape(xshape + yshape) if result.ndim == 0: return result.item() else: return result def gemm(self, alpha, psit_nG, C_mn, beta, newpsit_mG): """Helper function for MatrixOperator class.""" gemm(alpha, psit_nG, C_mn, beta, newpsit_mG) def gemv(self, alpha, psit_nG, C_n, beta, newpsit_G, trans='t'): """Helper function for CG eigensolver.""" gemv(alpha, psit_nG, C_n, beta, newpsit_G, trans) def coarsen(self): """Return coarsened `GridDescriptor` object. Reurned descriptor has 2x2x2 fewer grid points.""" if np.sometrue(self.N_c % 2): raise ValueError('Grid %s not divisible by 2!' % self.N_c) return self.new_descriptor(self.N_c // 2) def refine(self): """Return refined `GridDescriptor` object. Returned descriptor has 2x2x2 more grid points.""" return self.new_descriptor(self.N_c * 2) def get_boxes(self, spos_c, rcut, cut=True): """Find boxes enclosing sphere.""" N_c = self.N_c ncut = rcut * (self.icell_cv**2).sum(axis=1)**0.5 * self.N_c npos_c = spos_c * N_c beg_c = np.ceil(npos_c - ncut).astype(int) end_c = np.ceil(npos_c + ncut).astype(int) if cut: for c in range(3): if not self.pbc_c[c]: if beg_c[c] < 0: beg_c[c] = 0 if end_c[c] > N_c[c]: end_c[c] = N_c[c] else: for c in range(3): if (not self.pbc_c[c] and (beg_c[c] < 0 or end_c[c] > N_c[c])): msg = ('Box at %.3f %.3f %.3f crosses boundary. ' 'Beg. of box %s, end of box %s, max box size %s' % (tuple(spos_c) + (beg_c, end_c, self.N_c))) raise GridBoundsError(msg) range_c = ([], [], []) for c in range(3): b = beg_c[c] e = b while e < end_c[c]: b0 = b % N_c[c] e = min(end_c[c], b + N_c[c] - b0) if b0 < self.beg_c[c]: b1 = b + self.beg_c[c] - b0 else: b1 = b e0 = b0 - b + e if e0 > self.end_c[c]: e1 = e - (e0 - self.end_c[c]) else: e1 = e if e1 > b1: range_c[c].append((b1, e1)) b = e boxes = [] for b0, e0 in range_c[0]: for b1, e1 in range_c[1]: for b2, e2 in range_c[2]: b = np.array((b0, b1, b2)) e = np.array((e0, e1, e2)) beg_c = np.array((b0 % N_c[0], b1 % N_c[1], b2 % N_c[2])) end_c = beg_c + e - b disp = (b - beg_c) / N_c beg_c = np.maximum(beg_c, self.beg_c) end_c = np.minimum(end_c, self.end_c) if (beg_c[0] < end_c[0] and beg_c[1] < end_c[1] and beg_c[2] < end_c[2]): boxes.append((beg_c, end_c, disp)) return boxes def get_nearest_grid_point(self, spos_c, force_to_this_domain=False): """Return index of nearest grid point. The nearest grid point can be on a different CPU than the one the nucleus belongs to (i.e. return can be negative, or larger than gd.end_c), in which case something clever should be done. The point can be forced to the grid descriptors domain to be consistent with self.get_rank_from_position(spos_c). """ g_c = np.around(self.N_c * spos_c).astype(int) if force_to_this_domain: for c in range(3): g_c[c] = max(g_c[c], self.beg_c[c]) g_c[c] = min(g_c[c], self.end_c[c] - 1) return g_c - self.beg_c def plane_wave(self, k_c): """Evaluate plane wave on grid. Returns:: _ _ ik.r e , where the wave vector is given by k_c (in units of reciprocal lattice vectors).""" N_c = self.N_c return np.exp(2j * pi * np.dot(np.indices(N_c).T, k_c / N_c).T) def symmetrize(self, a_g, op_scc, ft_sc=None): if len(op_scc) == 1: return if ft_sc is not None and not ft_sc.any(): ft_sc = None A_g = self.collect(a_g) if self.comm.rank == 0: B_g = np.zeros_like(A_g) for s, op_cc in enumerate(op_scc): if ft_sc is None: _gpaw.symmetrize(A_g, B_g, op_cc) else: _gpaw.symmetrize_ft(A_g, B_g, op_cc, ft_sc[s]) else: B_g = None self.distribute(B_g, a_g) a_g /= len(op_scc) def collect(self, a_xg, broadcast=False): """Collect distributed array to master-CPU or all CPU's.""" if self.comm.size == 1: return a_xg xshape = a_xg.shape[:-3] # Collect all arrays on the master: if self.rank != 0: # There can be several sends before the corresponding receives # are posted, so use syncronous send here self.comm.ssend(a_xg, 0, 301) if broadcast: A_xg = self.empty(xshape, a_xg.dtype, global_array=True) self.comm.broadcast(A_xg, 0) return A_xg else: return None # Put the subdomains from the slaves into the big array # for the whole domain: A_xg = self.empty(xshape, a_xg.dtype, global_array=True) parsize_c = self.parsize_c r = 0 for n0 in range(parsize_c[0]): b0, e0 = self.n_cp[0][n0:n0 + 2] - self.beg_c[0] for n1 in range(parsize_c[1]): b1, e1 = self.n_cp[1][n1:n1 + 2] - self.beg_c[1] for n2 in range(parsize_c[2]): b2, e2 = self.n_cp[2][n2:n2 + 2] - self.beg_c[2] if r != 0: a_xg = np.empty(xshape + ((e0 - b0), (e1 - b1), (e2 - b2)), a_xg.dtype.char) self.comm.receive(a_xg, r, 301) A_xg[..., b0:e0, b1:e1, b2:e2] = a_xg r += 1 if broadcast: self.comm.broadcast(A_xg, 0) return A_xg def distribute(self, B_xg, b_xg): """Distribute full array B_xg to subdomains, result in b_xg. B_xg is not used by the slaves (i.e. it should be None on all slaves) b_xg must be allocated on all nodes and will be overwritten. """ if self.comm.size == 1: b_xg[:] = B_xg return if self.rank != 0: self.comm.receive(b_xg, 0, 42) return else: parsize_c = self.parsize_c requests = [] r = 0 for n0 in range(parsize_c[0]): b0, e0 = self.n_cp[0][n0:n0 + 2] - self.beg_c[0] for n1 in range(parsize_c[1]): b1, e1 = self.n_cp[1][n1:n1 + 2] - self.beg_c[1] for n2 in range(parsize_c[2]): b2, e2 = self.n_cp[2][n2:n2 + 2] - self.beg_c[2] if r != 0: a_xg = B_xg[..., b0:e0, b1:e1, b2:e2].copy() request = self.comm.send(a_xg, r, 42, NONBLOCKING) # Remember to store a reference to the # send buffer (a_xg) so that is isn't # deallocated: requests.append((request, a_xg)) else: b_xg[:] = B_xg[..., b0:e0, b1:e1, b2:e2] r += 1 for request, a_xg in requests: self.comm.wait(request) def zero_pad(self, a_xg): """Pad array with zeros as first element along non-periodic directions. Should only be invoked on global arrays. """ assert np.all(a_xg.shape[-3:] == (self.N_c + self.pbc_c - 1)) if self.pbc_c.all(): return a_xg npbx, npby, npbz = 1 - self.pbc_c b_xg = np.zeros(a_xg.shape[:-3] + tuple(self.N_c), dtype=a_xg.dtype) b_xg[..., npbx:, npby:, npbz:] = a_xg return b_xg def calculate_dipole_moment(self, rho_g): """Calculate dipole moment of density.""" rho_01 = rho_g.sum(axis=2) rho_02 = rho_g.sum(axis=1) rho_cg = [rho_01.sum(axis=1), rho_01.sum(axis=0), rho_02.sum(axis=0)] rhog_c = [np.dot(np.arange(self.beg_c[c], self.end_c[c]), rho_cg[c]) for c in range(3)] d_c = -np.dot(rhog_c, self.h_cv) * self.dv self.comm.sum(d_c) return d_c def wannier_matrix(self, psit_nG, psit_nG1, G_c, nbands=None): """Wannier localization integrals The soft part of Z is given by (Eq. 27 ref1):: ~ ~ -i G.r ~ Z = nm n m psit_nG and psit_nG1 are the set of wave functions for the two different spin/kpoints in question. ref1: Thygesen et al, Phys. Rev. B 72, 125119 (2005) """ if nbands is None: nbands = len(psit_nG) if nbands == 0: return np.zeros((0, 0), complex) e_G = np.exp(-2j * pi * np.dot(np.indices(self.n_c).T + self.beg_c, G_c / self.N_c).T) a_nG = (e_G * psit_nG[:nbands].conj()).reshape((nbands, -1)) return np.inner(a_nG, psit_nG1[:nbands].reshape((nbands, -1))) * self.dv def find_center(self, a_R): """Calculate center of positive function.""" assert self.orthogonal r_vR = self.get_grid_point_coordinates() a_R = a_R.astype(complex) center = [] for L, r_R in zip(self.cell_cv.diagonal(), r_vR): z = self.integrate(a_R, np.exp(2j * pi / L * r_R)) center.append(np.angle(z) / (2 * pi) * L % L) return np.array(center) def bytecount(self, dtype=float): """Get the number of bytes used by a grid of specified dtype.""" return int(np.prod(self.n_c)) * np.array(1, dtype).itemsize def get_grid_point_coordinates(self, dtype=float, global_array=False): """Construct cartesian coordinates of grid points in the domain.""" r_vG = np.dot(np.indices(self.n_c, dtype).T + self.beg_c, self.h_cv).T.copy() if global_array: return self.collect(r_vG, broadcast=True) # XXX waste! else: return r_vG def get_grid_point_distance_vectors(self, r_v, mic=True, dtype=float): """Return distances to a given vector in the domain. mic: if true adopts the mininimum image convention procedure by W. Smith in 'The Minimum image convention in Non-Cubic MD cells' March 29, 1989 """ s_Gc = (np.indices(self.n_c, dtype).T + self.beg_c) / self.N_c cell_cv = self.N_c * self.h_cv s_Gc -= np.linalg.solve(cell_cv.T, r_v) if mic: # XXX do the correction twice works better s_Gc -= self.pbc_c * (2 * s_Gc).astype(int) s_Gc -= self.pbc_c * (2 * s_Gc).astype(int) # sanity check assert((s_Gc * self.pbc_c >= -0.5).all()) assert((s_Gc * self.pbc_c <= 0.5).all()) return np.dot(s_Gc, cell_cv).T.copy() def interpolate_grid_points(self, spos_nc, vt_g, target_n, use_mlsqr=True): """Return interpolated values. Calculate interpolated values from array vt_g based on the scaled coordinates on spos_c. Uses moving least squares algorithm by default, or otherwise trilinear interpolation. This doesn't work in parallel, since it would require communication between neighbouring grid. """ assert mpi.world.size == 1 if use_mlsqr: mlsqr(3, 2.3, spos_nc, self.N_c, self.beg_c, vt_g, target_n) else: for n, spos_c in enumerate(spos_nc): g_c = self.N_c * spos_c - self.beg_c # The begin and end of the array slice bg_c = np.floor(g_c).astype(int) Bg_c = np.ceil(g_c).astype(int) # The coordinate within the box (bottom left = 0, # top right = h_c) dg_c = g_c - bg_c Bg_c %= self.N_c target_n[n] = ( vt_g[bg_c[0], bg_c[1], bg_c[2]] * (1.0 - dg_c[0]) * (1.0 - dg_c[1]) * (1.0 - dg_c[2]) + vt_g[Bg_c[0], bg_c[1], bg_c[2]] * (0.0 + dg_c[0]) * (1.0 - dg_c[1]) * (1.0 - dg_c[2]) + vt_g[bg_c[0], Bg_c[1], bg_c[2]] * (1.0 - dg_c[0]) * (0.0 + dg_c[1]) * (1.0 - dg_c[2]) + vt_g[Bg_c[0], Bg_c[1], bg_c[2]] * (0.0 + dg_c[0]) * (0.0 + dg_c[1]) * (1.0 - dg_c[2]) + vt_g[bg_c[0], bg_c[1], Bg_c[2]] * (1.0 - dg_c[0]) * (1.0 - dg_c[1]) * (0.0 + dg_c[2]) + vt_g[Bg_c[0], bg_c[1], Bg_c[2]] * (0.0 + dg_c[0]) * (1.0 - dg_c[1]) * (0.0 + dg_c[2]) + vt_g[bg_c[0], Bg_c[1], Bg_c[2]] * (1.0 - dg_c[0]) * (0.0 + dg_c[1]) * (0.0 + dg_c[2]) + vt_g[Bg_c[0], Bg_c[1], Bg_c[2]] * (0.0 + dg_c[0]) * (0.0 + dg_c[1]) * (0.0 + dg_c[2])) def __eq__(self, other): return (self.dv == other.dv and (self.h_cv == other.h_cv).all() and (self.N_c == other.N_c).all() and (self.n_c == other.n_c).all() and (self.beg_c == other.beg_c).all() and (self.end_c == other.end_c).all()) gpaw-0.11.0.13004/gpaw/response/0000775000175000017500000000000012553644063016247 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/response/df.py0000664000175000017500000006704612553643470017230 0ustar jensjjensj00000000000000from __future__ import print_function import os import sys import pickle from math import pi import numpy as np from ase.units import Hartree, Bohr import gpaw.mpi as mpi from gpaw.response.chi0 import Chi0 from gpaw.response.kernel2 import calculate_Kxc, truncated_coulomb from gpaw.response.wstc import WignerSeitzTruncatedCoulomb class DielectricFunction: """This class defines dielectric function related physical quantities.""" def __init__(self, calc, name=None, frequencies=None, domega0=0.1, omega2=10.0, omegamax=None, ecut=50, hilbert=True, nbands=None, eta=0.2, ftol=1e-6, threshold=1, intraband=True, nblocks=1, world=mpi.world, txt=sys.stdout, gate_voltage=None, truncation=None, disable_point_group=False, disable_time_reversal=False, use_more_memory=1, unsymmetrized=True): """Creates a DielectricFunction object. calc: str The groundstate calculation file that the linear response calculation is based on. name: str If defined, save the density-density response function to:: name + '%+d%+d%+d.pckl' % tuple((q_c * kd.N_c).round()) where q_c is the reduced momentum and N_c is the number of kpoints along each direction. frequencies: np.ndarray Specification of frequency grid. If not set the non-linear frequency grid is used. domega0: float Frequency grid spacing for non-linear frequency grid at omega = 0. omega2: float Frequency at which the non-linear frequency grid has doubled the spacing. omegamax: float The upper frequency bound for the non-linear frequency grid. ecut: float Plane-wave cut-off. hilbert: bool Use hilbert transform. nbands: int Number of bands from calc. eta: float Broadening parameter. ftol: float Threshold for including close to equally occupied orbitals, f_ik - f_jk > ftol. threshold: float Threshold for matrix elements in optical response perturbation theory. intraband: bool Include intraband transitions. world: comm mpi communicator. nblocks: int Split matrices in nblocks blocks and distribute them G-vectors or frequencies over processes. txt: str Output file. gate_voltage: float Shift Fermi level of ground state calculation by the specified amount. truncation: str 'wigner-seitz' for Wigner Seitz truncated Coulomb '2D' for regular truncation in the z-direction """ self.chi0 = Chi0(calc, frequencies, domega0=domega0, omega2=omega2, omegamax=omegamax, ecut=ecut, hilbert=hilbert, nbands=nbands, eta=eta, ftol=ftol, threshold=threshold, intraband=intraband, world=world, nblocks=nblocks, txt=txt, gate_voltage=gate_voltage, disable_point_group=disable_point_group, disable_time_reversal=disable_time_reversal, use_more_memory=use_more_memory, unsymmetrized=unsymmetrized) self.name = name self.omega_w = self.chi0.omega_w nw = len(self.omega_w) world = self.chi0.world self.mynw = (nw + world.size - 1) // world.size self.w1 = min(self.mynw * world.rank, nw) self.w2 = min(self.w1 + self.mynw, nw) self.truncation = truncation def calculate_chi0(self, q_c): """Calculates the density response function. Calculate the density response function for a specific momentum. q_c: [float, float, float] The momentum wavevector. """ if self.name: kd = self.chi0.calc.wfs.kd name = self.name + '%+d%+d%+d.pckl' % tuple((q_c * kd.N_c).round()) if os.path.isfile(name): return self.read(name) pd, chi0_wGG, chi0_wxvG, chi0_wvv = self.chi0.calculate(q_c) chi0_wGG = self.chi0.distribute_frequencies(chi0_wGG) self.chi0.timer.write(self.chi0.fd) if self.name: self.write(name, pd, chi0_wGG, chi0_wxvG, chi0_wvv) return pd, chi0_wGG, chi0_wxvG, chi0_wvv def write(self, name, pd, chi0_wGG, chi0_wxvG, chi0_wvv): nw = len(self.omega_w) nG = pd.ngmax world = self.chi0.world if world.rank == 0: fd = open(name, 'wb') pickle.dump((self.omega_w, pd, None, chi0_wxvG, chi0_wvv), fd, pickle.HIGHEST_PROTOCOL) for chi0_GG in chi0_wGG: pickle.dump(chi0_GG, fd, pickle.HIGHEST_PROTOCOL) tmp_wGG = np.empty((self.mynw, nG, nG), complex) w1 = self.mynw for rank in range(1, world.size): w2 = min(w1 + self.mynw, nw) world.receive(tmp_wGG[:w2 - w1], rank) for w in range(w2 - w1): pickle.dump(tmp_wGG[w], fd, pickle.HIGHEST_PROTOCOL) w1 = w2 fd.close() else: world.send(chi0_wGG, 0) def read(self, name): print('Reading from', name, file=self.chi0.fd) fd = open(name, 'rb') omega_w, pd, chi0_wGG, chi0_wxvG, chi0_wvv = pickle.load(fd) assert np.allclose(omega_w, self.omega_w) world = self.chi0.world nw = len(omega_w) nG = pd.ngmax if chi0_wGG is not None: # Old file format: chi0_wGG = chi0_wGG[self.w1:self.w2].copy() else: if world.rank == 0: chi0_wGG = np.empty((self.mynw, nG, nG), complex) for chi0_GG in chi0_wGG: chi0_GG[:] = pickle.load(fd) tmp_wGG = np.empty((self.mynw, nG, nG), complex) w1 = self.mynw for rank in range(1, world.size): w2 = min(w1 + self.mynw, nw) for w in range(w2 - w1): tmp_wGG[w] = pickle.load(fd) world.send(tmp_wGG[:w2 - w1], rank) w1 = w2 else: chi0_wGG = np.empty((self.w2 - self.w1, nG, nG), complex) world.receive(chi0_wGG, 0) return pd, chi0_wGG, chi0_wxvG, chi0_wvv def collect(self, a_w): world = self.chi0.world b_w = np.zeros(self.mynw, a_w.dtype) b_w[:self.w2 - self.w1] = a_w nw = len(self.omega_w) A_w = np.empty(world.size * self.mynw, a_w.dtype) world.all_gather(b_w, A_w) return A_w[:nw] def get_frequencies(self): """Return frequencies that Chi is evaluated on""" return self.omega_w * Hartree def get_chi(self, xc='RPA', q_c=[0, 0, 0], direction='x'): """ Returns v^1/2 chi V^1/2""" pd, chi0_wGG, chi0_wxvG, chi0_wvv = self.calculate_chi0(q_c) G_G = pd.G2_qG[0]**0.5 nG = len(G_G) if pd.kd.gamma: G_G[0] = 1.0 if isinstance(direction, str): d_v = {'x': [1, 0, 0], 'y': [0, 1, 0], 'z': [0, 0, 1]}[direction] else: d_v = direction d_v = np.asarray(d_v) / np.linalg.norm(d_v) W = slice(self.w1, self.w2) chi0_wGG[:, 0] = np.dot(d_v, chi0_wxvG[W, 0]) chi0_wGG[:, :, 0] = np.dot(d_v, chi0_wxvG[W, 1]) chi0_wGG[:, 0, 0] = np.dot(d_v, np.dot(chi0_wvv[W], d_v).T) G_G /= (4 * pi)**0.5 if self.truncation == 'wigner-seitz': kernel = WignerSeitzTruncatedCoulomb(pd.gd.cell_cv, self.chi0.calc.wfs.kd.N_c) K_G = kernel.get_potential(pd) K_G *= G_G**2 if pd.kd.gamma: K_G[0] = 0.0 elif self.truncation == '2D': K_G = truncated_coulomb(pd) K_G *= G_G**2 if pd.kd.gamma: K_G[0] = 0.0 else: K_G = np.ones(nG) K_GG = np.zeros((nG, nG), dtype=complex) for i in range(nG): K_GG[i, i] = K_G[i] if xc != 'RPA': R_av = self.chi0.calc.atoms.positions / Bohr nt_sG = self.chi0.calc.density.nt_sG Kxc_sGG = calculate_Kxc(pd, nt_sG, R_av, self.chi0.calc.wfs.setups, self.chi0.calc.density.D_asp, functional=xc) K_GG += Kxc_sGG[0] * G_G * G_G[:, np.newaxis] chi_wGG = [] for chi0_GG in chi0_wGG: chi0_GG[:] = chi0_GG / G_G / G_G[:, np.newaxis] chi_wGG.append(np.dot(np.linalg.inv(np.eye(nG) - np.dot(chi0_GG, K_GG)), chi0_GG)) return chi0_wGG, np.array(chi_wGG) def get_dielectric_matrix(self, xc='RPA', q_c=[0, 0, 0], direction='x', symmetric=True, calculate_chi=False, q0=None, add_intraband=True): """Returns the symmetrized dielectric matrix. :: \tilde\epsilon_GG' = v^{-1/2}_G \epsilon_GG' v^{1/2}_G', where:: epsilon_GG' = 1 - v_G * P_GG' and P_GG' is the polarization. :: In RPA: P = chi^0 In TDDFT: P = (1 - chi^0 * f_xc)^{-1} chi^0 The head of the inverse symmetrized dielectric matrix is equal to the head of the inverse dielectric matrix (inverse dielectric function) """ pd, chi0_wGG, chi0_wxvG, chi0_wvv = self.calculate_chi0(q_c) G_G = pd.G2_qG[0]**0.5 nG = len(G_G) if pd.kd.gamma: G_G[0] = 1.0 if isinstance(direction, str): d_v = {'x': [1, 0, 0], 'y': [0, 1, 0], 'z': [0, 0, 1]}[direction] else: d_v = direction d_v = np.asarray(d_v) / np.linalg.norm(d_v) W = slice(self.w1, self.w2) if add_intraband: chi0_wGG[:, 0] = np.dot(d_v, chi0_wxvG[W, 0]) chi0_wGG[:, :, 0] = np.dot(d_v, chi0_wxvG[W, 1]) chi0_wGG[:, 0, 0] = np.dot(d_v, np.dot(chi0_wvv[W], d_v).T) if q0 is not None: print('Restoring q dependence of head and wings of chi0') chi0_wGG[:, 1:, 0] *= q0 chi0_wGG[:, 0, 1:] *= q0 chi0_wGG[:, 0, 0] *= q0**2 G_G[0] = q0 if self.truncation == 'wigner-seitz': kernel = WignerSeitzTruncatedCoulomb(pd.gd.cell_cv, self.chi0.calc.wfs.kd.N_c) K_G = kernel.get_potential(pd)**0.5 if pd.kd.gamma: K_G[0] = 0.0 elif self.truncation == '2D': K_G = truncated_coulomb(pd, q0=q0) if pd.kd.gamma and q0 is None: K_G[0] = 0.0 else: K_G = (4 * pi)**0.5 / G_G if xc != 'RPA': R_av = self.chi0.calc.atoms.positions / Bohr nt_sG = self.chi0.calc.density.nt_sG Kxc_sGG = calculate_Kxc(pd, nt_sG, R_av, self.chi0.calc.wfs.setups, self.chi0.calc.density.D_asp, functional=xc) if calculate_chi: chi_wGG = [] for chi0_GG in chi0_wGG: if xc == 'RPA': P_GG = chi0_GG else: P_GG = np.dot(np.linalg.inv(np.eye(nG) - np.dot(chi0_GG, Kxc_sGG[0])), chi0_GG) if symmetric: e_GG = np.eye(nG) - P_GG * K_G * K_G[:, np.newaxis] else: K_GG = (K_G**2 * np.ones([nG, nG])).T e_GG = np.eye(nG) - P_GG * K_GG if calculate_chi: K_GG = np.diag(K_G**2) if xc != 'RPA': K_GG += Kxc_sGG[0] chi_wGG.append(np.dot(np.linalg.inv(np.eye(nG) - np.dot(chi0_GG, K_GG)), chi0_GG)) chi0_GG[:] = e_GG # chi0_wGG is now the dielectric matrix if not calculate_chi: return chi0_wGG else: # chi_wGG is the full density response function.. return pd, chi0_wGG, np.array(chi_wGG) def get_dielectric_function(self, xc='RPA', q_c=[0, 0, 0], direction='x', filename='df.csv'): """Calculate the dielectric function. Returns dielectric function without and with local field correction: df_NLFC_w, df_LFC_w = DielectricFunction.get_dielectric_function() """ e_wGG = self.get_dielectric_matrix(xc, q_c, direction) df_NLFC_w = np.zeros(len(e_wGG), dtype=complex) df_LFC_w = np.zeros(len(e_wGG), dtype=complex) for w, e_GG in enumerate(e_wGG): df_NLFC_w[w] = e_GG[0, 0] df_LFC_w[w] = 1 / np.linalg.inv(e_GG)[0, 0] df_NLFC_w = self.collect(df_NLFC_w) df_LFC_w = self.collect(df_LFC_w) if filename is not None and mpi.rank == 0: with open(filename, 'w') as fd: for omega, nlfc, lfc in zip(self.omega_w * Hartree, df_NLFC_w, df_LFC_w): print('%.6f, %.6f, %.6f, %.6f, %.6f' % (omega, nlfc.real, nlfc.imag, lfc.real, lfc.imag), file=fd) return df_NLFC_w, df_LFC_w def get_macroscopic_dielectric_constant(self, xc='RPA', direction='x'): """Calculate macroscopic dielectric constant. Returns eM_NLFC and eM_LFC. Macroscopic dielectric constant is defined as the real part of dielectric function at w=0. Parameters: eM_LFC: float Dielectric constant without local field correction. (RPA, ALDA) eM2_NLFC: float Dielectric constant with local field correction. """ fd = self.chi0.fd print('', file=fd) print('%s Macroscopic Dielectric Constant:' % xc, file=fd) df_NLFC_w, df_LFC_w = self.get_dielectric_function( xc=xc, filename=None, direction=direction) eps0 = np.real(df_NLFC_w[0]) eps = np.real(df_LFC_w[0]) print(' %s direction' % direction, file=fd) print(' Without local field: %f' % eps0, file=fd) print(' Include local field: %f' % eps, file=fd) return eps0, eps def get_eels_spectrum(self, xc='RPA', q_c=[0, 0, 0], direction='x', filename='eels.csv'): """Calculate EELS spectrum. By default, generate a file 'eels.csv'. EELS spectrum is obtained from the imaginary part of the inverse of dielectric function. Returns EELS spectrum without and with local field corrections: df_NLFC_w, df_LFC_w = DielectricFunction.get_eels_spectrum() """ # Calculate dielectric function df_NLFC_w, df_LFC_w = self.get_dielectric_function( xc=xc, q_c=q_c, direction=direction, filename=None) Nw = df_NLFC_w.shape[0] # Calculate eels eels_NLFC_w = -(1 / df_NLFC_w).imag eels_LFC_w = -(1 / df_LFC_w).imag # Write to file if filename is not None and mpi.rank == 0: fd = open(filename, 'w') print('# energy, eels_NLFC_w, eels_LFC_w', file=fd) for iw in range(Nw): print('%.6f, %.6f, %.6f' % (self.chi0.omega_w[iw] * Hartree, eels_NLFC_w[iw], eels_LFC_w[iw]), file=fd) fd.close() return eels_NLFC_w, eels_LFC_w def get_polarizability(self, xc='RPA', direction='x', filename='polarizability.csv', pbc=None): """Calculate the polarizability alpha. In 3D the imaginary part of the polarizability is related to the dielectric function by Im(eps_M) = 4 pi * Im(alpha). In systems with reduced dimensionality the converged value of alpha is independent of the cell volume. This is not the case for eps_M, which is ill defined. A truncated Coulomb kernel will always give eps_M = 1.0, whereas the polarizability maintains its structure. By default, generate a file 'polarizability.csv'. The five colomns are: frequency (eV), Real(alpha0), Imag(alpha0), Real(alpha), Imag(alpha) alpha0 is the result without local field effects and the dimension of alpha is \AA to the power of non-periodic directions """ cell_cv = self.chi0.calc.wfs.gd.cell_cv if not pbc: pbc_c = self.chi0.calc.atoms.pbc else: pbc_c = np.array(pbc) if pbc_c.all(): V = 1.0 else: V = np.abs(np.linalg.det(cell_cv[~pbc_c][:, ~pbc_c])) if not self.truncation: # Without truncation alpha is simply related to eps_M df0_w, df_w = self.get_dielectric_function(xc=xc, q_c=[0, 0, 0], filename=None, direction=direction) alpha_w = V * (df_w - 1.0) / (4 * pi) alpha0_w = V * (df0_w - 1.0) / (4 * pi) else: # With truncation we need to calculate \chit = v^0.5*chi*v^0.5 print('Using truncated Coulomb interaction', file=self.chi0.fd) chi0_wGG, chi_wGG = self.get_chi(xc=xc, direction=direction) alpha_w = -V * (chi_wGG[:, 0, 0]) / (4 * pi) alpha0_w = -V * (chi0_wGG[:, 0, 0]) / (4 * pi) alpha_w = self.collect(alpha_w) alpha0_w = self.collect(alpha0_w) Nw = len(alpha_w) if filename is not None and mpi.rank == 0: fd = open(filename, 'w') for iw in range(Nw): print('%.6f, %.6f, %.6f, %.6f, %.6f' % (self.chi0.omega_w[iw] * Hartree, alpha0_w[iw].real * Bohr**(sum(~pbc_c)), alpha0_w[iw].imag * Bohr**(sum(~pbc_c)), alpha_w[iw].real * Bohr**(sum(~pbc_c)), alpha_w[iw].imag * Bohr**(sum(~pbc_c))), file=fd) fd.close() return alpha0_w * Bohr**(sum(~pbc_c)), alpha_w * Bohr**(sum(~pbc_c)) def check_sum_rule(self, spectrum=None): """Check f-sum rule. It takes the y of a spectrum as an entry and it check its integral. spectrum: np.ndarray Input spectrum """ assert (self.omega_w[1:] - self.omega_w[:-1]).ptp() < 1e-10 fd = self.chi0.fd if spectrum is None: raise ValueError('No spectrum input ') dw = self.chi0.omega_w[1] - self.chi0.omega_w[0] N1 = 0 for iw in range(len(spectrum)): w = iw * dw N1 += spectrum[iw] * w N1 *= dw * self.chi0.vol / (2 * pi**2) print('', file=fd) print('Sum rule:', file=fd) nv = self.chi0.calc.wfs.nvalence print('N1 = %f, %f %% error' % (N1, (N1 - nv) / nv * 100), file=fd) def get_eigenmodes(self, q_c=[0, 0, 0], w_max=None, name=None, eigenvalue_only=False, direction='x', checkphase=True): """Plasmon eigenmodes as eigenvectors of the dielectric matrix.""" assert self.chi0.world.size == 1 pd, chi0_wGG, chi0_wxvG, chi0_wvv = self.calculate_chi0(q_c) e_wGG = self.get_dielectric_matrix(xc='RPA', q_c=q_c, direction=direction, symmetric=False) kd = pd.kd # Get real space grid for plasmon modes: r = pd.gd.get_grid_point_coordinates() w_w = self.omega_w * Hartree if w_max: w_w = w_w[np.where(w_w < w_max)] Nw = len(w_w) nG = e_wGG.shape[1] eig = np.zeros([Nw, nG], dtype=complex) eig_all = np.zeros([Nw, nG], dtype=complex) # Find eigenvalues and eigenvectors: e_GG = e_wGG[0] eig_all[0], vec = np.linalg.eig(e_GG) eig[0] = eig_all[0] vec_dual = np.linalg.inv(vec) omega0 = np.array([]) eigen0 = np.array([], dtype=complex) v_ind = np.zeros([0, r.shape[1], r.shape[2], r.shape[3]], dtype=complex) n_ind = np.zeros([0, r.shape[1], r.shape[2], r.shape[3]], dtype=complex) # Loop to find the eigenvalues that crosses zero # from negative to positive values: for i in np.array(range(1, Nw)): e_GG = e_wGG[i] # epsilon_GG'(omega + d-omega) eig_all[i], vec_p = np.linalg.eig(e_GG) if eigenvalue_only: continue vec_dual_p = np.linalg.inv(vec_p) overlap = np.abs(np.dot(vec_dual, vec_p)) index = list(np.argsort(overlap)[:, -1]) if len(np.unique(index)) < nG: # add missing indices addlist = [] removelist = [] for j in range(nG): if index.count(j) < 1: addlist.append(j) if index.count(j) > 1: for l in range(1, index.count(j)): removelist.append( np.argwhere(np.array(index) == j)[l]) for j in range(len(addlist)): index[removelist[j]] = addlist[j] vec = vec_p[:, index] vec_dual = vec_dual_p[index, :] eig[i] = eig_all[i, index] for k in [k for k in range(nG) # Eigenvalue crossing: if (eig[i - 1, k] < 0 and eig[i, k] > 0)]: a = np.real((eig[i, k] - eig[i - 1, k]) / (w_w[i] - w_w[i - 1])) # linear interp for crossing point w0 = np.real(-eig[i - 1, k]) / a + w_w[i - 1] eig0 = a * (w0 - w_w[i - 1]) + eig[i - 1, k] print('crossing found at w = %1.2f eV' % w0) omega0 = np.append(omega0, w0) eigen0 = np.append(eigen0, eig0) # Fourier Transform: qG = pd.get_reciprocal_vectors(add_q=True) coef_G = np.diagonal(np.inner(qG, qG)) / (4 * pi) qGr_R = np.inner(qG, r.T).T factor = np.exp(1j * qGr_R) v_temp = np.dot(factor, vec[:, k]) n_temp = np.dot(factor, vec[:, k] * coef_G) if checkphase: # rotate eigenvectors in complex plane integral = np.zeros([81]) phases = np.linspace(0, 2, 81) for ip in range(81): v_int = v_temp * np.exp(1j * pi * phases[ip]) integral[ip] = abs(np.imag(v_int)).sum() phase = phases[np.argsort(integral)][0] v_temp *= np.exp(1j * pi * phase) n_temp *= np.exp(1j * pi * phase) v_ind = np.append(v_ind, v_temp[np.newaxis, :], axis=0) n_ind = np.append(n_ind, n_temp[np.newaxis, :], axis=0) kd = self.chi0.calc.wfs.kd if name is None and self.name: name = (self.name + '%+d%+d%+d-eigenmodes.pckl' % tuple((q_c * kd.N_c).round())) elif name: name = (name + '%+d%+d%+d-eigenmodes.pckl' % tuple((q_c * kd.N_c).round())) else: name = '%+d%+d%+d-eigenmodes.pckl' % tuple((q_c * kd.N_c).round()) # Returns: real space grid, frequency grid, # sorted eigenvalues, zero-crossing frequencies + eigenvalues, # induced potential + density in real space. if eigenvalue_only: pickle.dump((r * Bohr, w_w, eig), open(name, 'wb'), pickle.HIGHEST_PROTOCOL) return r * Bohr, w_w, eig else: pickle.dump((r * Bohr, w_w, eig, omega0, eigen0, v_ind, n_ind), open(name, 'wb'), pickle.HIGHEST_PROTOCOL) return r * Bohr, w_w, eig, omega0, eigen0, v_ind, n_ind def get_spatial_eels(self, q_c=[0, 0, 0], direction='x', w_max=None, filename='eels'): """Spatially resolved loss spectrum. The spatially resolved loss spectrum is calculated as the inverse fourier transform of ``VChiV = (eps^{-1}-I)V``:: EELS(w,r) = - Im [sum_{G,G'} e^{iGr} Vchi_{GG'}(w) V_G'e^{-iG'r}] \delta(w-G\dot v_e ) Input parameters: direction: 'x', 'y', or 'z' The direction for scanning acroos the structure (perpendicular to the electron beam) . w_max: float maximum frequency filename: str name of output Returns: real space grid, frequency points, EELS(w,r) """ assert self.chi0.world.size == 1 pd, chi0_wGG, chi0_wxvG, chi0_wvv = self.calculate_chi0(q_c) e_wGG = self.get_dielectric_matrix(xc='RPA', q_c=q_c, symmetric=False) r = pd.gd.get_grid_point_coordinates() ix = r.shape[1] / 2 iy = r.shape[2] / 2 iz = r.shape[3] / 2 if direction == 'x': r = r[:, :, iy, iz] perpdir = [1, 2] if direction == 'y': r = r[:, ix, :, iz] perpdir = [0, 2] if direction == 'z': r = r[:, ix, iy, :] perpdir = [0, 1] nG = e_wGG.shape[1] Gvec = pd.G_Qv[pd.Q_qG[0]] Glist = [] # Only use G-vectors that are zero along electron beam # due to \delta(w-G\dot v_e ) for iG in range(nG): if Gvec[iG, perpdir[0]] == 0 and Gvec[iG, perpdir[1]] == 0: Glist.append(iG) qG = Gvec[Glist] + pd.K_qv w_w = self.omega_w * Hartree if w_max: w_w = w_w[np.where(w_w < w_max)] Nw = len(w_w) qGr = np.inner(qG, r.T).T phase = np.exp(1j * qGr) V_G = (4 * pi) / np.diagonal(np.inner(qG, qG)) phase2 = np.exp(-1j * qGr) * V_G E_wrr = np.zeros([Nw, r.shape[1], r.shape[1]]) E_wr = np.zeros([Nw, r.shape[1]]) for i in range(Nw): Vchi_GG = (np.linalg.inv(e_wGG[i, Glist, :][:, Glist]) - np.eye(len(Glist))) # Fourier transform: E_wrr[i] = -np.imag(np.dot(np.dot(phase, Vchi_GG), phase2.T)) E_wr[i] = np.diagonal(E_wrr[i]) pickle.dump((r * Bohr, w_w, E_wr), open('%s.pickle' % filename, 'wb'), pickle.HIGHEST_PROTOCOL) return r * Bohr, w_w, E_wr gpaw-0.11.0.13004/gpaw/response/kernel.py0000664000175000017500000004767312553643470020123 0ustar jensjjensj00000000000000# -*- coding: utf-8 # In an attempt to appease epydoc and still have readable docstrings, # the vertical bar | is represented by u'\u2758' in this module. """This module defines Coulomb and XC kernels for the response model. """ import numpy as np #from math import sqrt, pi, sin, cos, exp from gpaw.utilities.blas import gemmdot from gpaw.xc import XC from gpaw.sphere.lebedev import weight_n, R_nv from gpaw.mpi import world, rank, size from ase.dft.kpoints import monkhorst_pack def v3D_Coulomb(qG): """Coulomb Potential in the 3D Periodic Case. Periodic calculation, no cutoff. :: v3D = 4 pi / |q+G|^2 """ v_q = 1. / (qG**2).sum(axis=1) return v_q def v2D_Coulomb(qG, N_p, N_np, R): """Coulomb Potential in the 2D Periodic Case. Slab/Surface/Layer calculation. Cutoff in non-periodic N_np direction. No cutoff in periodic N_p directions. :: v2D = 4 pi/|q+G|^2 * [1 + exp(-|G_p|R)*[(G_n/|G_p|)*sin(G_n R) - cos(G_n R)] """ G_nR = qG[:, N_np[0]] * R G_pR = (qG[:, N_p[0]]**2 + qG[:, N_p[1]]**2)**0.5 * R v_q = 1. / (qG**2).sum(axis=1) v_q *= 1. + np.exp(-G_pR) * ((G_nR / G_pR) * np.sin(G_nR) - np.cos(G_nR)) return v_q.astype(complex) def v1D_Coulomb(qG, N_p, N_np, R): """Coulomb Potential in the 1D Periodic Case. Nanotube/Nanowire/Atomic Chain calculation. Cutoff in non-periodic N_np directions. No cutoff in periodic N_p direction. :: v1D = 4 pi/|q+G|^2 * [1 + |G_n|R J_1(|G_n|R) K_0(G_p R) - G_p R J_0(|G_n| R) K_1(G_p R)] """ from scipy.special import j1, k0, j0, k1 G_nR = (qG[:, N_np[0]]**2 + qG[:, N_np[1]]**2)**0.5 * R G_pR = abs(qG[:, N_p[0]]) * R v_q = 1. / (qG**2).sum(axis=1) v_q *= (1. + G_nR * j1(G_nR) * k0(G_pR) - G_pR * j0(G_nR) * k1(G_pR)) return v_q def v0D_Coulomb(qG, R): """Coulomb Potential in the 0D Non-Periodic Case Isolated System/Molecule calculation. Spherical cutoff in all directions. :: v0D = 4 pi/|G|^2 * [1 - cos(|G|R)] """ qGR = ((qG.sum(axis=1))**2)**0.5 * R v_q = 1. / (qG**2).sum(axis=1) v_q *= 1. - np.cos(qGR) return v_q class BaseCoulombKernel: """This is an abstract class for calculating the Coulomb kernel. """ def __init__(self, vcut): self.vcut = vcut def v_Coulomb(self, qG): """Returns the Coulomb potential in k-space. """ pass def calculate_Kc(self, q_c, Gvec_Gc, bcell_cv, integrate_gamma=False, N_k=None, symmetric=True): """Symmetric Coulomb kernel. """ pass def calculate_Kc_q(self, bcell_cv, N_k, q_qc=None, Gvec_c=None, N=100): """What does this do? XXX """ pass class CoulombKernel3D(BaseCoulombKernel): """Class for calculating the Coulomb kernel for a 3D calculation. vcut = [False, False, False]. """ def v_Coulomb(self, qG): """Coulomb Potential in the 3D Periodic Case. Periodic calculation, no cutoff. """ return v3D_Coulomb(qG) class CoulombKernel2D(BaseCoulombKernel): """Class for calculating the Coulomb kernel for a 2D calculation. Slab/Surface/Layer calculation. vcut = [False, False, True]. Cutoff in non-periodic N_np direction. No cutoff in periodic N_p directions. R = 1/2 max cell[N_np]. """ def __init__(self, vcut, cell): # Periodic Directions self.N_p = vcut.argsort()[:2] # Non-Periodic Direction self.N_np = vcut.argsort()[-1:] # 2D Radial Cutoff is one half the cell dimension in Bohr self.R = cell[self.N_np, self.N_np] / 2. BaseCoulombKernel.__init__(self, vcut) def v_Coulomb(self, qG): """Coulomb Potential in the 2D Periodic Case. Slab/Surface/Layer calculation. Cutoff in non-periodic N_np direction. No cutoff in periodic N_p directions. """ return v2D_Coulomb(qG, self.N_p, self.N_np, self.R) class CoulombKernel1D(BaseCoulombKernel): """Class for calculating the Coulomb kernel for a 1D calculation. Nanotube/Nanowire/Atomic Chain calculation. vcut = [False, True, True]. Cutoff in non-periodic N_np directions. No cutoff in periodic N_p direction. R = 1/2 max cell[N_np]. """ def __init__(self, vcut, cell): from scipy.special import j1, k0, j0, k1 # Periodic Direction self.N_p = vcut.argsort()[:1] # Non-Periodic Directions self.N_np = vcut.argsort()[-2:] # 2D Radial Cutoff is one half the cell dimension in Bohr self.R = max(cell[self.N_np[0], self.N_np[0]], cell[self.N_np[1], self.N_np[1]]) / 2. self.j1 = j1 self.k0 = k0 self.j0 = j0 self.k1 = k1 BaseCoulombKernel.__init__(self, vcut) def v_Coulomb(self, qG): """Coulomb Potential in the 1D Periodic Case. Nanotube/Nanowire/Atomic Chain calculation. Cutoff in non-periodic N_np directions. No cutoff in periodic N_p direction. """ return v1D_Coulomb(qG, self.N_p, self.N_np, self.R) class CoulombKernel0D(BaseCoulombKernel): """Class for calculating the Coulomb kernel for a 0D calculation. Isolated System/Molecule calculation. vcut = [True, True, True]. Spherical cutoff in all directions. R = 1/2 max cell. """ def __init__(self, vcut, cell): self.R = max(np.diag(cell)) / 2. BaseCoulombKernel.__init__(self, vcut) def v_Coulomb(self, qG): """Coulomb Potential in the 0D Non-Periodic Case Isolated System/Molecule calculation. Spherical cutoff in all directions. """ return v0D_Coulomb(qG, self.R) class CoulombKernel(BaseCoulombKernel): """Class for calculating the Coulomb kernel. vcut = None (Default). Applies Coulomb cutoff in non-periodic directions. vcut = '3D' => [False, False, False]. vcut = '2D' => [False, False, True]. vcut = '1D' => [False, True, True]. vcut = '0D' => [True, True, True]. vcut is a numpy arry of type bool of length 3. """ def __init__(self, vcut, pbc, cell): if vcut is None: vcut = pbc - True elif isinstance(vcut, str): # Assume vcut = 'nD', where n is number of periodic directions # Should be deprecated n_p = int(vcut[0]) vcut = np.ones(3, bool) vcut[:n_p] = False # 3D periodic case if vcut.sum() == 0: self.impl = CoulombKernel3D(vcut) # 2D periodic case elif vcut.sum() == 1: self.impl = CoulombKernel2D(vcut, cell) # 1D periodic case elif vcut.sum() == 2: self.impl = CoulombKernel1D(vcut, cell) # 0D periodic case elif vcut.sum() == 3: self.impl = CoulombKernel0D(vcut, cell) BaseCoulombKernel.__init__(self, vcut) def v_Coulomb(self, qG): """Returns vcut dependent Coulomb potential. Uses v_Coulomb as implemented in self.impl """ return self.impl.v_Coulomb(qG) def calculate_Kc(self, q_c, Gvec_Gc, bcell_cv, integrate_gamma=False, N_k=None, symmetric=True): """Symmetric Coulomb kernel""" if integrate_gamma: assert N_k is not None if (q_c == 0).all(): # Only to avoid dividing by zero below! # The term is handled separately later q_c = [1.e-12, 0., 0.] qG_c = np.zeros((len(Gvec_Gc), 3)) qG_c[:, 0] = Gvec_Gc[:, 0] + q_c[0] qG_c[:, 1] = Gvec_Gc[:, 1] + q_c[1] qG_c[:, 2] = Gvec_Gc[:, 2] + q_c[2] qG = np.dot(qG_c, bcell_cv) # Calculate coulomb kernel Kc_G = self.v_Coulomb(qG) if integrate_gamma and np.abs(q_c).sum() < 1e-8: bvol = np.abs(np.linalg.det(bcell_cv)) / (N_k[0] * N_k[1] * N_k[2]) R_q0 = (3. * bvol / (4. * np.pi))**(1. / 3.) Kc_G[0] = 4. * np.pi * R_q0 / bvol if symmetric: Kc_G = np.array(Kc_G, np.complex)**0.5 Kc_G = np.outer(Kc_G.conj(), Kc_G) return 4. * np.pi * Kc_G else: return 4. * np.pi * (Kc_G * np.ones([len(Kc_G), len(Kc_G)])).T def calculate_Kc_q(self, bcell_cv, N_k, q_qc=None, Gvec_c=None, N=100): if q_qc is None: q_qc = np.array([[1.e-12, 0., 0.]]) if Gvec_c is None: Gvec_c = np.array([0, 0, 0]) bcell = bcell_cv.copy() bcell[0] /= N_k[0] bcell[1] /= N_k[1] bcell[2] /= N_k[2] bvol = np.abs(np.linalg.det(bcell)) gamma = np.where(np.sum(abs(q_qc), axis=1) < 1e-5)[0][0] if (Gvec_c == 0).all(): q_qc = q_qc.copy() # Just to avoid zero division q_qc[gamma] = [0.001, 0., 0.] q_qc[:, 0] += Gvec_c[0] q_qc[:, 1] += Gvec_c[1] q_qc[:, 2] += Gvec_c[2] qG = np.dot(q_qc, bcell_cv) K0_q = self.v_Coulomb(qG) if (Gvec_c == 0).all(): R_q0 = (3. * bvol / (4. * np.pi))**(1. / 3.) K0_q[gamma] = 4. * np.pi * R_q0 / bvol bvol = np.abs(np.linalg.det(bcell)) # Integrated Coulomb kernel qt_qc = monkhorst_pack((N, N, N)) qt_qcv = np.dot(qt_qc, bcell) dv = bvol / len(qt_qcv) K_q = np.zeros(len(q_qc), complex) for i in range(len(q_qc)): q = qt_qcv.copy() + qG[i] v_q = v3D_Coulomb(q) K_q[i] = np.sum(v_q) * dv / bvol return 4. * np.pi * K_q, 4. * np.pi * K0_q def calculate_Kc(q_c, Gvec_Gc, acell_cv, bcell_cv, pbc, vcut=None, integrate_gamma=False, N_k=None, symmetric=True): """Symmetric Coulomb kernel""" if integrate_gamma: assert N_k is not None if (q_c == 0).all(): # Only to avoid dividing by zero below! # The term is handled separately later q_c = [1.e-12, 0., 0.] #G_p = np.array(pbc, float) #G_n = np.array([1,1,1]) - G_p if vcut is None: vcut = '3D' G_p = np.array(pbc, bool).argsort()[-int(vcut[0]):] G_n = np.array(pbc, bool).argsort()[:int(vcut[0])] if vcut is None or vcut == '3D': pass elif vcut == '2D': # R is half the length of cell in non-periodic direction if pbc.all(): # G_n.sum() < 1e-8: # default dir is z G_n = np.array([2]) # np.array([0,0,1]) G_p = np.array([0, 1]) # np.array([1,1,0]) acell_n = acell_cv[G_n, G_n] R = max(acell_n) / 2. elif vcut == '1D': # R is the radius of the cylinder containing the cell. if pbc.all(): # G_n.sum() < 1e-8: raise ValueError('Check boundary condition ! ') acell_n = acell_cv R = max(acell_n[G_n[0], G_n[0]], acell_n[G_n[1], G_n[1]]) / 2. elif vcut == '0D': # R is the minimum radius of a sphere containing the cell. acell_n = acell_cv R = min(acell_n[0, 0], acell_n[1, 1], acell_n[2, 2]) / 2. else: NotImplemented qG_c = np.zeros((len(Gvec_Gc), 3)) qG_c[:, 0] = Gvec_Gc[:, 0] + q_c[0] qG_c[:, 1] = Gvec_Gc[:, 1] + q_c[1] qG_c[:, 2] = Gvec_Gc[:, 2] + q_c[2] qG = np.dot(qG_c, bcell_cv) # Calculate Coulomb kernel if vcut is None or vcut == '3D': Kc_G = v3D_Coulomb(qG) elif vcut == '2D': Kc_G = v2D_Coulomb(qG, G_p, G_n, R) elif vcut == '1D': Kc_G = v1D_Coulomb(qG, G_p, G_n, R) elif vcut == '0D': Kc_G = v0D_Coulomb(qG, R) else: NotImplemented if integrate_gamma and np.abs(q_c).sum() < 1e-8: bvol = np.abs(np.linalg.det(bcell_cv)) / (N_k[0] * N_k[1] * N_k[2]) R_q0 = (3. * bvol / (4. * np.pi))**(1. / 3.) Kc_G[0] = 4. * np.pi * R_q0 / bvol if symmetric: #print "Kc_G" #print Kc_G Kc_G = np.array(Kc_G, np.complex)**0.5 #print "Kc_G^0.5" #print Kc_GC #print "Outer Product" Kc_G = np.outer(Kc_G.conj(), Kc_G) #print Kc_G return 4. * np.pi * Kc_G # np.outer(Kc_G.conj(), Kc_G) else: return 4. * np.pi * (Kc_G * np.ones([len(Kc_G), len(Kc_G)])).T def calculate_Kxc(gd, nt_sG, npw, Gvec_Gc, nG, vol, bcell_cv, R_av, setups, D_asp, functional='ALDA', density_cut=None): """ALDA kernel""" # The soft part #assert np.abs(nt_sG[0].shape - nG).sum() == 0 if functional == 'ALDA_X': x_only = True A_x = -3. / 4. * (3. / np.pi)**(1. / 3.) nspins = len(nt_sG) assert nspins in [1, 2] fxc_sg = nspins**(1. / 3.) * 4. / 9. * A_x * nt_sG**(-2. / 3.) else: assert len(nt_sG) == 1 x_only = False fxc_sg = np.zeros_like(nt_sG) xc = XC(functional[1:]) xc.calculate_fxc(gd, nt_sG, fxc_sg) if density_cut is not None: fxc_sg[np.where(nt_sG * len(nt_sG) < density_cut)] = 0.0 # FFT fxc(r) nG0 = nG[0] * nG[1] * nG[2] tmp_sg = [np.fft.fftn(fxc_sg[s]) * vol / nG0 for s in range(len(nt_sG))] r_vg = gd.get_grid_point_coordinates() Kxc_sGG = np.zeros((len(fxc_sg), npw, npw), dtype=complex) for s in range(len(fxc_sg)): for iG in range(npw): for jG in range(npw): dG_c = Gvec_Gc[iG] - Gvec_Gc[jG] if (nG / 2 - np.abs(dG_c) > 0).all(): index = (dG_c + nG) % nG Kxc_sGG[s, iG, jG] = tmp_sg[s][index[0], index[1], index[2]] else: # not in the fft index dG_v = np.dot(dG_c, bcell_cv) dGr_g = gemmdot(dG_v, r_vg, beta=0.0) Kxc_sGG[s, iG, jG] = gd.integrate(np.exp(-1j * dGr_g) * fxc_sg[s]) # The PAW part KxcPAW_sGG = np.zeros_like(Kxc_sGG) dG_GGv = np.zeros((npw, npw, 3)) for iG in range(npw): for jG in range(npw): dG_c = Gvec_Gc[iG] - Gvec_Gc[jG] dG_GGv[iG, jG] = np.dot(dG_c, bcell_cv) for a, setup in enumerate(setups): if rank == a % size: rgd = setup.xc_correction.rgd n_qg = setup.xc_correction.n_qg nt_qg = setup.xc_correction.nt_qg nc_g = setup.xc_correction.nc_g nct_g = setup.xc_correction.nct_g Y_nL = setup.xc_correction.Y_nL dv_g = rgd.dv_g D_sp = D_asp[a] B_pqL = setup.xc_correction.B_pqL D_sLq = np.inner(D_sp, B_pqL.T) nspins = len(D_sp) f_sg = rgd.empty(nspins) ft_sg = rgd.empty(nspins) n_sLg = np.dot(D_sLq, n_qg) nt_sLg = np.dot(D_sLq, nt_qg) # Add core density n_sLg[:, 0] += np.sqrt(4. * np.pi) / nspins * nc_g nt_sLg[:, 0] += np.sqrt(4. * np.pi) / nspins * nct_g coefatoms_GG = np.exp(-1j * np.inner(dG_GGv, R_av[a])) for n, Y_L in enumerate(Y_nL): w = weight_n[n] f_sg[:] = 0.0 n_sg = np.dot(Y_L, n_sLg) if x_only: f_sg = nspins * (4 / 9.) * A_x * (nspins * n_sg)**(-2 / 3.) else: xc.calculate_fxc(rgd, n_sg, f_sg) ft_sg[:] = 0.0 nt_sg = np.dot(Y_L, nt_sLg) if x_only: ft_sg = nspins * (4 / 9.) * (A_x * (nspins * nt_sg)**(-2 / 3.)) else: xc.calculate_fxc(rgd, nt_sg, ft_sg) for i in range(len(rgd.r_g)): coef_GG = np.exp(-1j * np.inner(dG_GGv, R_nv[n]) * rgd.r_g[i]) for s in range(len(f_sg)): KxcPAW_sGG[s] += w * np.dot(coef_GG, (f_sg[s, i] - ft_sg[s, i]) * dv_g[i]) * coefatoms_GG world.sum(KxcPAW_sGG) Kxc_sGG += KxcPAW_sGG return Kxc_sGG / vol def calculate_Kc_q(acell_cv, bcell_cv, pbc, N_k, vcut=None, integrated=True, q_qc=np.array([[1.e-12, 0., 0.]]), Gvec_c=np.array([0, 0, 0]), N=100): # get cutoff parameters #G_p = np.array(pbc, int) # Normal Direction #G_n = np.array([1,1,1]) - G_p if vcut is None: vcut = '3D' G_p = np.array(pbc, bool).argsort()[-int(vcut[0]):] G_n = np.array(pbc, bool).argsort()[:int(vcut[0])] if vcut is None or vcut == '3D': pass elif vcut == '2D': if pbc.all(): # G_n.sum() < 1e-8: # default dir is z G_n = np.array([2]) G_p = np.array([0, 1]) acell_n = acell_cv[G_n, G_n] R = max(acell_n) / 2. elif vcut == '1D': # R is the radius of the cylinder containing the cell. if pbc.all(): # G_n.sum() < 1e-8: raise ValueError('Check boundary condition ! ') acell_n = acell_cv R = max(acell_n[G_n[0], G_n[0]], acell_n[G_n[1], G_n[1]]) / 2. elif vcut == '0D': # R is the minimum radius of a sphere containing the cell. acell_n = acell_cv R = min(acell_n[0, 0], acell_n[1, 1], acell_n[2, 2]) / 2. else: NotImplemented bcell = bcell_cv.copy() bcell[0] /= N_k[0] bcell[1] /= N_k[1] bcell[2] /= N_k[2] bvol = np.abs(np.linalg.det(bcell)) gamma = np.where(np.sum(abs(q_qc), axis=1) < 1e-5)[0][0] if (Gvec_c[G_p] == 0).all(): q_qc[gamma][G_p[0]] = 1.e-12 # Just to avoid zero division q_qc[:, 0] += Gvec_c[0] q_qc[:, 1] += Gvec_c[1] q_qc[:, 2] += Gvec_c[2] qG = np.dot(q_qc, bcell_cv) if vcut is None or vcut == '3D': K0_q = v3D_Coulomb(qG) if (Gvec_c == 0).all(): R_q0 = (3. * bvol / (4. * np.pi))**(1. / 3.) K0_q[gamma] = 4. * np.pi * R_q0 / bvol elif vcut == '2D': K0_q = v2D_Coulomb(qG, G_p, G_n, R) if (Gvec_c == 0).all(): R_q0 = (3 * bvol / (4. * np.pi))**(1. / 3.) K0_q[gamma] = (4. * np.pi * R_q0 / bvol) elif vcut == '1D': K0_q = v1D_Coulomb(qG, G_p, G_n, R) elif vcut == '0D': K0_q = v0D_Coulomb(qG, R) else: NotImplemented bvol = np.abs(np.linalg.det(bcell)) # Integrated Coulomb kernel qt_qc = monkhorst_pack((N, N, N)) qt_qcv = np.dot(qt_qc, bcell) dv = bvol / len(qt_qcv) K_q = np.zeros(len(q_qc), complex) for i in range(len(q_qc)): q = qt_qcv.copy() + qG[i] if vcut is None or vcut == '3D': v_q = v3D_Coulomb(q) elif vcut == '2D': v_q = v2D_Coulomb(q, G_p, G_n, R) elif vcut == '1D': v_q = v1D_Coulomb(q, G_p, G_n, R) elif vcut == '0D': v_q = v0D_Coulomb(q, R) else: NotImplemented K_q[i] = np.sum(v_q) * dv / bvol return 4. * np.pi * K_q, 4. * np.pi * K0_q gpaw-0.11.0.13004/gpaw/response/df0.py0000664000175000017500000010245712553643470017304 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from math import sqrt, pi import pickle from ase.units import Hartree, Bohr from gpaw.mpi import rank from gpaw.response.chi import CHI class DF(CHI): """This class defines dielectric function related physical quantities.""" def __init__(self, calc=None, nbands=None, w=None, q=None, eshift=None, ecut=10., density_cut=None, G_plus_q=False, eta=0.2, rpad=None, vcut=None, ftol=1e-7, txt=None, xc='ALDA', print_xc_scf=False, hilbert_trans=True, time_ordered=False, optical_limit=False, comm=None, kcommsize=None): CHI.__init__(self, calc=calc, nbands=nbands, w=w, q=q, eshift=eshift, ecut=ecut, density_cut=density_cut, G_plus_q=G_plus_q, eta=eta, rpad=rpad, vcut=vcut, ftol=ftol, txt=txt, xc=xc, hilbert_trans=hilbert_trans, time_ordered=time_ordered, optical_limit=optical_limit, comm=comm, kcommsize=kcommsize) self.df_flag = False self.print_bootstrap = print_xc_scf self.df1_w = None # NLF RPA self.df2_w = None # LF RPA self.df3_w = None # NLF ALDA self.df4_w = None # LF ALDA def get_dielectric_matrix(self, xc='RPA', overwritechi0=False, symmetric=True, chi0_wGG=None, calc=None, vcut=None, dir=None): if self.chi0_wGG is None and chi0_wGG is None: self.initialize() self.calculate() elif self.chi0_wGG is None and chi0_wGG is not None: #Read from file and reinitialize self.xc = xc from gpaw.response.parallel import par_read self.chi0_wGG = par_read(chi0_wGG, 'chi0_wGG') self.nvalbands = self.nbands #self.parallel_init() # parallelization not yet implemented self.Nw_local = self.Nw # parallelization not yet implemented if self.calc is None: from gpaw import GPAW self.calc = GPAW(calc,txt=None) if self.xc == 'ALDA' or self.xc == 'ALDA_X': from gpaw.response.kernel import calculate_Kxc from gpaw.grid_descriptor import GridDescriptor from gpaw.mpi import world, rank, size, serial_comm self.pbc = self.calc.atoms.pbc self.gd = GridDescriptor(self.calc.wfs.gd.N_c*self.rpad, self.acell_cv, pbc_c=True, comm=serial_comm) R_av = self.calc.atoms.positions / Bohr nt_sg = self.calc.density.nt_sG if (self.rpad > 1).any() or (self.pbc - True).any(): nt_sG = self.gd.zeros(self.nspins) #nt_sG = np.zeros([self.nspins, self.nG[0], self.nG[1], self.nG[2]]) for s in range(self.nspins): nt_G = self.pad(nt_sg[s]) nt_sG[s] = nt_G else: nt_sG = nt_sg self.Kxc_sGG = calculate_Kxc(self.gd, nt_sG, self.npw, self.Gvec_Gc, self.gd.N_c, self.vol, self.bcell_cv, R_av, self.calc.wfs.setups, self.calc.density.D_asp, functional=self.xc, density_cut=self.density_cut) if overwritechi0: dm_wGG = self.chi0_wGG else: dm_wGG = np.zeros_like(self.chi0_wGG) if dir is None: q_c = self.q_c else: q_c = np.diag((1,1,1))[dir] * self.qopt self.chi0_wGG[:,0,:] = self.chi00G_wGv[:,:,dir] self.chi0_wGG[:,:,0] = self.chi0G0_wGv[:,:,dir] from gpaw.response.kernel import calculate_Kc, CoulombKernel kernel = CoulombKernel(vcut=self.vcut, pbc=self.calc.atoms.pbc, cell=self.acell_cv) self.Kc_GG = kernel.calculate_Kc(q_c, self.Gvec_Gc, self.bcell_cv, symmetric=symmetric) #self.Kc_GG = calculate_Kc(q_c, # self.Gvec_Gc, # self.acell_cv, # self.bcell_cv, # self.pbc, # self.vcut, # symmetric=symmetric) tmp_GG = np.eye(self.npw, self.npw) if xc == 'RPA': self.printtxt('Use RPA.') for iw in range(self.Nw_local): dm_wGG[iw] = tmp_GG - self.Kc_GG * self.chi0_wGG[iw] elif xc == 'ALDA': self.printtxt('Use ALDA kernel.') # E_LDA = 1 - v_c chi0 (1-fxc chi0)^-1 # http://prb.aps.org/pdf/PRB/v33/i10/p7017_1 eq. 4 A_wGG = self.chi0_wGG.copy() for iw in range(self.Nw_local): A_wGG[iw] = np.dot(self.chi0_wGG[iw], np.linalg.inv(tmp_GG - np.dot(self.Kxc_sGG[0], self.chi0_wGG[iw]))) for iw in range(self.Nw_local): dm_wGG[iw] = tmp_GG - self.Kc_GG * A_wGG[iw] return dm_wGG def get_inverse_dielectric_matrix(self, xc='RPA'): dm_wGG = self.get_dielectric_matrix(xc=xc) dminv_wGG = np.zeros_like(dm_wGG) for iw in range(self.Nw_local): dminv_wGG[iw] = np.linalg.inv(dm_wGG[iw]) return dminv_wGG def get_chi(self, xc='RPA'): """Solve Dyson's equation.""" if self.chi0_wGG is None: self.initialize() self.calculate() else: pass # read from file and re-initializing .... need to be implemented kernel_GG = np.zeros((self.npw, self.npw), dtype=complex) chi_wGG = np.zeros_like(self.chi0_wGG) # Coulomb kernel for iG in range(self.npw): qG = np.dot(self.q_c + self.Gvec_Gc[iG], self.bcell_cv) kernel_GG[iG,iG] = 4 * pi / np.dot(qG, qG) if xc == 'ALDA': kernel_GG += self.Kxc_sGG[0] for iw in range(self.Nw_local): tmp_GG = np.eye(self.npw, self.npw) - np.dot(self.chi0_wGG[iw], kernel_GG) chi_wGG[iw] = np.dot(np.linalg.inv(tmp_GG) , self.chi0_wGG[iw]) return chi_wGG def get_dielectric_function(self, xc='RPA', dir=None): """Calculate the dielectric function. Returns df1_w and df2_w. Parameters: df1_w: ndarray Dielectric function without local field correction. df2_w: ndarray Dielectric function with local field correction. """ if not self.optical_limit: assert dir is None if self.df_flag is False: dm_wGG = self.get_dielectric_matrix(xc=xc, dir=dir) Nw_local = dm_wGG.shape[0] dfNLF_w = np.zeros(Nw_local, dtype = complex) dfLFC_w = np.zeros(Nw_local, dtype = complex) df1_w = np.zeros(self.Nw, dtype = complex) df2_w = np.zeros(self.Nw, dtype = complex) for iw in range(Nw_local): tmp_GG = dm_wGG[iw] dfLFC_w[iw] = 1. / np.linalg.inv(tmp_GG)[0, 0] dfNLF_w[iw] = tmp_GG[0, 0] self.wcomm.all_gather(dfNLF_w, df1_w) self.wcomm.all_gather(dfLFC_w, df2_w) if xc == 'RPA': self.df1_w = df1_w self.df2_w = df2_w elif xc=='ALDA' or xc=='ALDA_X': self.df3_w = df1_w self.df4_w = df2_w if xc == 'RPA': return self.df1_w, self.df2_w elif xc == 'ALDA' or xc=='ALDA_X': return self.df3_w, self.df4_w def get_surface_response_function(self, z0=0., filename='surf_EELS'): """Calculate surface response function.""" if self.chi0_wGG is None: self.initialize() self.calculate() g_w2 = np.zeros((self.Nw,2), dtype=complex) assert self.acell_cv[0, 2] == 0. and self.acell_cv[1, 2] == 0. Nz = self.gd.N_c[2] # number of points in z direction tmp = np.zeros(Nz, dtype=int) nGz = 0 # number of G_z for i in range(self.npw): if self.Gvec_Gc[i, 0] == 0 and self.Gvec_Gc[i, 1] == 0: tmp[nGz] = self.Gvec_Gc[i, 2] nGz += 1 assert (np.abs(self.Gvec_Gc[:nGz, :2]) < 1e-10).all() for id, xc in enumerate(['RPA', 'ALDA']): chi_wGG = self.get_chi(xc=xc) # The first nGz are all Gx=0 and Gy=0 component chi_wgg_LFC = chi_wGG[:, :nGz, :nGz] del chi_wGG chi_wzz_LFC = np.zeros((self.Nw_local, Nz, Nz), dtype=complex) # Fourier transform of chi_wgg to chi_wzz Gz_g = tmp[:nGz] * self.bcell_cv[2,2] z_z = np.linspace(0, self.acell_cv[2,2]-self.gd.h_cv[2,2], Nz) phase1_zg = np.exp(1j * np.outer(z_z, Gz_g)) phase2_gz = np.exp(-1j * np.outer(Gz_g, z_z)) for iw in range(self.Nw_local): chi_wzz_LFC[iw] = np.dot(np.dot(phase1_zg, chi_wgg_LFC[iw]), phase2_gz) chi_wzz_LFC /= self.acell_cv[2,2] # Get surface response function z_z -= z0 / Bohr q_v = np.dot(self.q_c, self.bcell_cv) qq = sqrt(np.inner(q_v, q_v)) phase1_1z = np.array([np.exp(qq*z_z)]) phase2_z1 = np.exp(qq*z_z) tmp_w = np.zeros(self.Nw_local, dtype=complex) for iw in range(self.Nw_local): tmp_w[iw] = np.dot(np.dot(phase1_1z, chi_wzz_LFC[iw]), phase2_z1)[0] tmp_w *= -2 * pi / qq * self.gd.h_cv[2,2]**2 g_w = np.zeros(self.Nw, dtype=complex) self.wcomm.all_gather(tmp_w, g_w) g_w2[:, id] = g_w if rank == 0: f = open(filename,'w') for iw in range(self.Nw): energy = iw * self.dw * Hartree print(energy, np.imag(g_w2[iw, 0]), np.imag(g_w2[iw, 1]), file=f) f.close() # Wait for I/O to finish self.comm.barrier() def check_sum_rule(self, df1_w=None, df2_w=None): """Check f-sum rule.""" if df1_w is None: df1_w = self.df1_w df2_w = self.df2_w N1 = N2 = 0 for iw in range(self.Nw): w = iw * self.dw N1 += np.imag(df1_w[iw]) * w N2 += np.imag(df2_w[iw]) * w N1 *= self.dw * self.vol / (2 * pi**2) N2 *= self.dw * self.vol / (2 * pi**2) self.printtxt('') self.printtxt('Sum rule for ABS:') nv = self.nvalence self.printtxt('Without local field: N1 = %f, %f %% error' %(N1, (N1 - nv) / nv * 100) ) self.printtxt('Include local field: N2 = %f, %f %% error' %(N2, (N2 - nv) / nv * 100) ) N1 = N2 = 0 for iw in range(self.Nw): w = iw * self.dw N1 -= np.imag(1/df1_w[iw]) * w N2 -= np.imag(1/df2_w[iw]) * w N1 *= self.dw * self.vol / (2 * pi**2) N2 *= self.dw * self.vol / (2 * pi**2) self.printtxt('') self.printtxt('Sum rule for EELS:') nv = self.nvalence self.printtxt('Without local field: N1 = %f, %f %% error' %(N1, (N1 - nv) / nv * 100) ) self.printtxt('Include local field: N2 = %f, %f %% error' %(N2, (N2 - nv) / nv * 100) ) def get_macroscopic_dielectric_constant(self, xc='RPA'): """Calculate macroscopic dielectric constant. Returns eM1 and eM2 Macroscopic dielectric constant is defined as the real part of dielectric function at w=0. Parameters: eM1: float Dielectric constant without local field correction. (RPA, ALDA) eM2: float Dielectric constant with local field correction. """ assert self.optical_limit self.printtxt('') self.printtxt('%s Macroscopic Dielectric Constant:' % xc) dirstr = ['x', 'y', 'z'] for dir in range(3): eM = np.zeros(2) df1, df2 = self.get_dielectric_function(xc=xc, dir=dir) eps0 = np.real(df1[0]) eps = np.real(df2[0]) self.printtxt(' %s direction' %(dirstr[dir])) self.printtxt(' Without local field: %f' % eps0 ) self.printtxt(' Include local field: %f' % eps ) return eps0, eps def get_absorption_spectrum(self, filename='Absorption.dat'): """Calculate optical absorption spectrum. By default, generate a file 'Absorption.dat'. Optical absorption spectrum is obtained from the imaginary part of dielectric function. """ assert self.optical_limit for dir in range(3): df1, df2 = self.get_dielectric_function(xc='RPA', dir=dir) if self.xc == 'ALDA': df3, df4 = self.get_dielectric_function(xc='ALDA', dir=dir) if self.xc == 'ALDA_X': df3, df4 = self.get_dielectric_function(xc='ALDA_X', dir=dir) Nw = df1.shape[0] if self.xc == 'Bootstrap': # bootstrap doesnt support all direction spectra yet from gpaw.response.fxc import Bootstrap Kc_GG = np.zeros((self.npw, self.npw)) q_c = np.diag((1, 1, 1))[dir] * self.qopt for iG in range(self.npw): qG = np.dot(q_c + self.Gvec_Gc[iG], self.bcell_cv) Kc_GG[iG,iG] = 4 * pi / np.dot(qG, qG) from gpaw.mpi import world assert self.wcomm.size == world.size df3 = Bootstrap(self.chi0_wGG, Nw, Kc_GG, self.printtxt, self.print_bootstrap, self.wcomm) if rank == 0: f = open('%s.%s' % (filename, 'xyz'[dir]), 'w') #f = open(filename+'.%s'%(dirstr[dir]),'w') # ???? for iw in range(Nw): energy = iw * self.dw * Hartree if self.xc == 'RPA': print(energy, np.real(df1[iw]), np.imag(df1[iw]), \ np.real(df2[iw]), np.imag(df2[iw]), file=f) elif self.xc == 'ALDA': print(energy, np.real(df1[iw]), np.imag(df1[iw]), \ np.real(df2[iw]), np.imag(df2[iw]), \ np.real(df3[iw]), np.imag(df3[iw]), \ np.real(df4[iw]), np.imag(df4[iw]), file=f) elif self.xc == 'Bootstrap': print(energy, np.real(df1[iw]), np.imag(df1[iw]), \ np.real(df2[iw]), np.imag(df2[iw]), \ np.real(df3[iw]), np.imag(df3[iw]), file=f) f.close() # Wait for I/O to finish self.comm.barrier() def get_EELS_spectrum(self, filename='EELS.dat'): """Calculate EELS spectrum. By default, generate a file 'EELS.dat'. EELS spectrum is obtained from the imaginary part of the inverse of dielectric function. """ # calculate RPA dielectric function df1, df2 = self.get_dielectric_function(xc='RPA') if self.xc == 'ALDA': df3, df4 = self.get_dielectric_function(xc='ALDA') Nw = df1.shape[0] if rank == 0: f = open(filename,'w') for iw in range(self.Nw): energy = iw * self.dw * Hartree if self.xc == 'RPA': print(energy, -np.imag(1./df1[iw]), -np.imag(1./df2[iw]), file=f) elif self.xc == 'ALDA': print(energy, -np.imag(1./df1[iw]), -np.imag(1./df2[iw]), \ -np.imag(1./df3[iw]), -np.imag(1./df4[iw]), file=f) f.close() # Wait for I/O to finish self.comm.barrier() def get_jdos(self, f_skn, e_skn, kd, kq, dw, Nw, sigma): """Calculate Joint density of states""" JDOS_w = np.zeros(Nw) nbands = f_skn[0].shape[1] for k in range(kd.nbzkpts): print(k) ibzkpt1 = kd.bz2ibz_k[k] ibzkpt2 = kd.bz2ibz_k[kq[k]] for n in range(nbands): for m in range(nbands): focc = f_skn[0][ibzkpt1, n] - f_skn[0][ibzkpt2, m] w0 = e_skn[0][ibzkpt2, m] - e_skn[0][ibzkpt1, n] if focc > 0 and w0 >= 0: w0_id = int(w0 / dw) if w0_id + 1 < Nw: alpha = (w0_id + 1 - w0/dw) / dw JDOS_w[w0_id] += focc * alpha alpha = (w0/dw-w0_id) / dw JDOS_w[w0_id+1] += focc * alpha w = np.arange(Nw) * dw * Hartree return w, JDOS_w def calculate_induced_density(self, q, w): """ Evaluate induced density for a certain q and w. Parameters: q: ndarray Momentum tranfer at reduced coordinate. w: scalar Energy (eV). """ if isinstance(w, int): iw = w w = self.wlist[iw] / Hartree elif isinstance(w, float): w /= Hartree iw = int(np.round(w / self.dw)) else: raise ValueError('Frequency not correct !') self.printtxt('Calculating Induced density at q, w (iw)') self.printtxt('(%f, %f, %f), %f(%d)' %(q[0], q[1], q[2], w*Hartree, iw)) # delta_G0 delta_G = np.zeros(self.npw) delta_G[0] = 1. # coef is (q+G)**2 / 4pi coef_G = np.zeros(self.npw) for iG in range(self.npw): qG = np.dot(q + self.Gvec_Gc[iG], self.bcell_cv) coef_G[iG] = np.dot(qG, qG) coef_G /= 4 * pi # obtain chi_G0(q,w) dm_wGG = self.get_RPA_dielectric_matrix() tmp_GG = dm_wGG[iw] del dm_wGG chi_G = (np.linalg.inv(tmp_GG)[:, 0] - delta_G) * coef_G gd = self.gd r = gd.get_grid_point_coordinates() # calculate dn(r,q,w) drho_R = gd.zeros(dtype=complex) for iG in range(self.npw): qG = np.dot(q + self.Gvec_Gc[iG], self.bcell_cv) qGr_R = np.inner(qG, r.T).T drho_R += chi_G[iG] * np.exp(1j * qGr_R) # phase = sum exp(iq.R_i) return drho_R def get_induced_density_z(self, q, w): """Get induced density on z axis (summation over xy-plane). """ drho_R = self.calculate_induced_density(q, w) drho_z = np.zeros(self.gd.N_c[2],dtype=complex) # dxdy = np.cross(self.h_c[0], self.h_c[1]) for iz in range(self.gd.N_c[2]): drho_z[iz] = drho_R[:,:,iz].sum() return drho_z def get_eigenmodes(self,filename = None, chi0 = None, calc = None, dm = None, xc = 'RPA', sum = None, vcut = None, checkphase = False, return_full = False): """ Calculate the plasmonic eigenmodes as eigenvectors of the dielectric matrix. Parameters: filename: pckl file output from response calculation. chi0: gpw file chi0_wGG from response calculation. calc: gpaw calculator instance ground state calculator used in response calculation. Wavefunctions only needed if chi0 is calculated from scratch dm: gpw file dielectric matrix from response calculation xc: str 'RPA'or 'ALDA' XC- Kernel sum: str '2D': sum in the x and y directions '1D': To be implemented vcut: str '0D','1D' or '2D' Cut the Coulomb potential checkphase: Bool if True, the eigenfunctions id rotated in the complex plane, to be made as real as posible return_full: Bool if True, the eigenvectors in reciprocal space is also returned. """ self.read(filename) self.pbc = [1,1,1] #self.calc.atoms.pbc = [1,1,1] npw = self.npw self.w_w = np.linspace(0, self.dw * (self.Nw - 1)*Hartree, self.Nw) self.vcut = vcut dm_wGG = self.get_dielectric_matrix(xc=xc, symmetric=False, chi0_wGG=chi0, calc=calc, vcut=vcut) q = self.q_c # get grid on which the eigenmodes are calculated #gd = self.calc.wfs.gd #r = gd.get_grid_point_coordinates() #rrr = r*Bohr from gpaw.utilities.gpts import get_number_of_grid_points from gpaw.grid_descriptor import GridDescriptor grid_size = [1,1,1] h=0.2 cell_cv = self.acell_cv*np.diag(grid_size) mode = 'fd' realspace = True h /= Bohr N_c = get_number_of_grid_points(cell_cv, h, mode, realspace) gd = GridDescriptor(N_c, cell_cv, self.pbc) #gd = self.calc.wfs.gd r = gd.get_grid_point_coordinates() rrr = r*Bohr eig_0 = np.array([], dtype = complex) eig_left = np.array([], dtype = complex) eig_right = np.array([], dtype = complex) vec_modes = np.zeros([1, self.npw], dtype = complex) vec_modes_dual = np.zeros([1, self.npw], dtype = complex) vec_modes_density = np.zeros([1, self.npw], dtype = complex) vec_modes_norm = np.zeros([1, self.npw], dtype = complex) eig_all = np.zeros([1, self.npw], dtype = complex) eig_dummy = np.zeros([1, self.npw], dtype = complex) v_dummy = np.zeros([1, self.npw], dtype = complex) vec_dummy = np.zeros([1, self.npw], dtype = complex) vec_dummy2 = np.zeros([1, self.npw], dtype = complex) w_0 = np.array([]) w_left = np.array([]) w_right = np.array([]) if sum == '2D': v_ind = np.zeros([1, r.shape[-1]], dtype = complex) n_ind = np.zeros([1, r.shape[-1]], dtype = complex) elif sum == '1D': self.printtxt('1D sum not implemented') return else: v_ind = np.zeros([1, r.shape[1], r.shape[2], r.shape[3]], dtype = complex) n_ind = np.zeros([1, r.shape[1], r.shape[2], r.shape[3]], dtype = complex) eps_GG_plus = dm_wGG[0] eig_plus, vec_plus = np.linalg.eig(eps_GG_plus) # find eigenvalues and eigenvectors vec_plus_dual = np.linalg.inv(vec_plus) # loop over frequencies, where the eigenvalues for the 2D matrix in G,G' are found. for i in np.array(range(self.Nw-1))+1: eps_GG = eps_GG_plus eig, vec = eig_plus,vec_plus vec_dual = vec_plus_dual eps_GG_plus = dm_wGG[i] # epsilon_GG'(omega + d-omega) eig_plus, vec_plus = np.linalg.eig(eps_GG_plus) vec_plus_dual = np.linalg.inv(vec_plus) eig_dummy[0,:] = eig eig_all = np.append(eig_all, eig_dummy, axis=0) # append all eigenvalues to array # loop to check find the eigenvalues that crosses zero from negative to positive values: for k in range(self.npw): for m in range(self.npw): if eig[k]< 0 and 0 < eig_plus[m]: # check it's the same mode - Overlap between eigenvectors should be large: if abs(np.inner(vec[:,k], vec_plus_dual[m,:])) > 0.95: self.printtxt('crossing found at w = %1.1f eV'%self.w_w[i-1]) eig_left = np.append(eig_left, eig[k]) eig_right = np.append(eig_right, eig_plus[m]) vec_dummy[0, :] = vec[:,k] vec_modes = np.append(vec_modes, vec_dummy, axis = 0) vec_dummy[0, :] = vec_dual[k, :].T vec_modes_dual = np.append(vec_modes_dual, vec_dummy, axis = 0) w1 = self.w_w[i-1] w2 = self.w_w[i] a = np.real((eig_plus[m]-eig[k]) / (w2-w1)) w0 = np.real(-eig[k]) / a + w1 eig0 = a*(w0-w1)+eig[k] w_0 = np.append(w_0,w0) w_left = np.append(w_left, w1) eig_0 = np.append(eig_0,eig0) n_dummy = np.zeros([1, r.shape[1], r.shape[2], r.shape[3]], dtype = complex) v_dummy = np.zeros([1, r.shape[1], r.shape[2], r.shape[3]], dtype = complex) vec_n = np.zeros([self.npw]) for iG in range(self.npw): # Fourier transform qG = np.dot((q + self.Gvec_Gc[iG]), self.bcell_cv) coef_G = np.dot(qG, qG) / (4 * pi) qGr_R = np.inner(qG, r.T).T v_dummy += vec[iG, k] * np.exp(1j * qGr_R) n_dummy += vec[iG, k] * np.exp(1j * qGr_R) * coef_G if checkphase: # rotate eigenvectors in complex plane integral = np.zeros([81]) phases = np.linspace(0,2,81) for ip in range(81): v_int = v_dummy * np.exp(1j * pi * phases[ip]) integral[ip] = abs(np.imag(v_int)).sum() phase = phases[np.argsort(integral)][0] v_dummy *= np.exp(1j * pi * phase) n_dummy *= np.exp(1j * pi * phase) if sum == '2D': i_xyz = 3 v_dummy_z = np.zeros([1,v_dummy.shape[i_xyz]], dtype = complex) n_dummy_z = np.zeros([1,v_dummy.shape[i_xyz]], dtype = complex) v_dummy_z[0,:] = np.sum(np.sum(v_dummy, axis = 1), axis = 1)[0,:] n_dummy_z[0,:] = np.sum(np.sum(n_dummy, axis = 1), axis = 1)[0,:] v_ind = np.append(v_ind, v_dummy_z, axis=0) n_ind = np.append(n_ind, n_dummy_z, axis=0) elif sum == '1D': self.printtxt('1D sum not implemented') else : v_ind = np.append(v_ind, v_dummy, axis=0) n_ind = np.append(n_ind, n_dummy, axis=0) """ returns: grid points, frequency grid, all eigenvalues, mode energies, left point energies, mode eigenvalues, eigenvalues of left and right-side points, (mode eigenvectors, mode dual eigenvectors,) induced potential in real space, induced density in real space """ if return_full: return rrr, self.w_w, eig_all[1:], w_0, eig_0, w_left, eig_left, \ eig_right, vec_modes[1:], vec_modes_dual[1:], v_ind[1:], n_ind[1:] else: return rrr, self.w_w, eig_all[1:], w_0, eig_0, v_ind[1:], n_ind[1:] def project_chi_to_LCAO_pair_orbital(self, orb_MG): nLCAO = orb_MG.shape[0] N = np.zeros((self.Nw, nLCAO, nLCAO), dtype=complex) kcoulinv_GG = np.zeros((self.npw, self.npw)) for iG in range(self.npw): qG = np.dot(self.q_c + self.Gvec_Gc[iG], self.bcell_cv) kcoulinv_GG[iG, iG] = np.dot(qG, qG) kcoulinv_GG /= 4.*pi dm_wGG = self.get_RPA_dielectric_matrix() for mu in range(nLCAO): for nu in range(nLCAO): pairorb_R = orb_MG[mu] * orb_MG[nu] if not (pairorb_R * pairorb_R.conj() < 1e-10).all(): tmp_G = np.fft.fftn(pairorb_R) * self.vol / self.nG0 pairorb_G = np.zeros(self.npw, dtype=complex) for iG in range(self.npw): index = self.Gindex[iG] pairorb_G[iG] = tmp_G[index[0], index[1], index[2]] for iw in range(self.Nw): chi_GG = (dm_wGG[iw] - np.eye(self.npw)) * kcoulinv_GG N[iw, mu, nu] = (np.outer(pairorb_G.conj(), pairorb_G) * chi_GG).sum() # N[iw, mu, nu] = np.inner(pairorb_G.conj(),np.inner(pairorb_G, chi_GG)) return N def write(self, filename, all=False): """Dump essential data""" data = {'nbands': self.nbands, 'acell': self.acell_cv, #* Bohr, 'bcell': self.bcell_cv, #/ Bohr, 'h_cv' : self.gd.h_cv, #* Bohr, 'nG' : self.gd.N_c, 'nG0' : self.nG0, 'vol' : self.vol, #* Bohr**3, 'BZvol': self.BZvol, #/ Bohr**3, 'nkpt' : self.kd.nbzkpts, 'ecut' : self.ecut, #* Hartree, 'npw' : self.npw, 'eta' : self.eta, #* Hartree, 'ftol' : self.ftol, 'Nw' : self.Nw, 'NwS' : self.NwS, 'dw' : self.dw, # * Hartree, 'q_red': self.q_c, 'q_car': self.qq_v, # / Bohr, 'qmod' : np.dot(self.qq_v, self.qq_v), # / Bohr 'vcut' : self.vcut, 'pbc' : self.pbc, 'nvalence' : self.nvalence, 'hilbert_trans' : self.hilbert_trans, 'optical_limit' : self.optical_limit, 'e_skn' : self.e_skn, # * Hartree, 'f_skn' : self.f_skn, 'bzk_kc' : self.kd.bzk_kc, 'ibzk_kc' : self.kd.ibzk_kc, 'kq_k' : self.kq_k, 'Gvec_Gc' : self.Gvec_Gc, 'dfNLFRPA_w' : self.df1_w, 'dfLFCRPA_w' : self.df2_w, 'dfNLFALDA_w' : self.df3_w, 'dfLFCALDA_w' : self.df4_w, 'df_flag' : True} if all: from gpaw.response.parallel import par_write par_write('chi0' + filename,'chi0_wGG',self.wcomm,self.chi0_wGG) if rank == 0: pickle.dump(data, open(filename, 'w'), -1) self.comm.barrier() def read(self, filename): """Read data from pickle file""" data = pickle.load(open(filename)) self.nbands = data['nbands'] self.acell_cv = data['acell'] self.bcell_cv = data['bcell'] self.nG0 = data['nG0'] self.vol = data['vol'] self.BZvol = data['BZvol'] self.ecut = data['ecut'] self.npw = data['npw'] self.eta = data['eta'] self.ftol = data['ftol'] self.Nw = data['Nw'] self.NwS = data['NwS'] self.dw = data['dw'] self.q_c = data['q_red'] self.qq_v = data['q_car'] self.qmod = data['qmod'] #self.vcut = data['vcut'] #self.pbc = data['pbc'] self.hilbert_trans = data['hilbert_trans'] self.optical_limit = data['optical_limit'] self.e_skn = data['e_skn'] self.f_skn = data['f_skn'] self.nvalence= data['nvalence'] self.kq_k = data['kq_k'] self.Gvec_Gc = data['Gvec_Gc'] self.df1_w = data['dfNLFRPA_w'] self.df2_w = data['dfLFCRPA_w'] self.df3_w = data['dfNLFALDA_w'] self.df4_w = data['dfLFCALDA_w'] self.df_flag = data['df_flag'] self.printtxt('Read succesfully !') gpaw-0.11.0.13004/gpaw/response/cell.py0000664000175000017500000000436112553643470017545 0ustar jensjjensj00000000000000import numpy as np from math import sqrt, pi def get_primitive_cell(a, rpad=None): """From the unit cell, calculate primitive cell and volume. """ if rpad is None: rpad = np.ones(3, int) a = (a.T * rpad).T # ??? vol = np.abs(np.dot(a[0], np.cross(a[1], a[2]))) BZvol = (2. * pi)**3 / vol b = np.linalg.inv(a.T) b *= 2 * pi assert np.abs((np.dot(b.T, a) - 2.*pi*np.eye(3)).sum()) < 1e-10 return a, b, vol, BZvol def set_Gvectors(acell, bcell, nG, Ecut, q=[0., 0., 0.]): """Calculate the number of planewaves with a certain cutoff, their reduced coordinates and index.""" # Refer to R.Martin P85 Gmax = np.zeros(3, dtype=int) Gcut = np.zeros(3, dtype=float) for i in range(3): a = acell[i] Gcut[i] = sqrt(2*Ecut[i]) if Gcut[i] > 0: Gmax[i] = sqrt(a[0]**2 + a[1]**2 + a[2]**2) * Gcut[i] / (2*pi) + 1 Nmax = np.ones([3], dtype = int) for dim in range(3): if Gcut[dim] > 0: Nmax[dim] = 2 * Gmax[dim] + 2 #assert (nG - Nmax >=0).all() # to prevent too many planewaves m = {} for dim in range(3): m[dim] = np.zeros(Nmax[dim],dtype=int) for i in range(Nmax[dim]): m[dim][i] = i if m[dim][i] > np.int(Gmax[dim]): m[dim][i] = i - Nmax[dim] G = np.zeros((Nmax[0]*Nmax[1]*Nmax[2],3),dtype=int) n = 0 for i in range(Nmax[0]): for j in range(Nmax[1]): for k in range(Nmax[2]): tmp = np.array([m[0][i], m[1][j], m[2][k]]) tmpG = np.dot(tmp+np.array(q), bcell) Gmod = 0 for dim in range(3): if Gcut[dim] > 0: Gmod += tmpG[dim]**2/Gcut[dim]**2 if Gmod < 1: G[n] = tmp n += 1 npw = n Gvec = G[:n] Gindex = np.zeros(npw, dtype=int) id = np.zeros(3, dtype=int) for iG in range(npw): G = Gvec[iG] for dim in range(3): if G[dim] >= 0: id[dim] = G[dim] else: id[dim] = nG[dim] - np.abs(G[dim]) Gindex[iG] = id[0]*nG[1]*nG[2] + id[1]*nG[2] + id[2] return npw, Gvec, Gindex gpaw-0.11.0.13004/gpaw/response/tool.py0000664000175000017500000001230312553643470017576 0ustar jensjjensj00000000000000import numpy as np from scipy.optimize import leastsq import pylab as pl def check_degenerate_bands(filename, etol): from gpaw import GPAW calc = GPAW(filename,txt=None) print('Number of Electrons :', calc.get_number_of_electrons()) nibzkpt = calc.get_ibz_k_points().shape[0] nbands = calc.get_number_of_bands() print('Number of Bands :', nbands) print('Number of ibz-kpoints :', nibzkpt) e_kn = np.array([calc.get_eigenvalues(k) for k in range(nibzkpt)]) f_kn = np.array([calc.get_occupation_numbers(k) for k in range(nibzkpt)]) for k in range(nibzkpt): for n in range(1,nbands): if (f_kn[k,n-1] - f_kn[k,n] > 1e-5) and (np.abs(e_kn[k,n] - e_kn[k,n-1]) < etol): print(k, n, e_kn[k,n], e_kn[k, n-1]) return def get_orbitals(calc): """Get LCAO orbitals on 3D grid by lcao_to_grid method.""" bfs_a = [setup.phit_j for setup in calc.wfs.setups] from gpaw.lfc import BasisFunctions bfs = BasisFunctions(calc.wfs.gd, bfs_a, calc.wfs.kd.comm, cut=True) spos_ac = calc.atoms.get_scaled_positions() bfs.set_positions(spos_ac) nLCAO = calc.get_number_of_bands() orb_MG = calc.wfs.gd.zeros(nLCAO) C_M = np.identity(nLCAO) bfs.lcao_to_grid(C_M, orb_MG,q=-1) return orb_MG def find_peaks(x,y,threshold = None): """ Find peaks for a certain curve. Usage: threshold = (xmin, xmax, ymin, ymax) """ assert isinstance(x, np.ndarray) and isinstance(y, np.ndarray) assert x.ndim == 1 and y.ndim == 1 assert x.shape[0] == y.shape[0] if threshold is None: threshold = (x.min(), x.max(), y.min(), y.max()) if not isinstance(threshold, tuple): threshold = (threshold, ) if len(threshold) == 1: threshold += (x.max(), y.min(), y.max()) elif len(threshold) == 2: threshold += (y.min(), y.max()) elif len(threshold) == 3: threshold += (y.max(),) else: pass xmin = threshold[0] xmax = threshold[1] ymin = threshold[2] ymax = threshold[3] peak = {} npeak = 0 for i in range(1, x.shape[0]-1): if (y[i] >= ymin and y[i] <= ymax and x[i] >= xmin and x[i] <= xmax ): if y[i] > y[i-1] and y[i] > y[i+1]: peak[npeak] = np.array([x[i], y[i]]) npeak += 1 peakarray = np.zeros([npeak, 2]) for i in range(npeak): peakarray[i] = peak[i] return peakarray def lorz_fit(x,y, npeak=1, initpara = None): """ Fit curve using Lorentzian function Note: currently only valid for one and two lorentizian The lorentzian function is defined as:: A w lorz = --------------------- + y0 (x-x0)**2 + w**2 where A is the peak amplitude, w is the width, (x0,y0) the peak position Parameters: x, y: ndarray Input data for analyze p: ndarray Parameters for curving fitting function. [A, x0, y0, w] p0: ndarray Parameters for initial guessing. similar to p """ def residual(p, x, y): err = y - lorz(x, p, npeak) return err def lorz(x, p, npeak): if npeak == 1: return p[0] * p[3] / ( (x-p[1])**2 + p[3]**2 ) + p[2] if npeak == 2: return ( p[0] * p[3] / ( (x-p[1])**2 + p[3]**2 ) + p[2] + p[4] * p[7] / ( (x-p[5])**2 + p[7]**2 ) + p[6] ) else: raise ValueError('Larger than 2 peaks not supported yet!') if initpara is None: if npeak == 1: initpara[i] = np.array([1., 0., 0., 0.1]) if npeak == 2: initpara[i] = np.array([1., 0., 0., 0.1, 3., 0., 0., 0.1]) p0 = initpara result = leastsq(residual, p0, args=(x, y), maxfev=2000) yfit = lorz(x, result[0],npeak) return yfit, result[0] def linear_fit(x,y, initpara = None): def residual(p, x, y): err = y - linear(x, p) return err def linear(x, p): return p[0]*x + p[1] if initpara is None: initpara = np.array([1.0,1.0]) p0 = initpara result = leastsq(residual, p0, args=(x, y), maxfev=2000) yfit = linear(x, result[0]) return yfit, result[0] def plot_setfont(): params = { 'axes.labelsize': 18, 'text.fontsize': 18, 'legend.fontsize': 18, 'xtick.labelsize': 18, 'ytick.labelsize': 18, 'text.usetex': True} # 'figure.figsize': fig_size} pl.rcParams.update(params) def plot_setticks(x=True, y=True): pl.minorticks_on() ax = pl.gca() if x: ax.xaxis.set_major_locator(pl.AutoLocator()) x_major = ax.xaxis.get_majorticklocs() dx_minor = (x_major[-1]-x_major[0])/(len(x_major)-1) /5. ax.xaxis.set_minor_locator(pl.MultipleLocator(dx_minor)) else: pl.minorticks_off() if y: ax.yaxis.set_major_locator(pl.AutoLocator()) y_major = ax.yaxis.get_majorticklocs() dy_minor = (y_major[-1]-y_major[0])/(len(y_major)-1) /5. ax.yaxis.set_minor_locator(pl.MultipleLocator(dy_minor)) else: pl.minorticks_off() gpaw-0.11.0.13004/gpaw/response/gw0.py0000664000175000017500000000313212553643470017316 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from gpaw.response.g0w0 import G0W0 class GW0(G0W0): def __init__(self, calc, filename='gw0', **kwargs): G0W0.__init__(self, calc, filename, savew=True, **kwargs) try: self.qp_xsin = np.load(filename + '-gw0.npy') except IOError: self.qp_xsin = np.empty((1,) + self.shape) self.iteration = len(self.qp_xsin) def get_k_point(self, s, K, n1, n2): kpt = G0W0.get_k_point(self, s, K, n1, n2) if self.iteration > 1: b1, b2 = self.bands m1 = max(b1, n1) m2 = min(b2, n2) if m2 > m1: k = self.calc.wfs.kd.bz2ibz_k[K] i = self.kpts.index(k) qp_n = self.qp_xsin[-1, s, i, m1 - b1:m2 - b1] kpt.eps_n[m1 - n1:m2 - n1] = qp_n return kpt def update_qp_energies(self): print('Iteration:', self.iteration, file=self.fd) if self.iteration == 1: self.qp_xsin[0] = self.eps_sin self.Z_sin = 1 / (1 - self.dsigma_sin) self.qp_sin = self.eps_sin + self.Z_sin * ( self.sigma_sin + self.exx_sin - self.vxc_sin) self.iteration += 1 qp_xsin = np.empty((self.iteration,) + self.shape) qp_xsin[:-1] = self.qp_xsin qp_xsin[-1] = self.qp_sin self.qp_xsin = qp_xsin if self.world.rank == 0: with open(self.filename + '.qp.npy', 'w') as fd: np.save(fd, self.qp_xsin) gpaw-0.11.0.13004/gpaw/response/bse.py0000664000175000017500000010327012553643470017376 0ustar jensjjensj00000000000000from __future__ import print_function import pickle from math import pi from time import time, ctime import numpy as np from ase.io import write from ase.units import Hartree from ase.utils import opencew from gpaw.response.df0 import DF from gpaw.io.tar import Writer, Reader from gpaw.response.base import BASECHI from gpaw.utilities.memory import maxrss from gpaw.blacs import BlacsGrid, Redistributor from gpaw.mpi import world, size, rank, serial_comm from gpaw.response.kernel import calculate_Kc, calculate_Kc_q from gpaw.response.parallel import parallel_partition, gatherv class BSE(BASECHI): """This class defines Bethe-Salpeter equations.""" def __init__(self, calc=None, nbands=None, nc=None, nv=None, w=None, q=None, eshift=None, ecut=10., eta=0.2, gw_skn=None, # GW QP energies in Hartree rpad=None, vcut=None, # Coulomb cutoff only 2D works ftol=1e-5, txt=None, optical_limit=None, integrate_coulomb=None, print_coulomb=False, coupling=False, # False : use Tamm-Dancoff Approx mode='BSE', # BSE, TDHF or RPA kernel_file=None,#'W_qGG', qsymm=True): BASECHI.__init__(self, calc=calc, nbands=nbands, w=w, q=q, eshift=eshift, ecut=ecut, eta=eta, rpad=rpad, ftol=ftol, txt=txt, optical_limit=optical_limit) assert mode in ['RPA', 'TDHF', 'BSE'] self.epsilon_w = None self.coupling = coupling self.vcut = vcut self.nc = nc # conduction band index self.nv = nv # valence band index self.gw_skn = gw_skn self.mode = mode self.integrate_coulomb = integrate_coulomb self.print_coulomb = print_coulomb self.kernel_file = kernel_file self.qsymm = qsymm def initialize(self): self.printtxt('----------------------------------------') self.printtxt('Bethe-Salpeter Equation calculation') self.printtxt('----------------------------------------') self.printtxt('Started at: %s' % ctime()) self.printtxt('') BASECHI.initialize(self) assert self.nspins == 1 calc = self.calc self.kd = kd = calc.wfs.kd # frequency points init self.dw = self.w_w[1] - self.w_w[0] assert ((self.w_w[1:] - self.w_w[:-1] - self.dw) < 1e-10).all() # make sure its linear w grid assert self.w_w.max() == self.w_w[-1] self.dw /= Hartree self.w_w /= Hartree self.wmax = self.w_w[-1] self.Nw = int(self.wmax / self.dw) + 1 # band init if self.nc is None: nv = self.nvalence / 2 - 1 self.nv = np.array([nv, nv+1]) # conduction band start / end self.nc = np.array([nv+1, nv+2]) # valence band start / end self.printtxt('') self.printtxt('Number of electrons : %d' % (self.nvalence)) self.printtxt('Valence band included : (band %d to band %d)' %(self.nv[0], self.nv[1]-1)) self.printtxt('Conduction band included : (band %d to band %d)' %(self.nc[0], self.nc[1]-1)) if self.eshift is not None: self.printtxt('Scissors operator : %2.3f eV' % self.eshift) self.printtxt('') # find the pair index and initialized pair energy (e_i - e_j) and occupation(f_i-f_j) self.e_S = {} focc_s = {} self.Sindex_S3 = {} iS = 0 kq_k = self.kq_k for k1 in range(self.kd.nbzkpts): ibzkpt1 = kd.bz2ibz_k[k1] ibzkpt2 = kd.bz2ibz_k[kq_k[k1]] for n1 in range(self.nv[0], self.nv[1]): for m1 in range(self.nc[0], self.nc[1]): focc = self.f_skn[0][ibzkpt1,n1] - self.f_skn[0][ibzkpt2,m1] if self.coupling: # Dont use Tamm-Dancoff Approx. check_ftol = np.abs(focc) > self.ftol else: check_ftol = focc > self.ftol if check_ftol: if self.gw_skn is None: self.e_S[iS] = self.e_skn[0][ibzkpt2,m1] - self.e_skn[0][ibzkpt1,n1] else: self.e_S[iS] = self.gw_skn[0][ibzkpt2,m1] - self.gw_skn[0][ibzkpt1,n1] focc_s[iS] = focc self.Sindex_S3[iS] = (k1, n1, m1) iS += 1 self.nS = iS self.focc_S = np.zeros(self.nS) for iS in range(self.nS): self.focc_S[iS] = focc_s[iS] # q points init self.bzq_qc = kd.get_bz_q_points() if not self.qsymm: self.ibzq_qc = self.bzq_qc else: (self.ibzq_qc, self.ibzq_q, self.iop_q, self.timerev_q, self.diff_qc) = kd.get_ibz_q_points(self.bzq_qc, calc.wfs.kd.symmetry.op_scc) if np.abs(self.bzq_qc - kd.bzk_kc).sum() < 1e-8: assert np.abs(self.ibzq_qc - kd.ibzk_kc).sum() < 1e-8 self.nibzq = len(self.ibzq_qc) # Parallel initialization # kcomm and wScomm is only to be used when wavefunctions are distributed in parallel. self.comm = self.Scomm = world self.kcomm = world self.wScomm = serial_comm self.nS, self.nS_local, self.nS_start, self.nS_end = parallel_partition( self.nS, world.rank, world.size, reshape=False) self.print_bse() if calc.input_parameters['mode'] == 'lcao': calc.initialize_positions() # Coulomb interaction at q=0 for Hartree coupling ### 2D z direction only !!!!!!!!!!!!!!!!!!!!!! if self.integrate_coulomb is None: self.integrate_coulomb = [] if self.vcut is None: pass elif self.vcut == '2D': for iG in range(len(self.Gvec_Gc)): if self.Gvec_Gc[iG, 0] == 0 and self.Gvec_Gc[iG, 1] == 0: self.integrate_coulomb.append(iG) else: raise NotImplementedError elif isinstance(self.integrate_coulomb, int): self.integrate_coulomb = range(self.integrate_coulomb) elif self.integrate_coulomb == 'all': self.integrate_coulomb = range(len(self.Gvec_Gc)) elif isinstance(self.integrate_coulomb, list): pass else: raise 'Invalid option for integrate_coulomb' self.printtxt('') self.printtxt('Calculating bare Coulomb kernel') if not len(self.integrate_coulomb) == 0: self.printtxt('Integrating Coulomb kernel at %s reciprocal lattice vector(s)' % len(self.integrate_coulomb)) # Coulomb interaction at problematic G's for exchange coupling if len(self.integrate_coulomb) != 0: self.vint_Gq = [] for iG in self.integrate_coulomb: v_q, v0_q = calculate_Kc_q(self.acell_cv, self.bcell_cv, self.pbc, self.kd.N_c, vcut=self.vcut, Gvec_c=self.Gvec_Gc[iG], q_qc=self.ibzq_qc.copy()) self.vint_Gq.append(v_q) if self.print_coulomb: self.printtxt('') self.printtxt('Average kernel relative to bare kernel - \int v(q)dq / v(q0): ') self.printtxt(' G: % s' % self.Gvec_Gc[iG]) for iq in range(len(v_q)): q_s = ' q = [%1.2f, %1.2f, %1.2f]: ' % (self.ibzq_qc[iq,0], self.ibzq_qc[iq,1], self.ibzq_qc[iq,2]) v_rel = v_q[iq] / v0_q[iq] self.printtxt(q_s + '%1.3f' % v_rel) self.printtxt('') self.V_qGG = self.full_bare_interaction() def calculate(self): calc = self.calc focc_S = self.focc_S e_S = self.e_S op_scc = calc.wfs.kd.symmetry.op_scc # Get phi_qaGp if self.mode == 'RPA': self.phi_aGp = self.get_phi_aGp() else: fd = opencew('phi_qaGp') if fd is None: self.reader = Reader('phi_qaGp') tmp = self.load_phi_aGp(self.reader, 0)[0] assert len(tmp) == self.npw self.printtxt('Finished reading phi_aGp') else: self.printtxt('Calculating phi_qaGp') self.get_phi_qaGp() world.barrier() self.reader = Reader('phi_qaGp') self.printtxt('Memory used %f M' % (maxrss() / 1024.**2)) self.printtxt('') if self.optical_limit: iq = np.where(np.sum(abs(self.ibzq_qc), axis=1) < 1e-5)[0][0] else: iq = np.where(np.sum(abs(self.ibzq_qc - self.q_c), axis=1) < 1e-5)[0][0] kc_G = np.array([self.V_qGG[iq, iG, iG] for iG in range(self.npw)]) if self.optical_limit: kc_G[0] = 0. # Get screened Coulomb kernel if self.mode == 'BSE': try: # Read data = pickle.load(open(self.kernel_file+'.pckl')) W_qGG = data['W_qGG'] assert np.shape(W_qGG) == np.shape(self.V_qGG) self.printtxt('Finished reading screening interaction kernel') except: # Calculate from scratch self.printtxt('Calculating screening interaction kernel.') W_qGG = self.full_static_screened_interaction() self.printtxt('') else: W_qGG = self.V_qGG t0 = time() self.printtxt('Calculating %s matrix elements' % self.mode) # Calculate full kernel K_SS = np.zeros((self.nS_local, self.nS), dtype=complex) self.rhoG0_S = np.zeros(self.nS, dtype=complex) #noGmap = 0 for iS in range(self.nS_start, self.nS_end): k1, n1, m1 = self.Sindex_S3[iS] rho1_G = self.density_matrix(n1,m1,k1) self.rhoG0_S[iS] = rho1_G[0] for jS in range(self.nS): k2, n2, m2 = self.Sindex_S3[jS] rho2_G = self.density_matrix(n2,m2,k2) K_SS[iS-self.nS_start, jS] = np.sum(rho1_G.conj() * rho2_G * kc_G) if not self.mode == 'RPA': rho3_G = self.density_matrix(n1,n2,k1,k2) rho4_G = self.density_matrix(m1,m2,self.kq_k[k1], self.kq_k[k2]) q_c = self.kd.bzk_kc[k2] - self.kd.bzk_kc[k1] q_c[np.where(q_c > 0.501)] -= 1. q_c[np.where(q_c < -0.499)] += 1. iq = self.kd.where_is_q(q_c, self.bzq_qc) if not self.qsymm: W_GG = W_qGG[iq] else: ibzq = self.ibzq_q[iq] W_GG_tmp = W_qGG[ibzq] iop = self.iop_q[iq] timerev = self.timerev_q[iq] diff_c = self.diff_qc[iq] invop = np.linalg.inv(op_scc[iop]) Gindex = np.zeros(self.npw, dtype=int) for iG in range(self.npw): G_c = self.Gvec_Gc[iG] if timerev: RotG_c = -np.int8(np.dot(invop, G_c+diff_c).round()) else: RotG_c = np.int8(np.dot(invop, G_c+diff_c).round()) tmp_G = np.abs(self.Gvec_Gc - RotG_c).sum(axis=1) try: Gindex[iG] = np.where(tmp_G < 1e-5)[0][0] except: #noGmap += 1 Gindex[iG] = -1 W_GG = np.zeros_like(W_GG_tmp) for iG in range(self.npw): for jG in range(self.npw): if Gindex[iG] == -1 or Gindex[jG] == -1: W_GG[iG, jG] = 0 else: W_GG[iG, jG] = W_GG_tmp[Gindex[iG], Gindex[jG]] if self.mode == 'BSE': tmp_GG = np.outer(rho3_G.conj(), rho4_G) * W_GG K_SS[iS-self.nS_start, jS] -= 0.5 * np.sum(tmp_GG) else: tmp_G = rho3_G.conj() * rho4_G * np.diag(W_GG) K_SS[iS-self.nS_start, jS] -= 0.5 * np.sum(tmp_G) self.timing(iS, t0, self.nS_local, 'pair orbital') K_SS /= self.vol world.sum(self.rhoG0_S) #self.printtxt('Number of G indices outside the Gvec_Gc: %d' % noGmap) # Get and solve Hamiltonian H_sS = np.zeros_like(K_SS) for iS in range(self.nS_start, self.nS_end): H_sS[iS-self.nS_start,iS] = e_S[iS] for jS in range(self.nS): H_sS[iS-self.nS_start,jS] += focc_S[iS] * K_SS[iS-self.nS_start,jS] # Force matrix to be Hermitian if not self.coupling: if world.size > 1: H_Ss = self.redistribute_H(H_sS) else: H_Ss = H_sS H_sS = (np.real(H_sS) + np.real(H_Ss.T)) / 2. + 1j * (np.imag(H_sS) - np.imag(H_Ss.T)) /2. # Save H_sS matrix self.par_save('H_SS','H_SS', H_sS) return H_sS def diagonalize(self, H_sS): if self.coupling: # Non-Hermitian matrix can only use linalg.eig self.printtxt('Use numpy.linalg.eig') H_SS = np.zeros((self.nS, self.nS), dtype=complex) if self.nS % world.size == 0: world.all_gather(H_sS, H_SS) else: H_SS = gatherv(H_sS) self.w_S, self.v_SS = np.linalg.eig(H_SS) self.par_save('v_SS', 'v_SS', self.v_SS[self.nS_start:self.nS_end, :].copy()) else: if world.size == 1: self.printtxt('Use lapack.') from gpaw.utilities.lapack import diagonalize self.w_S = np.zeros(self.nS) H_SS = H_sS diagonalize(H_SS, self.w_S) self.v_SS = H_SS.conj() # eigenvectors in the rows, transposed later else: self.printtxt('Use scalapack') self.w_S, self.v_sS = self.scalapack_diagonalize(H_sS) self.v_SS = self.v_sS # just use the same name self.par_save('v_SS', 'v_SS', self.v_SS) return def par_save(self,filename, name, A_sS): from gpaw.io import open nS = self.nS if rank == 0: w = open(filename, 'w', world) w.dimension('nS', nS) if name == 'v_SS': w.add('w_S', ('nS',), dtype=self.w_S.dtype) w.fill(self.w_S) w.add('rhoG0_S', ('nS',), dtype=complex) w.fill(self.rhoG0_S) w.add(name, ('nS', 'nS'), dtype=complex) tmp = np.zeros_like(A_sS) # Assumes that H_SS is written in order from rank 0 - rank N for irank in range(size): if irank == 0: if rank == 0: w.fill(A_sS) else: if rank == irank: world.send(A_sS, 0, irank+100) if rank == 0: world.receive(tmp, irank, irank+100) w.fill(tmp) if rank == 0: w.close() world.barrier() def par_load(self,filename, name): from gpaw.io import open r = open(filename, 'r') nS = r.dimension('nS') if name == 'v_SS': self.w_S = r.get('w_S') A_SS = np.zeros((self.nS_local, nS), dtype=complex) for iS in range(self.nS_start, self.nS_end): A_SS[iS-self.nS_start,:] = r.get(name, iS) self.rhoG0_S = r.get('rhoG0_S') r.close() return A_SS def full_static_screened_interaction(self): """Calcuate W_GG(q)""" W_qGG = np.zeros((self.nibzq, self.npw, self.npw), dtype=complex) t0 = time() for iq in range(self.nibzq): q = self.ibzq_qc[iq] optical_limit = False if np.abs(q).sum() < 1e-8: q = np.array([0.0001, 0, 0]) optical_limit = True df = DF(calc=self.calc, q=q, w=(0.,), optical_limit=optical_limit, nbands=self.nbands, hilbert_trans=False, eta=0.0001, ecut=self.ecut*Hartree, xc='RPA', txt='df.out') df.initialize() df.calculate() if optical_limit: K_GG = self.V_qGG[iq].copy() K0 = calculate_Kc(q, self.Gvec_Gc, self.acell_cv, self.bcell_cv, self.pbc, vcut=self.vcut)[0,0] for iG in range(1,self.npw): K_GG[0, iG] = self.V_qGG[iq, iG, iG]**0.5 * K0**0.5 K_GG[iG, 0] = self.V_qGG[iq, iG, iG]**0.5 * K0**0.5 K_GG[0,0] = K0 df_GG = np.eye(self.npw, self.npw) - K_GG*df.chi0_wGG[0] else: df_GG = np.eye(self.npw, self.npw) - self.V_qGG[iq]*df.chi0_wGG[0] dfinv_GG = np.linalg.inv(df_GG) if optical_limit: eps = 1/dfinv_GG[0,0] self.printtxt(' RPA macroscopic dielectric constant is: %3.3f' % eps.real) W_qGG[iq] = dfinv_GG * self.V_qGG[iq] self.timing(iq, t0, self.nibzq, 'iq') if rank == 0: if self.kernel_file is not None: data = {'W_qGG': W_qGG} name = self.kernel_file+'.pckl' pickle.dump(data, open(name, 'w'), -1) return W_qGG def full_bare_interaction(self): """Calculate V_GG(q)""" V_qGG = np.zeros((self.nibzq, self.npw, self.npw), dtype=complex) for iq in range(self.nibzq): q = self.ibzq_qc[iq] Vq_G = np.diag(calculate_Kc(q, self.Gvec_Gc, self.acell_cv, self.bcell_cv, self.pbc, integrate_gamma=True, N_k=self.kd.N_c, vcut=self.vcut))**0.5 for i, iG in enumerate(self.integrate_coulomb): Vq_G[iG] = self.vint_Gq[i][iq]**0.5 V_qGG[iq] = np.outer(Vq_G, Vq_G) return V_qGG def print_bse(self): printtxt = self.printtxt if not self.mode == 'RPA': printtxt('Number of q points : %d' %(self.nibzq)) printtxt('Number of frequency points : %d' %(self.Nw) ) printtxt('Number of pair orbitals : %d' %(self.nS) ) printtxt('') printtxt('Parallelization scheme:') printtxt(' Total cpus : %d' %(world.size)) printtxt(' pair orb parsize : %d' %(self.Scomm.size)) return def get_phi_qaGp(self): N1_max = 0 N2_max = 0 natoms = len(self.calc.wfs.setups) for id in range(natoms): N1 = self.npw N2 = self.calc.wfs.setups[id].ni**2 if N1 > N1_max: N1_max = N1 if N2 > N2_max: N2_max = N2 nbzq = self.kd.nbzkpts nbzq, nq_local, q_start, q_end = parallel_partition( nbzq, world.rank, world.size, reshape=False) phimax_qaGp = np.zeros((nq_local, natoms, N1_max, N2_max), dtype=complex) #phimax_qaGp = np.zeros((nbzq, natoms, N1_max, N2_max), dtype=complex) t0 = time() for iq in range(nq_local): q_c = self.bzq_qc[iq + q_start] tmp_aGp = self.get_phi_aGp(q_c, parallel=False) for id in range(natoms): N1, N2 = tmp_aGp[id].shape phimax_qaGp[iq, id, :N1, :N2] = tmp_aGp[id] self.timing(iq*world.size, t0, nq_local, 'iq') world.barrier() # Write to disk filename = 'phi_qaGp' if world.rank == 0: w = Writer(filename) w.dimension('nbzq', nbzq) w.dimension('natoms', natoms) w.dimension('nG', N1_max) w.dimension('nii', N2_max) w.add('phi_qaGp', ('nbzq', 'natoms', 'nG', 'nii',), dtype=complex) for q in range(nbzq): residual = nbzq % size N_local = nbzq // size if q < residual * (N_local + 1): qrank = q // (N_local + 1) else: qrank = (q - residual * (N_local + 1)) // N_local + residual if qrank == 0: if world.rank == 0: phi_aGp = phimax_qaGp[q - q_start] else: if world.rank == qrank: phi_aGp = phimax_qaGp[q - q_start] world.send(phi_aGp, 0, q) elif world.rank == 0: world.receive(phi_aGp, qrank, q) if world.rank == 0: w.fill(phi_aGp) if world.rank == 0: w.close() world.barrier() def load_phi_aGp(self, reader, iq): phimax_aGp = np.array(reader.get('phi_qaGp', iq), complex) phi_aGp = {} natoms = len(phimax_aGp) for a in range(natoms): N1 = self.npw N2 = self.calc.wfs.setups[a].ni**2 phi_aGp[a] = phimax_aGp[a, :N1, :N2] return phi_aGp def get_dielectric_function(self, filename='df.dat', readfile=None): if self.epsilon_w is None: self.initialize() if readfile is None: H_sS = self.calculate() self.printtxt('Diagonalizing %s matrix.' % self.mode) self.diagonalize(H_sS) self.printtxt('Calculating dielectric function.') elif readfile == 'H_SS': H_sS = self.par_load('H_SS', 'H_SS') self.printtxt('Finished reading H_SS.gpw') self.diagonalize(H_sS) self.printtxt('Finished diagonalizing BSE matrix') elif readfile == 'v_SS': self.v_SS = self.par_load('v_SS', 'v_SS') self.printtxt('Finished reading v_SS.gpw') else: 1 / 0 w_S = self.w_S if not self.coupling: v_SS = self.v_SS.T # v_SS[:,lamda] else: v_SS = self.v_SS rhoG0_S = self.rhoG0_S focc_S = self.focc_S # get overlap matrix if self.coupling: tmp = np.dot(v_SS.conj().T, v_SS ) overlap_SS = np.linalg.inv(tmp) # get chi epsilon_w = np.zeros(self.Nw, dtype=complex) A_S = np.dot(rhoG0_S, v_SS) B_S = np.dot(rhoG0_S*focc_S, v_SS) if self.coupling: C_S = np.dot(B_S.conj(), overlap_SS.T) * A_S else: if world.size == 1: C_S = B_S.conj() * A_S else: tmp = B_S.conj() * A_S C_S = gatherv(tmp, self.nS) for iw in range(self.Nw): tmp_S = 1. / (iw*self.dw - w_S + 1j*self.eta) epsilon_w[iw] += np.dot(tmp_S, C_S) epsilon_w *= - 4 * pi / np.inner(self.qq_v, self.qq_v) / self.vol epsilon_w += 1 self.epsilon_w = epsilon_w if rank == 0: f = open(filename, 'w') for iw in range(self.Nw): energy = iw * self.dw * Hartree print(energy, np.real(epsilon_w[iw]), np.imag(epsilon_w[iw]), file=f) f.close() #g.close() # Wait for I/O to finish world.barrier() """Check f-sum rule.""" N1 = 0 for iw in range(self.Nw): w = iw * self.dw N1 += np.imag(epsilon_w[iw]) * w N1 *= self.dw * self.vol / (2 * pi**2) self.printtxt('') self.printtxt('Sum rule:') nv = self.nvalence self.printtxt('N1 = %f, %f %% error' %(N1, (N1 - nv) / nv * 100) ) return epsilon_w def get_e_h_density(self, lamda=None, filename=None): if filename is not None: self.load(filename) self.initialize() gd = self.gd v_SS = self.v_SS A_S = v_SS[:, lamda] kq_k = self.kq_k kd = self.kd # Electron density nte_R = gd.zeros() for iS in range(self.nS_start, self.nS_end): print('electron density:', iS) k1, n1, m1 = self.Sindex_S3[iS] ibzkpt1 = kd.bz2ibz_k[k1] psitold_g = self.get_wavefunction(ibzkpt1, n1) psit1_g = kd.transform_wave_function(psitold_g, k1) for jS in range(self.nS): k2, n2, m2 = self.Sindex_S3[jS] if m1 == m2 and k1 == k2: psitold_g = self.get_wavefunction(ibzkpt1, n2) psit2_g = kd.transform_wave_function(psitold_g, k1) nte_R += A_S[iS] * A_S[jS].conj() * psit1_g.conj() * psit2_g # Hole density nth_R = gd.zeros() for iS in range(self.nS_start, self.nS_end): print('hole density:', iS) k1, n1, m1 = self.Sindex_S3[iS] ibzkpt1 = kd.bz2ibz_k[kq_k[k1]] psitold_g = self.get_wavefunction(ibzkpt1, m1) psit1_g = kd.transform_wave_function(psitold_g, kq_k[k1]) for jS in range(self.nS): k2, n2, m2 = self.Sindex_S3[jS] if n1 == n2 and k1 == k2: psitold_g = self.get_wavefunction(ibzkpt1, m2) psit2_g = kd.transform_wave_function(psitold_g, kq_k[k1]) nth_R += A_S[iS] * A_S[jS].conj() * psit1_g * psit2_g.conj() self.Scomm.sum(nte_R) self.Scomm.sum(nth_R) if rank == 0: write('rho_e.cube',self.calc.atoms, format='cube', data=nte_R) write('rho_h.cube',self.calc.atoms, format='cube', data=nth_R) world.barrier() return def get_excitation_wavefunction(self, lamda=None,filename=None, re_c=None, rh_c=None): """ garbage at the moment. come back later""" if filename is not None: self.load(filename) self.initialize() gd = self.gd v_SS = self.v_SS A_S = v_SS[:, lamda] kq_k = self.kq_k kd = self.kd nx, ny, nz = self.gd.N_c nR = 9 nR2 = (nR - 1 ) // 2 if re_c is not None: psith_R = gd.zeros(dtype=complex) psith2_R = np.zeros((nR*nx, nR*ny, nz), dtype=complex) elif rh_c is not None: psite_R = gd.zeros(dtype=complex) psite2_R = np.zeros((nR*nx, ny, nR*nz), dtype=complex) else: self.printtxt('No wavefunction output !') return for iS in range(self.nS_start, self.nS_end): k, n, m = self.Sindex_S3[iS] ibzkpt1 = kd.bz2ibz_k[k] ibzkpt2 = kd.bz2ibz_k[kq_k[k]] print('hole wavefunction', iS, (k,n,m),A_S[iS]) psitold_g = self.get_wavefunction(ibzkpt1, n) psit1_g = kd.transform_wave_function(psitold_g, k) psitold_g = self.get_wavefunction(ibzkpt2, m) psit2_g = kd.transform_wave_function(psitold_g, kq_k[k]) if re_c is not None: # given electron position, plot hole wavefunction tmp = A_S[iS] * psit1_g[re_c].conj() * psit2_g psith_R += tmp k_c = self.kd.bzk_kc[k] + self.q_c for i in range(nR): for j in range(nR): R_c = np.array([i-nR2, j-nR2, 0]) psith2_R[i*nx:(i+1)*nx, j*ny:(j+1)*ny, 0:nz] += \ tmp * np.exp(1j*2*pi*np.dot(k_c,R_c)) elif rh_c is not None: # given hole position, plot electron wavefunction tmp = A_S[iS] * psit1_g.conj() * psit2_g[rh_c] * self.expqr_g psite_R += tmp k_c = self.kd.bzk_kc[k] k_v = np.dot(k_c, self.bcell_cv) for i in range(nR): for j in range(nR): R_c = np.array([i-nR2, 0, j-nR2]) R_v = np.dot(R_c, self.acell_cv) assert np.abs(np.dot(k_v, R_v) - np.dot(k_c, R_c) * 2*pi).sum() < 1e-5 psite2_R[i*nx:(i+1)*nx, 0:ny, j*nz:(j+1)*nz] += \ tmp * np.exp(-1j*np.dot(k_v,R_v)) else: pass if re_c is not None: self.Scomm.sum(psith_R) self.Scomm.sum(psith2_R) if rank == 0: write('psit_h.cube',self.calc.atoms, format='cube', data=psith_R) atoms = self.calc.atoms shift = atoms.cell[0:2].copy() atoms.cell[0:2] *= nR2 atoms.positions += shift * (nR2 - 1) write('psit_bigcell_h.cube',atoms, format='cube', data=psith2_R) elif rh_c is not None: self.Scomm.sum(psite_R) self.Scomm.sum(psite2_R) if rank == 0: write('psit_e.cube',self.calc.atoms, format='cube', data=psite_R) atoms = self.calc.atoms # shift = atoms.cell[0:2].copy() atoms.cell[0:2] *= nR2 # atoms.positions += shift * (nR2 - 1) write('psit_bigcell_e.cube',atoms, format='cube', data=psite2_R) else: pass world.barrier() return def load(self, filename): data = pickle.load(open(filename)) self.w_S = data['w_S'] self.v_SS = data['v_SS'] self.printtxt('Read succesfully !') def save(self, filename): """Dump essential data""" data = {'w_S' : self.w_S, 'v_SS' : self.v_SS} if rank == 0: pickle.dump(data, open(filename, 'w'), -1) world.barrier() def redistribute_H(self, H_sS): g1 = BlacsGrid(world, size, 1) g2 = BlacsGrid(world, 1, size) N = self.nS nndesc1 = g1.new_descriptor(N, N, self.nS_local, N) nndesc2 = g2.new_descriptor(N, N, N, self.nS_local) H_Ss = nndesc2.empty(dtype=H_sS.dtype) redistributor = Redistributor(world, nndesc1, nndesc2) redistributor.redistribute(H_sS, H_Ss) return H_Ss def scalapack_diagonalize(self, H_sS): mb = 32 N = self.nS g1 = BlacsGrid(world, size, 1) g2 = BlacsGrid(world, size//2, 2) nndesc1 = g1.new_descriptor(N, N, self.nS_local, N) nndesc2 = g2.new_descriptor(N, N, mb, mb) A_ss = nndesc2.empty(dtype=H_sS.dtype) redistributor = Redistributor(world, nndesc1, nndesc2) redistributor.redistribute(H_sS, A_ss) # diagonalize v_ss = nndesc2.zeros(dtype=A_ss.dtype) w_S = np.zeros(N,dtype=float) nndesc2.diagonalize_dc(A_ss, v_ss, w_S, 'L') # distribute the eigenvectors to master v_sS = np.zeros_like(H_sS) redistributor = Redistributor(world, nndesc2, nndesc1) redistributor.redistribute(v_ss, v_sS) # v2_SS = np.zeros((self.nS, self.nS), dtype=complex) # world.all_gather(v_sS, v2_SS) return w_S, v_sS.conj() """ def get_chi(self, w): H_SS = self.calculate() self.printtxt('Diagonalizing BSE matrix.') self.diagonalize(H_SS) self.printtxt('Calculating BSE response function.') w_S = self.w_S if not self.coupling: v_SS = self.v_SS.T # v_SS[:,lamda] else: v_SS = self.v_SS rhoG0_S = self.rhoG0_S focc_S = self.focc_S # get overlap matrix if self.coupling: tmp = np.dot(v_SS.conj().T, v_SS ) overlap_SS = np.linalg.inv(tmp) # get chi chi_wGG = np.zeros((len(w), self.npw, self.npw), dtype=complex) t0 = time() A_S = np.dot(rhoG0_S, v_SS) B_S = np.dot(rhoG0_S*focc_S, v_SS) if self.coupling: C_S = np.dot(B_S.conj(), overlap_SS.T) * A_S else: C_S = B_S.conj() * A_S return chi_wGG """ gpaw-0.11.0.13004/gpaw/response/qeh.py0000664000175000017500000006064312553643470017410 0ustar jensjjensj00000000000000from __future__ import print_function import pickle import numpy as np Hartree = 27.2113956555 Bohr = 0.529177257507 class Heterostructure: """This class defines dielectric function of heterostructures and related physical quantities.""" def __init__(self, structure, d, include_dipole=True, d0=None, wmax=10, qmax=None): """Creates a Heterostructure object. structure: list of str Heterostructure set up. Each entry should consist of number of layers + chemical formula. For example: ['3H-MoS2', graphene', '10H-WS2'] gives 3 layers of H-MoS2, 1 layer of graphene and 10 layers of H-WS2. d: array of floats Interlayer distances for neighboring layers in Ang. Length of array = number of layers - 1 d0: float The width of a single layer in Ang, only used for monolayer calculation. The layer separation in bulk is typically a good measure. include_dipole: Bool Includes dipole contribution if True wmax: float Cutoff for frequency grid (eV) qmax: float Cutoff for wave-vector grid (1/Ang) """ chi_monopole = [] drho_monopole = [] if include_dipole: chi_dipole = [] drho_dipole = [] else: self.chi_dipole = None drho_dipole = None self.z = [] layer_indices = [] self.n_layers = 0 namelist = [] for n in range(len(structure)): name = structure[n] num = '' while name[0].isdigit(): num += name[0] name = name[1:] if num == '': num = '1' self.n_layers += int(num) if name not in namelist: namelist.append(name) name += '-chi.pckl' q, w, chim, chid, zi, drhom, drhod = pickle.load(open(name)) if qmax is not None: qindex = np.argmin(abs(q - qmax * Bohr)) + 1 else: qindex = -1 if wmax is not None: windex = np.argmin(abs(w - wmax / Hartree)) + 1 else: windex = -1 chi_monopole.append(np.array(chim[:qindex, :windex])) drho_monopole.append(np.array(drhom[:qindex])) if include_dipole: chi_dipole.append(np.array(chid[:qindex, :windex])) drho_dipole.append(np.array(drhod[:qindex])) self.z.append(np.array(zi)) else: n = namelist.index(name) indices = [n for i in range(int(num))] layer_indices = np.append(layer_indices, indices) self.layer_indices = np.array(layer_indices, dtype=int) self.q_abs = q[:qindex] self.frequencies = w[:windex] self.n_types = len(namelist) # layers and distances self.d = np.array(d) / Bohr # interlayer distances if self.n_layers > 1: # space around each layer self.s = (np.insert(self.d, 0, self.d[0]) + np.append(self.d, self.d[-1])) / 2. else: # Monolayer calculation self.s = [d0 / Bohr] # Width of single layer self.dim = self.n_layers if include_dipole: self.dim *= 2 # Grid stuff self.poisson_lim = 100 # above this limit use potential model edgesize = 50 system_size = np.sum(self.d) + edgesize self.z_lim = system_size self.dz = 0.01 # master grid self.z_big = np.arange(0, self.z_lim, self.dz) - edgesize / 2. self.z0 = np.append(np.array([0]), np.cumsum(self.d)) # arange potential and density self.chi_monopole = np.array(chi_monopole) if include_dipole: self.chi_dipole = np.array(chi_dipole) self.drho_monopole, self.drho_dipole, self.basis_array, \ self.drho_array = self.arange_basis(drho_monopole, drho_dipole) self.dphi_array = self.get_induced_potentials() self.kernel_qij = None def arange_basis(self, drhom, drhod=None): from scipy.interpolate import interp1d Nz = len(self.z_big) drho_array = np.zeros([self.dim, len(self.q_abs), Nz], dtype=complex) basis_array = np.zeros([self.dim, len(self.q_abs), Nz], dtype=complex) for i in range(self.n_types): z = self.z[i] - self.z[i][len(self.z[i]) / 2] drhom_i = drhom[i] fm = interp1d(z, np.real(drhom_i)) fm2 = interp1d(z, np.imag(drhom_i)) if drhod is not None: drhod_i = drhod[i] fd = interp1d(z, np.real(drhod_i)) fd2 = interp1d(z, np.imag(drhod_i)) for k in [k for k in range(self.n_layers) if self.layer_indices[k] == i]: z_big = self.z_big - self.z0[k] i_1s = np.argmin(np.abs(-self.s[i] / 2. - z_big)) i_2s = np.argmin(np.abs(self.s[i] / 2. - z_big)) i_1 = np.argmin(np.abs(z[0] - z_big)) + 1 i_2 = np.argmin(np.abs(z[-1] - z_big)) - 1 if drhod is not None: drho_array[2 * k, :, i_1: i_2] = \ fm(z_big[i_1: i_2]) + 1j * fm2(z_big[i_1: i_2]) basis_array[2 * k, :, i_1s: i_2s] = 1. / self.s[i] drho_array[2 * k + 1, :, i_1: i_2] = \ fd(z_big[i_1: i_2]) + 1j * fd2(z_big[i_1: i_2]) basis_array[2 * k + 1, :, i_1: i_2] = \ fd(z_big[i_1: i_2]) + 1j * fd2(z_big[i_1: i_2]) else: drho_array[k, :, i_1: i_2] = \ fm(z_big[i_1: i_2]) + 1j * fm2(z_big[i_1: i_2]) basis_array[k, :, i_1s: i_2s] = 1. / self.s[i] return drhom, drhod, basis_array, drho_array def get_induced_potentials(self): from scipy.interpolate import interp1d Nz = len(self.z_big) dphi_array = np.zeros([self.dim, len(self.q_abs), Nz], dtype=complex) for i in range(self.n_types): z = self.z[i] for iq in range(len(self.q_abs)): q = self.q_abs[iq] drho_m = self.drho_monopole[i][iq].copy() poisson_m = self.solve_poisson_1D(drho_m, q, z) z_poisson = self.get_z_grid(z, z_lim=self.poisson_lim) if not len(z_poisson) == len(np.real(poisson_m)): z_poisson = z_poisson[:len(poisson_m)] poisson_m = poisson_m[:len(z_poisson)] fm = interp1d(z_poisson, np.real(poisson_m)) fm2 = interp1d(z_poisson, np.imag(poisson_m)) if self.chi_dipole is not None: drho_d = self.drho_dipole[i][iq].copy() # delta is the distance between dipole peaks / 2 delta = np.abs(z[np.argmax(drho_d)] - z[np.argmin(drho_d)]) / 2. poisson_d = self.solve_poisson_1D(drho_d, q, z, dipole=True, delta=delta) fd = interp1d(z_poisson, np.real(poisson_d)) for k in [k for k in range(self.n_layers) if self.layer_indices[k] == i]: z_big = self.z_big - self.z0[k] i_1 = np.argmin(np.abs(z_poisson[0] - z_big)) + 1 i_2 = np.argmin(np.abs(z_poisson[-1] - z_big)) - 1 dphi_array[self.dim / self.n_layers * k, iq] = \ self.potential_model(self.q_abs[iq], self.z_big, self.z0[k]) dphi_array[self.dim / self.n_layers * k, iq, i_1: i_2] = \ fm(z_big[i_1: i_2]) + 1j * fm2(z_big[i_1: i_2]) if self.chi_dipole is not None: dphi_array[2 * k + 1, iq] = \ self.potential_model(self.q_abs[iq], self.z_big, self.z0[k], dipole=True, delta=delta) dphi_array[2 * k + 1, iq, i_1: i_2] = \ fd(z_big[i_1: i_2]) return dphi_array def get_z_grid(self, z, z_lim=None): dz = z[1] - z[0] if z_lim is None: z_lim = self.z_lim z_lim = int(z_lim / dz) * dz z_grid = np.insert(z, 0, np.arange(-z_lim, z[0], dz)) z_grid = np.append(z_grid, np.arange(z[-1] + dz, z_lim + dz, dz)) return z_grid def potential_model(self, q, z, z0=0, dipole=False, delta=None): """ 2D Coulomb: 2 pi / q with exponential decay in z-direction """ if dipole: # Two planes separated by 2 * delta V = np.pi / (q * delta) * \ (-np.exp(-q * np.abs(z - z0 + delta)) + np.exp(-q * np.abs(z - z0 - delta))) else: # Monopole potential from single plane V = 2 * np.pi / q * np.exp(-q * np.abs(z - z0)) return V def solve_poisson_1D(self, drho, q, z, dipole=False, delta=None): """ Solves poissons equation in 1D using finite difference method. drho: induced potential basis function q: momentum transfer. """ z -= np.mean(z) # center arround 0 z_grid = self.get_z_grid(z, z_lim=self.poisson_lim) dz = z[1] - z[0] Nz_loc = (len(z_grid) - len(z)) / 2 drho = np.append(np.insert(drho, 0, np.zeros([Nz_loc])), np.zeros([Nz_loc])) Nint = len(drho) - 1 bc_v0 = self.potential_model(q, z_grid[0], dipole=dipole, delta=delta) bc_vN = self.potential_model(q, z_grid[-1], dipole=dipole, delta=delta) M = np.zeros((Nint + 1, Nint + 1)) f_z = np.zeros(Nint + 1, dtype=complex) f_z[:] = - 4 * np.pi * drho[:] # Finite Difference Matrix for i in range(1, Nint): M[i, i] = -2. / (dz**2) - q**2 M[i, i + 1] = 1. / dz**2 M[i, i - 1] = 1. / dz**2 M[0, 0] = 1. M[Nint, Nint] = 1. f_z[0] = bc_v0 f_z[Nint] = bc_vN # Getting the Potential M_inv = np.linalg.inv(M) dphi = np.dot(M_inv, f_z) return dphi def get_Coulomb_Kernel(self, step_potential=False): kernel_qij = np.zeros([len(self.q_abs), self.dim, self.dim], dtype=complex) for iq in range(len(self.q_abs)): if step_potential: # Use step-function average for monopole contribution kernel_qij[iq] = np.dot(self.basis_array[:, iq], self.dphi_array[:, iq].T) * self.dz else: # Normal kernel kernel_qij[iq] = np.dot(self.drho_array[:, iq], self.dphi_array[:, iq].T) * self.dz return kernel_qij def get_chi_matrix(self): """ Dyson equation: chi_full = chi_intra + chi_intra V_inter chi_full """ Nls = self.n_layers q_abs = self.q_abs chi_m_iqw = self.chi_monopole chi_d_iqw = self.chi_dipole if self.kernel_qij is None: self.kernel_qij = self.get_Coulomb_Kernel() chi_qwij = np.zeros((len(self.q_abs), len(self.frequencies), self.dim, self.dim), dtype=complex) for iq in range(len(q_abs)): kernel_ij = self.kernel_qij[iq].copy() np.fill_diagonal(kernel_ij, 0) # Diagonal is set to zero for iw in range(0, len(self.frequencies)): chi_intra_i = chi_m_iqw[self.layer_indices, iq, iw] if self.chi_dipole is not None: chi_intra_i = np.insert(chi_intra_i, np.arange(Nls) + 1, chi_d_iqw[self.layer_indices, iq, iw]) chi_intra_ij = np.diag(chi_intra_i) chi_qwij[iq, iw, :, :] = np.dot(np.linalg.inv( np.eye(self.dim) - np.dot(chi_intra_ij, kernel_ij)), chi_intra_ij) return chi_qwij def get_eps_matrix(self, step_potential=False): """ Get dielectric matrix as: eps^{-1} = 1 + V chi_full """ self.kernel_qij =\ self.get_Coulomb_Kernel(step_potential=step_potential) chi_qwij = self.get_chi_matrix() eps_qwij = np.zeros((len(self.q_abs), len(self.frequencies), self.dim, self.dim), dtype=complex) for iq in range(len(self.q_abs)): kernel_ij = self.kernel_qij[iq] for iw in range(0, len(self.frequencies)): eps_qwij[iq, iw, :, :] = np.linalg.inv( np.eye(kernel_ij.shape[0]) + np.dot(kernel_ij, chi_qwij[iq, iw, :, :])) return eps_qwij def get_exciton_screened_potential(self, e_distr, h_distr): v_screened_qw = np.zeros((len(self.q_abs), len(self.frequencies))) eps_qwij = self.get_eps_matrix() h_distr = h_distr.transpose() kernel_qij = self.get_Coulomb_Kernel() for iq in range(0, len(self.q_abs)): ext_pot = np.dot(kernel_qij[iq], h_distr) for iw in range(0, len(self.frequencies)): v_screened_qw[iq, iw] =\ np.dot(e_distr, np.dot(np.linalg.inv(eps_qwij[iq, iw, :, :]), ext_pot)) return self.q_abs, -v_screened_qw, kernel_qij def get_macroscopic_dielectric_function(self, layers=None): """ Calculates the averaged dielectric matrix over the structure in the static limit omega = 0. Parameters: layers: array of integers list with index of specific layers to include in the average. Returns list of q-points, dielectric function. """ constant_perturbation = np.ones([self.n_layers]) layer_weight = self.s / np.sum(self.s) * self.n_layers if self.chi_dipole is not None: constant_perturbation = np.insert(constant_perturbation, np.arange(self.n_layers) + 1, np.zeros([self.n_layers])) layer_weight = np.insert(layer_weight, np.arange(self.n_layers) + 1, layer_weight) if layers is None: # average over entire structure N = self.n_layers potential = constant_perturbation else: # average over selected layers N = len(layers) potential = np.zeros([self.dim]) index = layers * self.dim / self.n_layers potential[index] = 1. epsM_q = [] eps_qij = self.get_eps_matrix(step_potential=True)[:, 0] for iq in range(len(self.q_abs)): eps_ij = eps_qij[iq] epsinv_ij = np.linalg.inv(eps_ij) epsinv_M = 1. / N * np.dot(np.array(potential) * layer_weight, np.dot(epsinv_ij, np.array(constant_perturbation))) epsM_q.append(1. / epsinv_M.real) return self.q_abs / Bohr, epsM_q def get_response(self, iw=0, dipole=False): """ Get the induced density and potential due to constant perturbation obtained as: rho_ind(r) = \int chi(r,r') dr' """ constant_perturbation = np.ones([self.n_layers]) if self.chi_dipole is not None: constant_perturbation = np.insert(constant_perturbation, np.arange(self.n_layers) + 1, np.zeros([self.n_layers])) if dipole: constant_perturbation = self.z0 - self.z0[-1] / 2. constant_perturbation = np.insert(constant_perturbation, np.arange(self.n_layers) + 1, np.ones([self.n_layers])) chi_qij = self.get_chi_matrix()[:, iw] Vind_z = np.zeros((len(self.q_abs), len(self.z_big))) rhoind_z = np.zeros((len(self.q_abs), len(self.z_big))) drho_array = self.drho_array.copy() dphi_array = self.dphi_array.copy() # Expand on potential and density basis function # to get spatial detendence for iq in range(len(self.q_abs)): chi_ij = chi_qij[iq] Vind_qi = np.dot(chi_ij, np.array(constant_perturbation)) rhoind_z[iq] = np.dot(drho_array[:, iq].T, Vind_qi) Vind_z[iq] = np.dot(dphi_array[:, iq].T, Vind_qi) return self.z_big * Bohr, rhoind_z, Vind_z, self.z0 * Bohr def get_plasmon_eigenmodes(self): """ Diagonalize the dieletric matrix to get the plasmon eigenresonances of the system. Returns: Eigenvalue array (shape Nq x nw x dim), z-grid, induced densities, induced potentials, energies at zero crossings. """ eps_qwij = self.get_eps_matrix() Nw = len(self.frequencies) Nq = len(self.q_abs) w_w = self.frequencies eig = np.zeros([Nq, Nw, self.dim], dtype=complex) vec = np.zeros([Nq, Nw, self.dim, self.dim], dtype=complex) omega0 = [[] for i in range(Nq)] rho_z = [np.zeros([0, len(self.z_big)]) for i in range(Nq)] phi_z = [np.zeros([0, len(self.z_big)]) for i in range(Nq)] for iq in range(Nq): m = 0 eig[iq, 0], vec[iq, 0] = np.linalg.eig(eps_qwij[iq, 0]) vec_dual = np.linalg.inv(vec[iq, 0]) for iw in range(1, Nw): eig[iq, iw], vec_p = np.linalg.eig(eps_qwij[iq, iw]) vec_dual_p = np.linalg.inv(vec_p) overlap = np.abs(np.dot(vec_dual, vec_p)) index = list(np.argsort(overlap)[:, -1]) if len(np.unique(index)) < self.dim: # add missing indices addlist = [] removelist = [] for j in range(self.dim): if index.count(j) < 1: addlist.append(j) if index.count(j) > 1: for l in range(1, index.count(j)): removelist.append( np.argwhere(np.array(index) == j)[l]) for j in range(len(addlist)): index[removelist[j]] = addlist[j] vec[iq, iw] = vec_p[:, index] vec_dual = vec_dual_p[index, :] eig[iq, iw, :] = eig[iq, iw, index] klist = [k for k in range(self.dim) if (eig[iq, iw - 1, k] < 0 and eig[iq, iw, k] > 0)] for k in klist: # Eigenvalue crossing a = np.real((eig[iq, iw, k] - eig[iq, iw - 1, k]) / (w_w[iw] - w_w[iw - 1])) # linear interp for crossing point w0 = np.real(-eig[iq, iw - 1, k]) / a + w_w[iw - 1] rho = np.dot(self.drho_array[:, iq, :].T, vec_dual_p[k, :]) phi = np.dot(self.dphi_array[:, iq, :].T, vec_dual_p[k, :]) rho_z[iq] = np.append(rho_z[iq], rho[np.newaxis, :], axis=0) phi_z[iq] = np.append(phi_z[iq], phi[np.newaxis, :], axis=0) omega0[iq].append(w0) m += 1 return eig, self.z_big * Bohr, rho_z, phi_z, np.array(omega0) """TOOLS""" def get_chi_2D(filenames=None, name=None): """Calculate the monopole and dipole contribution to the 2D susceptibillity chi_2D, defined as :: \chi^M_2D(q, \omega) = \int\int dr dr' \chi(q, \omega, r,r') \\ = L \chi_{G=G'=0}(q, \omega) \chi^D_2D(q, \omega) = \int\int dr dr' z \chi(q, \omega, r,r') z' = 1/L sum_{G_z,G_z'} z_factor(G_z) chi_{G_z,G_z'} z_factor(G_z'), Where z_factor(G_z) = +/- i e^{+/- i*G_z*z0} (L G_z cos(G_z L/2)-2 sin(G_z L/2))/G_z^2 input parameters: filenames: list of str list of chi_wGG.pckl files for different q calculated with the DielectricFunction module in GPAW name: str name writing output files """ q_list_abs = [] omega_w, pd, chi_wGG, q0 = read_chi_wGG(filenames[0]) nq = len(filenames) nw = omega_w.shape[0] r = pd.gd.get_grid_point_coordinates() z = r[2, 0, 0, :] L = pd.gd.cell_cv[2, 2] # Length of cell in Bohr z0 = L / 2. # position of layer chiM_2D_qw = np.zeros([nq, nw], dtype=complex) chiD_2D_qw = np.zeros([nq, nw], dtype=complex) drho_M_qz = np.zeros([nq, len(z)], dtype=complex) # induced density drho_D_qz = np.zeros([nq, len(z)], dtype=complex) # induced dipole density for iq in range(nq): if not iq == 0: omega_w, pd, chi_wGG, q0 = read_chi_wGG(filenames[iq]) if q0 is not None: q = q0 else: q = pd.K_qv npw = chi_wGG.shape[1] Gvec = pd.get_reciprocal_vectors(add_q=False) Glist = [] for iG in range(npw): # List of G with Gx,Gy = 0 if Gvec[iG, 0] == 0 and Gvec[iG, 1] == 0: Glist.append(iG) chiM_2D_qw[iq] = L * chi_wGG[:, 0, 0] drho_M_qz[iq] += chi_wGG[0, 0, 0] q_abs = np.linalg.norm(q) q_list_abs.append(q_abs) for iG in Glist[1:]: G_z = Gvec[iG, 2] qGr_R = np.inner(G_z, z.T).T # Fourier transform to get induced density at \omega=0 drho_M_qz[iq] += np.exp(1j * qGr_R) * chi_wGG[0, iG, 0] for iG1 in Glist[1:]: G_z1 = Gvec[iG1, 2] # integrate with z along both coordinates factor = z_factor(z0, L, G_z) factor1 = z_factor(z0, L, G_z1, sign=-1) chiD_2D_qw[iq, :] += 1. / L * factor * chi_wGG[:, iG, iG1] * \ factor1 # induced dipole density due to V_ext = z drho_D_qz[iq, :] += 1. / L * np.exp(1j * qGr_R) * \ chi_wGG[0, iG, iG1] * factor1 # Normalize induced densities with chi drho_M_qz /= np.repeat(chiM_2D_qw[:, 0, np.newaxis], drho_M_qz.shape[1], axis=1) drho_D_qz /= np.repeat(chiD_2D_qw[:, 0, np.newaxis], drho_M_qz.shape[1], axis=1) """ Returns q array, frequency array, chi2D monopole and dipole, induced densities and z array (all in Bohr) """ pickle.dump((np.array(q_list_abs), omega_w, chiM_2D_qw, chiD_2D_qw, z, drho_M_qz, drho_D_qz), open(name + '-chi.pckl', 'w')) return np.array(q_list_abs) / Bohr, omega_w * Hartree, chiM_2D_qw, \ chiD_2D_qw, z, drho_M_qz, drho_D_qz def z_factor(z0, d, G, sign=1): factor = -1j * sign * np.exp(1j * sign * G * z0) * \ (d * G * np.cos(G * d / 2.) - 2. * np.sin(G * d / 2.)) / G**2 return factor def z_factor2(z0, d, G, sign=1): factor = sign * np.exp(1j * sign * G * z0) * np.sin(G * d / 2.) return factor def read_chi_wGG(name): """ Read density response matrix calculated with the DielectricFunction module in GPAW. Returns frequency grid, gpaw.wavefunctions object, chi_wGG """ fd = open(name) omega_w, pd, chi_wGG, q0, chi0_wvv = pickle.load(fd) nw = len(omega_w) nG = pd.ngmax chi_wGG = np.empty((nw, nG, nG), complex) for chi_GG in chi_wGG: chi_GG[:] = pickle.load(fd) return omega_w, pd, chi_wGG, q0 gpaw-0.11.0.13004/gpaw/response/wstc.py0000664000175000017500000000526412553643470017611 0ustar jensjjensj00000000000000"""Wigner-Seitz truncated coulomb interaction. See: Ravishankar Sundararaman and T. A. Arias: Phys. Rev. B 87, 165122 (2013) Regularization of the Coulomb singularity in exact exchange by Wigner-Seitz truncated interactions: Towards chemical accuracy in nontrivial systems """ import sys from math import pi import numpy as np from ase.units import Bohr from ase.utils import prnt import gpaw.mpi as mpi from gpaw.utilities import erf from gpaw.fftw import get_efficient_fft_size from gpaw.grid_descriptor import GridDescriptor class WignerSeitzTruncatedCoulomb: def __init__(self, cell_cv, nk_c, txt=sys.stdout): self.nk_c = nk_c bigcell_cv = cell_cv * nk_c[:, np.newaxis] L_c = (np.linalg.inv(bigcell_cv)**2).sum(0)**-0.5 rc = 0.5 * L_c.min() prnt('Inner radius for %dx%dx%d Wigner-Seitz cell: %.3f Ang' % (tuple(nk_c) + (rc * Bohr,)), file=txt) self.a = 5 / rc prnt('Range-separation parameter: %.3f Ang^-1' % (self.a / Bohr), file=txt) # nr_c = [get_efficient_fft_size(2 * int(L * self.a * 1.5)) nr_c = [get_efficient_fft_size(2 * int(L * self.a * 3.0)) for L in L_c] prnt('FFT size for calculating truncated Coulomb: %dx%dx%d' % tuple(nr_c), file=txt) self.gd = GridDescriptor(nr_c, bigcell_cv, comm=mpi.serial_comm) v_R = self.gd.empty() v_i = v_R.ravel() pos_iv = self.gd.get_grid_point_coordinates().reshape((3, -1)).T corner_jv = np.dot(np.indices((2, 2, 2)).reshape((3, 8)).T, bigcell_cv) for i, pos_v in enumerate(pos_iv): r = ((pos_v - corner_jv)**2).sum(axis=1).min()**0.5 if r == 0: v_i[i] = 2 * self.a / pi**0.5 else: v_i[i] = erf(self.a * r) / r self.K_Q = np.fft.fftn(v_R) * self.gd.dv def get_potential(self, pd): q_c = pd.kd.bzk_kc[0] shift_c = (q_c * self.nk_c).round().astype(int) max_c = self.gd.N_c // 2 K_G = pd.zeros() N_c = pd.gd.N_c for G, Q in enumerate(pd.Q_qG[0]): Q_c = (np.unravel_index(Q, N_c) + N_c // 2) % N_c - N_c // 2 Q_c = Q_c * self.nk_c + shift_c if (abs(Q_c) < max_c).all(): K_G[G] = self.K_Q[tuple(Q_c)] G2_G = pd.G2_qG[0] a = self.a if pd.kd.gamma: K_G[0] += pi / a**2 else: K_G[0] += 4 * pi * (1 - np.exp(-G2_G[0] / (4 * a**2))) / G2_G[0] K_G[1:] += 4 * pi * (1 - np.exp(-G2_G[1:] / (4 * a**2))) / G2_G[1:] assert pd.dtype == complex return K_G gpaw-0.11.0.13004/gpaw/response/kernel2.py0000664000175000017500000001226712553643470020174 0ustar jensjjensj00000000000000# -*- coding: utf-8 # In an attempt to appease epydoc and still have readable docstrings, # the vertical bar | is represented by u'\u2758' in this module. """This module defines Coulomb and XC kernels for the response model. """ import numpy as np #from math import sqrt, pi, sin, cos, exp from gpaw.utilities.blas import gemmdot from gpaw.xc import XC from gpaw.sphere.lebedev import weight_n, R_nv from gpaw.mpi import world, rank, size from ase.dft.kpoints import monkhorst_pack def truncated_coulomb(pd, q0=None): """ Simple truncation of Coulomb kernel along z Rozzi, C., Varsano, D., Marini, A., Gross, E., & Rubio, A. (2006). Exact Coulomb cutoff technique for supercell calculations. Physical Review B, 73(20), 205119. doi:10.1103/PhysRevB.73.205119 """ qG = pd.get_reciprocal_vectors(add_q=True) if pd.kd.gamma: # Set small finite q to handle divergence if q0 is None: q0 = 0.0000001 qG += [q0, 0, 0] nG = len(qG) L = pd.gd.cell_cv[2, 2] R = L / 2. # Truncation length is half of unit cell qG_par = ((qG[:, 0])**2 + (qG[:, 1]**2))**0.5 qG_z = qG[:, 2] K_G = 4 * np.pi / (qG**2).sum(axis=1) # K_G *= 1. + np.exp(-qG_par * R) * (qG_z / qG_par * np.sin(qG_z * R)\ # - np.cos(qG_z * R)) # sin(qG_z * R) = 0 when R = L/2 K_G *= 1. - np.exp(-qG_par * R) * np.cos(qG_z * R) K_G **= 0.5 return K_G.astype(complex) def calculate_Kxc(pd, nt_sG, R_av, setups, D_asp, functional='ALDA', density_cut=None): """ALDA kernel""" gd = pd.gd npw = pd.ngmax nG = pd.gd.N_c vol = pd.gd.volume bcell_cv = np.linalg.inv(pd.gd.cell_cv) G_Gv = pd.get_reciprocal_vectors() # The soft part #assert np.abs(nt_sG[0].shape - nG).sum() == 0 if functional == 'ALDA_X': x_only = True A_x = -3. / 4. * (3. / np.pi)**(1. / 3.) nspins = len(nt_sG) assert nspins in [1, 2] fxc_sg = nspins**(1. / 3.) * 4. / 9. * A_x * nt_sG**(-2. / 3.) else: assert len(nt_sG) == 1 x_only = False fxc_sg = np.zeros_like(nt_sG) xc = XC(functional[1:]) xc.calculate_fxc(gd, nt_sG, fxc_sg) if density_cut is not None: fxc_sg[np.where(nt_sG * len(nt_sG) < density_cut)] = 0.0 # FFT fxc(r) nG0 = nG[0] * nG[1] * nG[2] tmp_sg = [np.fft.fftn(fxc_sg[s]) * vol / nG0 for s in range(len(nt_sG))] r_vg = gd.get_grid_point_coordinates() Kxc_sGG = np.zeros((len(fxc_sg), npw, npw), dtype=complex) for s in range(len(fxc_sg)): for iG, iQ in enumerate(pd.Q_qG[0]): iQ_c = (np.unravel_index(iQ, nG) + nG // 2) % nG - nG // 2 for jG, jQ in enumerate(pd.Q_qG[0]): jQ_c = (np.unravel_index(jQ, nG) + nG // 2) % nG - nG // 2 ijQ_c = (iQ_c - jQ_c) if (abs(ijQ_c) < nG // 2).all(): Kxc_sGG[s, iG, jG] = tmp_sg[s][tuple(ijQ_c)] # The PAW part KxcPAW_sGG = np.zeros_like(Kxc_sGG) dG_GGv = np.zeros((npw, npw, 3)) for v in range(3): dG_GGv[:, :, v] = np.subtract.outer(G_Gv[:, v], G_Gv[:, v]) for a, setup in enumerate(setups): if rank == a % size: rgd = setup.xc_correction.rgd n_qg = setup.xc_correction.n_qg nt_qg = setup.xc_correction.nt_qg nc_g = setup.xc_correction.nc_g nct_g = setup.xc_correction.nct_g Y_nL = setup.xc_correction.Y_nL dv_g = rgd.dv_g D_sp = D_asp[a] B_pqL = setup.xc_correction.B_pqL D_sLq = np.inner(D_sp, B_pqL.T) nspins = len(D_sp) f_sg = rgd.empty(nspins) ft_sg = rgd.empty(nspins) n_sLg = np.dot(D_sLq, n_qg) nt_sLg = np.dot(D_sLq, nt_qg) # Add core density n_sLg[:, 0] += np.sqrt(4. * np.pi) / nspins * nc_g nt_sLg[:, 0] += np.sqrt(4. * np.pi) / nspins * nct_g coefatoms_GG = np.exp(-1j * np.inner(dG_GGv, R_av[a])) for n, Y_L in enumerate(Y_nL): w = weight_n[n] f_sg[:] = 0.0 n_sg = np.dot(Y_L, n_sLg) if x_only: f_sg = nspins * (4 / 9.) * A_x * (nspins * n_sg)**(-2 / 3.) else: xc.calculate_fxc(rgd, n_sg, f_sg) ft_sg[:] = 0.0 nt_sg = np.dot(Y_L, nt_sLg) if x_only: ft_sg = nspins * (4 / 9.) * (A_x * (nspins * nt_sg)**(-2 / 3.)) else: xc.calculate_fxc(rgd, nt_sg, ft_sg) for i in range(len(rgd.r_g)): coef_GG = np.exp(-1j * np.inner(dG_GGv, R_nv[n]) * rgd.r_g[i]) for s in range(len(f_sg)): KxcPAW_sGG[s] += w * np.dot(coef_GG, (f_sg[s, i] - ft_sg[s, i]) * dv_g[i]) * coefatoms_GG world.sum(KxcPAW_sGG) Kxc_sGG += KxcPAW_sGG return Kxc_sGG / vol gpaw-0.11.0.13004/gpaw/response/g0w0.py0000664000175000017500000006120312553643470017401 0ustar jensjjensj00000000000000# This makes sure that division works as in Python3 from __future__ import division, print_function import functools import pickle from math import pi import numpy as np from ase.dft.kpoints import monkhorst_pack from ase.units import Hartree from ase.utils import opencew, devnull from ase.utils.timing import timer import gpaw.mpi as mpi from gpaw import debug from gpaw.kpt_descriptor import KPointDescriptor from gpaw.response.chi0 import Chi0, HilbertTransform from gpaw.response.pair import PairDensity from gpaw.response.wstc import WignerSeitzTruncatedCoulomb from gpaw.wavefunctions.pw import PWDescriptor, count_reciprocal_vectors from gpaw.xc.exx import EXX, select_kpts from gpaw.xc.tools import vxc class G0W0(PairDensity): """This class defines the G0W0 calculator. The G0W0 calculator is used is used to calculate the quasi particle energies through the G0W0 approximation for a number of states. Note: So far the G0W0 calculation only works for spin-paired systems. Parameters: calc: str or PAW object GPAW calculator object or filename of saved calculator object. filename: str Base filename of output files. kpts: list List of indices of the IBZ k-points to calculate the quasi particle energies for. bands: tuple Range of band indices, like (n1, n2+1), to calculate the quasi particle energies for. Note that the second band index is not included. ecut: float Plane wave cut-off energy in eV. nbands: int Number of bands to use in the calculation. If :None: the number will be determined from :ecut: to yield a number close to the number of plane waves used. ppa: bool Sets whether the Godby-Needs plasmon-pole approximation for the dielectric function should be used. E0: float Energy (in eV) used for fitting in the plasmon-pole approximation. domega0: float Minimum frequency step (in eV) used in the generation of the non- linear frequency grid. omega2: float Control parameter for the non-linear frequency grid, equal to the frequency where the grid spacing has doubled in size. wstc: bool Sets whether a Wigner-Seitz truncation should be used for the Coloumb potential. """ def __init__(self, calc, filename='gw', kpts=None, bands=None, nbands=None, ppa=False, wstc=False, ecut=150.0, eta=0.1, E0=1.0 * Hartree, domega0=0.025, omega2=10.0, nblocks=1, savew=False, world=mpi.world): if world.rank != 0: txt = devnull else: txt = open(filename + '.txt', 'w') p = functools.partial(print, file=txt) p(' ___ _ _ _ ') p(' | || | | |') p(' | | || | | |') p(' |__ ||_____|') p(' |___|') p() self.inputcalc = calc PairDensity.__init__(self, calc, ecut, world=world, nblocks=nblocks, txt=txt) self.filename = filename self.savew = savew ecut /= Hartree self.ppa = ppa self.wstc = wstc self.eta = eta / Hartree self.E0 = E0 / Hartree self.domega0 = domega0 / Hartree self.omega2 = omega2 / Hartree self.kpts = list(select_kpts(kpts, self.calc)) if bands is None: bands = [0, self.nocc2] self.bands = bands b1, b2 = bands self.shape = shape = (self.calc.wfs.nspins, len(self.kpts), b2 - b1) self.eps_sin = np.empty(shape) # KS-eigenvalues self.f_sin = np.empty(shape) # occupation numbers self.sigma_sin = np.zeros(shape) # self-energies self.dsigma_sin = np.zeros(shape) # derivatives of self-energies self.vxc_sin = None # KS XC-contributions self.exx_sin = None # exact exchange contributions self.Z_sin = None # renormalization factors if nbands is None: nbands = int(self.vol * ecut**1.5 * 2**0.5 / 3 / pi**2) self.nbands = nbands p() p('Quasi particle states:') if kpts is None: p('All k-points in IBZ') else: kptstxt = ', '.join(['{0:d}'.format(k) for k in self.kpts]) p('k-points (IBZ indices): [' + kptstxt + ']') p('Band range: ({0:d}, {1:d})'.format(b1, b2)) p() p('Computational parameters:') p('Plane wave cut-off: {0:g} eV'.format(self.ecut * Hartree)) p('Number of bands: {0:d}'.format(self.nbands)) p('Broadening: {0:g} eV'.format(self.eta * Hartree)) kd = self.calc.wfs.kd self.mysKn1n2 = None # my (s, K, n1, n2) indices self.distribute_k_points_and_bands(b1, b2, kd.ibz2bz_k[self.kpts]) # Find q-vectors and weights in the IBZ: assert -1 not in kd.bz2bz_ks offset_c = 0.5 * ((kd.N_c + 1) % 2) / kd.N_c bzq_qc = monkhorst_pack(kd.N_c) + offset_c self.qd = KPointDescriptor(bzq_qc) self.qd.set_symmetry(self.calc.atoms, kd.symmetry) assert self.calc.wfs.nspins == 1 @timer('G0W0') def calculate(self, ecuts=None): """Starts the G0W0 calculation. Returns a dict with the results with the following key/value pairs: f: (s, k, n) ndarray Occupation numbers eps: (s, k, n) ndarray Kohn-Sham eigenvalues in eV vxc: (s, k, n) ndarray Exchange-correlation contributions in eV exx: (s, k, n) ndarray Exact exchange contributions in eV sigma: (s, k, n) ndarray Self-energy contributions in eV Z: (s, k, n) ndarray Renormalization factors qp: (s, k, n) ndarray Quasi particle energies in eV """ kd = self.calc.wfs.kd self.calculate_ks_xc_contribution() self.calculate_exact_exchange() # Reset calculation self.sigma_sin = np.zeros(self.shape) # self-energies self.dsigma_sin = np.zeros(self.shape) # derivatives of self-energies # Get KS eigenvalues and occupation numbers: b1, b2 = self.bands for i, k in enumerate(self.kpts): kpt = self.calc.wfs.kpt_u[k] self.eps_sin[0, i] = kpt.eps_n[b1:b2] self.f_sin[0, i] = kpt.f_n[b1:b2] / kpt.weight # My part of the states we want to calculate QP-energies for: mykpts = [self.get_k_point(s, K, n1, n2) for s, K, n1, n2 in self.mysKn1n2] # Loop over q in the IBZ: for pd0, W0, q_c in self.calculate_screened_potential(): for kpt1 in mykpts: K2 = kd.find_k_plus_q(q_c, [kpt1.K])[0] kpt2 = self.get_k_point(0, K2, 0, self.nbands, block=True) k1 = kd.bz2ibz_k[kpt1.K] i = self.kpts.index(k1) self.calculate_q(i, kpt1, kpt2, pd0, W0) self.world.sum(self.sigma_sin) self.world.sum(self.dsigma_sin) self.Z_sin = 1 / (1 - self.dsigma_sin) self.qp_sin = self.eps_sin + self.Z_sin * (self.sigma_sin + self.exx_sin - self.vxc_sin) results = {'f': self.f_sin, 'eps': self.eps_sin * Hartree, 'vxc': self.vxc_sin * Hartree, 'exx': self.exx_sin * Hartree, 'sigma': self.sigma_sin * Hartree, 'Z': self.Z_sin, 'qp': self.qp_sin * Hartree} self.print_results(results) return results def calculate_q(self, i, kpt1, kpt2, pd0, W0): """Calculates the contribution to the self-energy and its derivative for a given set of k-points, kpt1 and kpt2.""" wfs = self.calc.wfs N_c = pd0.gd.N_c i_cG = self.sign * np.dot(self.U_cc, np.unravel_index(pd0.Q_qG[0], N_c)) q_c = wfs.kd.bzk_kc[kpt2.K] - wfs.kd.bzk_kc[kpt1.K] q0 = np.allclose(q_c, 0) and not self.wstc shift0_c = q_c - self.sign * np.dot(self.U_cc, pd0.kd.bzk_kc[0]) assert np.allclose(shift0_c.round(), shift0_c) shift0_c = shift0_c.round().astype(int) shift_c = kpt1.shift_c - kpt2.shift_c - shift0_c I_G = np.ravel_multi_index(i_cG + shift_c[:, None], N_c, 'wrap') G_Gv = pd0.get_reciprocal_vectors() pos_av = np.dot(self.spos_ac, pd0.gd.cell_cv) M_vv = np.dot(pd0.gd.cell_cv.T, np.dot(self.U_cc.T, np.linalg.inv(pd0.gd.cell_cv).T)) Q_aGii = [] for a, Q_Gii in enumerate(self.Q_aGii): x_G = np.exp(1j * np.dot(G_Gv, (pos_av[a] - self.sign * np.dot(M_vv, pos_av[a])))) U_ii = self.calc.wfs.setups[a].R_sii[self.s] Q_Gii = np.dot(np.dot(U_ii, Q_Gii * x_G[:, None, None]), U_ii.T).transpose(1, 0, 2) Q_aGii.append(Q_Gii) if debug: self.check(i_cG, shift0_c, N_c, q_c, Q_aGii) if self.ppa: calculate_sigma = self.calculate_sigma_ppa else: calculate_sigma = self.calculate_sigma for n in range(kpt1.n2 - kpt1.n1): ut1cc_R = kpt1.ut_nR[n].conj() eps1 = kpt1.eps_n[n] C1_aGi = [np.dot(Qa_Gii, P1_ni[n].conj()) for Qa_Gii, P1_ni in zip(Q_aGii, kpt1.P_ani)] n_mG = self.calculate_pair_densities(ut1cc_R, C1_aGi, kpt2, pd0, I_G) if self.sign == 1: n_mG = n_mG.conj() if q0: n_mG[:, 0] = 0 m = n + kpt1.n1 - kpt2.n1 if 0 <= m < len(n_mG): n_mG[m, 0] = 1.0 f_m = kpt2.f_n deps_m = eps1 - kpt2.eps_n sigma, dsigma = calculate_sigma(n_mG, deps_m, f_m, W0) nn = kpt1.n1 + n - self.bands[0] self.sigma_sin[kpt1.s, i, nn] += sigma self.dsigma_sin[kpt1.s, i, nn] += dsigma def check(self, i_cG, shift0_c, N_c, q_c, Q_aGii): I0_G = np.ravel_multi_index(i_cG - shift0_c[:, None], N_c, 'wrap') qd1 = KPointDescriptor([q_c]) pd1 = PWDescriptor(self.ecut, self.calc.wfs.gd, complex, qd1) G_I = np.empty(N_c.prod(), int) G_I[:] = -1 I1_G = pd1.Q_qG[0] G_I[I1_G] = np.arange(len(I0_G)) G_G = G_I[I0_G] assert len(I0_G) == len(I1_G) assert (G_G >= 0).all() for a, Q_Gii in enumerate(self.initialize_paw_corrections(pd1)): e = abs(Q_aGii[a] - Q_Gii[G_G]).max() assert e < 1e-12 @timer('Sigma') def calculate_sigma(self, n_mG, deps_m, f_m, C_swGG): """Calculates a contribution to the self-energy and its derivative for a given (k, k-q)-pair from its corresponding pair-density and energy.""" o_m = abs(deps_m) # Add small number to avoid zeros for degenerate states: sgn_m = np.sign(deps_m + 1e-15) # Pick +i*eta or -i*eta: s_m = (1 + sgn_m * np.sign(0.5 - f_m)).astype(int) // 2 beta = (2**0.5 - 1) * self.domega0 / self.omega2 w_m = (o_m / (self.domega0 + beta * o_m)).astype(int) o1_m = self.omega_w[w_m] o2_m = self.omega_w[w_m + 1] x = 1.0 / (self.qd.nbzkpts * 2 * pi * self.vol) sigma = 0.0 dsigma = 0.0 # Performing frequency integration for o, o1, o2, sgn, s, w, n_G in zip(o_m, o1_m, o2_m, sgn_m, s_m, w_m, n_mG): C1_GG = C_swGG[s][w] C2_GG = C_swGG[s][w + 1] p = x * sgn myn_G = n_G[self.Ga:self.Gb] sigma1 = p * np.dot(np.dot(myn_G, C1_GG), n_G.conj()).imag sigma2 = p * np.dot(np.dot(myn_G, C2_GG), n_G.conj()).imag sigma += ((o - o1) * sigma2 + (o2 - o) * sigma1) / (o2 - o1) dsigma += sgn * (sigma2 - sigma1) / (o2 - o1) return sigma, dsigma def calculate_screened_potential(self): """Calculates the screened potential for each q-point in the 1st BZ. Since many q-points are related by symmetry, the actual calculation is only done for q-points in the IBZ and the rest are obtained by symmetry transformations. Results are returned as a generator to that it is not necessary to store a huge matrix for each q-point in the memory.""" # The decorator $timer('W') doesn't work for generators, do we will # have to manually start and stop the timer here: self.timer.start('W') print('Calculating screened Coulomb potential', file=self.fd) if self.wstc: print('Using Wigner-Seitz truncated Coloumb potential', file=self.fd) if self.ppa: print('Using Godby-Needs plasmon-pole approximation:', file=self.fd) print(' Fitting energy: i*E0, E0 = %.3f Hartee' % self.E0, file=self.fd) # use small imaginary frequency to avoid dividing by zero: frequencies = [1e-10j, 1j * self.E0 * Hartree] parameters = {'eta': 0, 'hilbert': False, 'timeordered': False, 'frequencies': frequencies} else: print('Using full frequency integration:', file=self.fd) print(' domega0: {0:g}'.format(self.domega0 * Hartree), file=self.fd) print(' omega2: {0:g}'.format(self.omega2 * Hartree), file=self.fd) parameters = {'eta': self.eta * Hartree, 'hilbert': True, 'timeordered': True, 'domega0': self.domega0 * Hartree, 'omega2': self.omega2 * Hartree} chi0 = Chi0(self.inputcalc, nbands=self.nbands, ecut=self.ecut * Hartree, intraband=False, real_space_derivatives=False, txt=self.filename + '.w.txt', timer=self.timer, keep_occupied_states=True, nblocks=self.blockcomm.size, no_optical_limit=self.wstc, **parameters) if self.wstc: wstc = WignerSeitzTruncatedCoulomb( self.calc.wfs.gd.cell_cv, self.calc.wfs.kd.N_c, chi0.fd) else: wstc = None self.omega_w = chi0.omega_w self.omegamax = chi0.omegamax htp = HilbertTransform(self.omega_w, self.eta, gw=True) htm = HilbertTransform(self.omega_w, -self.eta, gw=True) # Find maximum size of chi-0 matrices: gd = self.calc.wfs.gd nGmax = max(count_reciprocal_vectors(self.ecut, gd, q_c) for q_c in self.qd.ibzk_kc) nw = len(self.omega_w) size = self.blockcomm.size mynGmax = (nGmax + size - 1) // size mynw = (nw + size - 1) // size # Allocate memory in the beginning and use for all q: A1_x = np.empty(nw * mynGmax * nGmax, complex) A2_x = np.empty(max(mynw * nGmax, nw * mynGmax) * nGmax, complex) # Need to pause the timer in between iterations self.timer.stop('W') for iq, q_c in enumerate(self.qd.ibzk_kc): self.timer.start('W') if self.savew: wfilename = self.filename + '.w.q%d.pckl' % iq fd = opencew(wfilename) if self.savew and fd is None: # Read screened potential from file with open(wfilename) as fd: pd, W = pickle.load(fd) # We also need to initialize the PAW corrections self.Q_aGii = self.initialize_paw_corrections(pd) else: # First time calculation pd, W = self.calculate_w(chi0, q_c, htp, htm, wstc, A1_x, A2_x) if self.savew: pickle.dump((pd, W), fd, pickle.HIGHEST_PROTOCOL) self.timer.stop('W') # Loop over all k-points in the BZ and find those that are related # to the current IBZ k-point by symmetry Q1 = self.qd.ibz2bz_k[iq] done = set() for s, Q2 in enumerate(self.qd.bz2bz_ks[Q1]): if Q2 >= 0 and Q2 not in done: s = self.qd.sym_k[Q2] self.s = s self.U_cc = self.qd.symmetry.op_scc[s] time_reversal = self.qd.time_reversal_k[Q2] self.sign = 1 - 2 * time_reversal Q_c = self.qd.bzk_kc[Q2] d_c = self.sign * np.dot(self.U_cc, q_c) - Q_c assert np.allclose(d_c.round(), d_c) yield pd, W, Q_c done.add(Q2) @timer('WW') def calculate_w(self, chi0, q_c, htp, htm, wstc, A1_x, A2_x): """Calculates the screened potential for a specified q-point.""" pd, chi0_wGG = chi0.calculate(q_c, A_x=A1_x)[:2] self.Q_aGii = chi0.Q_aGii self.Ga = chi0.Ga self.Gb = chi0.Gb if self.blockcomm.size > 1: A1_x = chi0_wGG.ravel() chi0_wGG = chi0.redistribute(chi0_wGG, A2_x) if self.wstc: iG_G = (wstc.get_potential(pd) / (4 * pi))**0.5 if np.allclose(q_c, 0): chi0_wGG[:, 0] = 0.0 chi0_wGG[:, :, 0] = 0.0 G0inv = 0.0 G20inv = 0.0 else: G0inv = None G20inv = None else: if np.allclose(q_c, 0): dq3 = (2 * pi)**3 / (self.qd.nbzkpts * self.vol) qc = (dq3 / 4 / pi * 3)**(1 / 3) G0inv = 2 * pi * qc**2 / dq3 G20inv = 4 * pi * qc / dq3 G_G = pd.G2_qG[0]**0.5 G_G[0] = 1 iG_G = 1 / G_G else: iG_G = pd.G2_qG[0]**-0.5 G0inv = None G20inv = None delta_GG = np.eye(len(iG_G)) if self.ppa: return pd, self.ppa_w(chi0_wGG, iG_G, delta_GG, G0inv, G20inv, q_c) self.timer.start('Dyson eq.') # Calculate W and store it in chi0_wGG ndarray: for chi0_GG in chi0_wGG: e_GG = (delta_GG - 4 * pi * chi0_GG * iG_G * iG_G[:, np.newaxis]) W_GG = chi0_GG W_GG[:] = 4 * pi * (np.linalg.inv(e_GG) - delta_GG) * iG_G * iG_G[:, np.newaxis] if np.allclose(q_c, 0): W_GG[0, 0] *= G20inv W_GG[1:, 0] *= G0inv W_GG[0, 1:] *= G0inv if self.blockcomm.size > 1: Wm_wGG = chi0.redistribute(chi0_wGG, A1_x) else: Wm_wGG = chi0_wGG Wp_wGG = A2_x[:Wm_wGG.size].reshape(Wm_wGG.shape) Wp_wGG[:] = Wm_wGG with self.timer('Hilbert transform'): htp(Wp_wGG) htm(Wm_wGG) self.timer.stop('Dyson eq.') return pd, [Wp_wGG, Wm_wGG] @timer('Kohn-Sham XC-contribution') def calculate_ks_xc_contribution(self): name = self.filename + '.vxc.npy' fd = opencew(name) if fd is None: print('Reading Kohn-Sham XC contribution from file:', name, file=self.fd) with open(name) as fd: self.vxc_sin = np.load(fd) assert self.vxc_sin.shape == self.shape, self.vxc_sin.shape return print('Calculating Kohn-Sham XC contribution', file=self.fd) if self.reader is not None: self.calc.wfs.read_projections(self.reader) vxc_skn = vxc(self.calc, self.calc.hamiltonian.xc) / Hartree n1, n2 = self.bands self.vxc_sin = vxc_skn[:, self.kpts, n1:n2] np.save(fd, self.vxc_sin) @timer('EXX') def calculate_exact_exchange(self): name = self.filename + '.exx.npy' fd = opencew(name) if fd is None: print('Reading EXX contribution from file:', name, file=self.fd) with open(name) as fd: self.exx_sin = np.load(fd) assert self.exx_sin.shape == self.shape, self.exx_sin.shape return print('Calculating EXX contribution', file=self.fd) exx = EXX(self.calc, kpts=self.kpts, bands=self.bands, txt=self.filename + '.exx.txt', timer=self.timer) exx.calculate() self.exx_sin = exx.get_eigenvalue_contributions() / Hartree np.save(fd, self.exx_sin) def print_results(self, results): description = ['f: Occupation numbers', 'eps: KS-eigenvalues [eV]', 'vxc: KS vxc [eV]', 'exx: Exact exchange [eV]', 'sigma: Self-energies [eV]', 'Z: Renormalization factors', 'qp: QP-energies [eV]'] print('\nResults:', file=self.fd) for line in description: print(line, file=self.fd) b1, b2 = self.bands names = [line.split(':', 1)[0] for line in description] ibzk_kc = self.calc.wfs.kd.ibzk_kc for s in range(self.calc.wfs.nspins): for i, ik in enumerate(self.kpts): print('\nk-point ' + '{0} ({1}): ({2:.3f}, {3:.3f}, {4:.3f})'.format( i, ik, *ibzk_kc[ik]), file=self.fd) print('band' + ''.join('{0:>8}'.format(name) for name in names), file=self.fd) for n in range(b2 - b1): print('{0:4}'.format(n + b1) + ''.join('{0:8.3f}'.format(results[name][s, i, n]) for name in names), file=self.fd) self.timer.write(self.fd) @timer('PPA') def ppa_w(self, chi0_wGG, iG_G, delta_GG, G0inv, G20inv, q_c): einv_wGG = [] for chi0_GG in chi0_wGG: e_GG = (delta_GG - 4 * pi * chi0_GG * iG_G * iG_G[:, np.newaxis]) einv_wGG.append(np.linalg.inv(e_GG) - delta_GG) if self.wstc and np.allclose(q_c, 0): einv_wGG[0][0] = 42 einv_wGG[0][:, 0] = 42 omegat_GG = self.E0 * np.sqrt(einv_wGG[1] / (einv_wGG[0] - einv_wGG[1])) R_GG = -0.5 * omegat_GG * einv_wGG[0] W_GG = 4 * pi**2 * R_GG * iG_G * iG_G[:, np.newaxis] if np.allclose(q_c, 0): W_GG[0, 0] *= G20inv W_GG[1:, 0] *= G0inv W_GG[0, 1:] *= G0inv return [W_GG, omegat_GG] @timer('PPA-Sigma') def calculate_sigma_ppa(self, n_mG, deps_m, f_m, W): W_GG, omegat_GG = W sigma = 0.0 dsigma = 0.0 # init variables (is this necessary?) nG = n_mG.shape[1] deps_GG = np.empty((nG, nG)) sign_GG = np.empty((nG, nG)) x1_GG = np.empty((nG, nG)) x2_GG = np.empty((nG, nG)) x3_GG = np.empty((nG, nG)) x4_GG = np.empty((nG, nG)) x_GG = np.empty((nG, nG)) dx_GG = np.empty((nG, nG)) nW_G = np.empty(nG) for m in range(np.shape(n_mG)[0]): deps_GG = deps_m[m] sign_GG = 2 * f_m[m] - 1 x1_GG = 1 / (deps_GG + omegat_GG - 1j * self.eta) x2_GG = 1 / (deps_GG - omegat_GG + 1j * self.eta) x3_GG = 1 / (deps_GG + omegat_GG - 1j * self.eta * sign_GG) x4_GG = 1 / (deps_GG - omegat_GG - 1j * self.eta * sign_GG) x_GG = W_GG * (sign_GG * (x1_GG - x2_GG) + x3_GG + x4_GG) dx_GG = W_GG * (sign_GG * (x1_GG**2 - x2_GG**2) + x3_GG**2 + x4_GG**2) nW_G = np.dot(n_mG[m], x_GG) sigma += np.vdot(n_mG[m], nW_G).real nW_G = np.dot(n_mG[m], dx_GG) dsigma -= np.vdot(n_mG[m], nW_G).real x = 1 / (self.qd.nbzkpts * 2 * pi * self.vol) return x * sigma, x * dsigma gpaw-0.11.0.13004/gpaw/response/gw.py0000664000175000017500000007076112553643470017252 0ustar jensjjensj00000000000000import os import sys import pickle import numpy as np from math import pi, sqrt from time import time, ctime from datetime import timedelta from ase.parallel import paropen from ase.units import Hartree, Bohr from ase.utils import devnull from gpaw import GPAW from gpaw.version import version from gpaw.mpi import world, rank, size, serial_comm from gpaw.utilities.blas import gemmdot from gpaw.xc.tools import vxc from gpaw.wavefunctions.pw import PWWaveFunctions from gpaw.response.parallel import set_communicator, parallel_partition, SliceAlongFrequency, GatherOrbitals from gpaw.response.base import BASECHI from gpaw.response.df0 import DF from gpaw.response.kernel import calculate_Kxc, calculate_Kc, calculate_Kc_q class GW(BASECHI): def __init__( self, file=None, nbands=None, bands=None, kpoints=None, e_skn=None, eshift=None, w=None, ecut=150., eta=0.1, ppa=False, E0=None, hilbert_trans=False, wpar=1, vcut=None, numint=False, txt=None ): BASECHI.__init__(self, calc=file, nbands=nbands, w=w, eshift=eshift, ecut=ecut, eta=eta, txt=devnull) self.file = file self.gwnbands = nbands self.bands = bands self.kpoints = kpoints self.user_skn = e_skn self.ppa = ppa self.E0 = E0 self.hilbert_trans = hilbert_trans self.wpar = wpar self.vcut = vcut self.numint = numint self.gwtxtname = txt def initialize(self): self.ini = True BASECHI.initialize(self) self.txtname = self.gwtxtname self.output_init() self.printtxt('GPAW version %s' %(version)) self.printtxt('-----------------------------------------------') self.printtxt('GW calculation started at:') self.printtxt(ctime()) self.printtxt('-----------------------------------------------') self.starttime = time() calc = self.calc kd = self.kd # band init if self.gwnbands is None: if self.npw > calc.wfs.bd.nbands: self.nbands = calc.wfs.bd.nbands else: self.nbands = self.npw # eigenvalue init if self.user_skn is not None: self.printtxt('Use eigenvalues from user.') assert np.shape(self.user_skn)[0] == self.nspins, 'Eigenvalues not compatible with .gpw file!' assert np.shape(self.user_skn)[1] == self.kd.nibzkpts, 'Eigenvalues not compatible with .gpw file!' assert np.shape(self.user_skn)[2] >= self.nbands, 'Too few eigenvalues!' self.e_skn = self.user_skn else: self.printtxt('Use eigenvalues from the calculator.') # q point init self.bzq_kc = kd.get_bz_q_points() self.ibzq_qc = self.bzq_kc # q point symmetry is not used at the moment. self.nqpt = np.shape(self.bzq_kc)[0] # frequency points init self.static=False if self.ppa: # Plasmon Pole Approximation if self.E0 is None: self.E0 = Hartree self.E0 /= Hartree self.w_w = np.array([0., 1j*self.E0]) self.hilbert_trans=False self.wpar=1 elif self.w_w is None: # static COHSEX self.w_w = np.array([0.]) self.static=True self.hilbert_trans=False self.wpar=1 self.eta = 0.0001 / Hartree else: # create nonlinear frequency grid # grid is linear from 0 to wcut with spacing dw # spacing is linearily increasing between wcut and wmax # Hilbert transforms are still carried out on linear grid wcut = self.w_w[0] wmax = self.w_w[1] dw = self.w_w[2] w_w = np.linspace(0., wcut, wcut/dw+1) i=1 wi=wcut while wi < wmax: wi += i*dw w_w = np.append(w_w, wi) i+=1 while len(w_w) % self.wpar != 0: wi += i*dw w_w = np.append(w_w, wi) i+=1 dw_w = np.zeros(len(w_w)) dw_w[0] = dw dw_w[1:] = w_w[1:] - w_w[:-1] self.w_w = w_w / Hartree self.dw_w = dw_w / Hartree self.eta_w = dw_w * 4 / Hartree self.wcut = wcut self.wmax = self.w_w[-1] self.wmin = self.w_w[0] self.dw = self.w_w[1] - self.w_w[0] self.Nw = len(self.w_w) # self.wpar = int(self.Nw * self.npw**2 * 16. / 1024**2) // 1500 + 1 # estimate memory and parallelize over frequencies for s in range(self.nspins): emaxdiff = self.e_skn[s][:,self.nbands-1].max() - self.e_skn[s][:,0].min() assert (self.wmax > emaxdiff), 'Maximum frequency must be larger than %f' %(emaxdiff*Hartree) # GW kpoints init if self.kpoints is None: self.gwnkpt = self.kd.nibzkpts self.gwkpt_k = kd.ibz2bz_k else: self.gwnkpt = np.shape(self.kpoints)[0] self.gwkpt_k = self.kpoints # GW bands init if self.bands is None: self.gwnband = self.nbands self.bands = self.gwbands_n = np.arange(self.nbands) else: self.gwnband = np.shape(self.bands)[0] self.gwbands_n = self.bands self.alpha = 1j/(2*pi * self.vol * self.kd.nbzkpts) # parallel init assert len(self.w_w) % self.wpar == 0 self.wcommsize = self.wpar self.qcommsize = size // self.wpar assert self.qcommsize * self.wcommsize == size, 'wpar must be integer divisor of number of requested cores' if self.nqpt != 1: # parallelize over q-points self.wcomm, self.qcomm, self.worldcomm = set_communicator(world, rank, size, self.wpar) self.ncomm = serial_comm self.dfcomm = self.wcomm self.kcommsize = 1 else: # parallelize over bands self.wcomm, self.ncomm, self.worldcomm = set_communicator(world, rank, size, self.wpar) self.qcomm = serial_comm if self.wpar > 1: self.dfcomm = self.wcomm self.kcommsize = 1 else: self.dfcomm = self.ncomm self.kcommsize = self.ncomm.size nq, self.nq_local, self.q_start, self.q_end = parallel_partition( self.nqpt, self.qcomm.rank, self.qcomm.size, reshape=False) nb, self.nbands_local, self.m_start, self.m_end = parallel_partition( self.nbands, self.ncomm.rank, self.ncomm.size, reshape=False) def get_QP_spectrum(self, exxfile='EXX.pckl', file='GW.pckl'): try: self.ini except: self.initialize() self.print_gw_init() self.printtxt("calculating Self energy") Sigma_skn = np.zeros((self.nspins, self.gwnkpt, self.gwnband), dtype=float) dSigma_skn = np.zeros((self.nspins, self.gwnkpt, self.gwnband), dtype=float) Z_skn = np.zeros((self.nspins, self.gwnkpt, self.gwnband), dtype=float) t0 = time() t_w = 0 t_selfenergy = 0 for iq in range(self.q_start, self.q_end): if iq >= self.nqpt: continue t1 = time() # get screened interaction. df, W_wGG = self.screened_interaction_kernel(iq) t2 = time() t_w += t2 - t1 # get self energy S, dS = self.get_self_energy(df, W_wGG) t3 = time() - t2 t_selfenergy += t3 Sigma_skn += S dSigma_skn += dS del df, W_wGG self.timing(iq, t0, self.nq_local, 'iq') self.qcomm.barrier() self.qcomm.sum(Sigma_skn) self.qcomm.sum(dSigma_skn) self.printtxt('W_wGG takes %s ' %(timedelta(seconds=round(t_w)))) self.printtxt('Self energy takes %s ' %(timedelta(seconds=round(t_selfenergy)))) Z_skn = 1. / (1. - dSigma_skn) # exact exchange exx = os.path.isfile(exxfile) world.barrier() if exx: open(exxfile) self.printtxt("reading Exact exchange and E_XC from file") else: t0 = time() self.get_exact_exchange() world.barrier() exxfile='EXX.pckl' self.printtxt('EXX takes %s ' %(timedelta(seconds=round(time()-t0)))) data = pickle.load(open(exxfile, 'rb')) vxc_skn = data['vxc_skn'] # in Hartree exx_skn = data['exx_skn'] # in Hartree f_skn = data['f_skn'] gwkpt_k = data['gwkpt_k'] gwbands_n = data['gwbands_n'] assert (gwkpt_k == self.gwkpt_k).all(), 'exxfile inconsistent with input parameters' assert (gwbands_n == self.gwbands_n).all(), 'exxfile inconsistent with input parameters' if self.user_skn is None: e_skn = data['e_skn'] # in Hartree else: e_skn = np.zeros((self.nspins, self.gwnkpt, self.gwnband), dtype=float) for s in range(self.nspins): for i, k in enumerate(self.gwkpt_k): ik = self.kd.bz2ibz_k[k] for j, n in enumerate(self.gwbands_n): if self.user_skn is None: assert e_skn[s][i][j] == self.e_skn[s][ik][n], 'exxfile inconsistent with eigenvalues' else: e_skn[s][i][j] = self.e_skn[s][ik][n] if not self.static: QP_skn = e_skn + Z_skn * (Sigma_skn + exx_skn - vxc_skn) else: QP_skn = e_skn + Sigma_skn - vxc_skn self.QP_skn = QP_skn # finish self.print_gw_finish(e_skn, f_skn, vxc_skn, exx_skn, Sigma_skn, Z_skn, QP_skn) data = { 'gwkpt_k': self.gwkpt_k, 'gwbands_n': self.gwbands_n, 'f_skn': f_skn, 'e_skn': e_skn, # in Hartree 'vxc_skn': vxc_skn, # in Hartree 'exx_skn': exx_skn, # in Hartree 'Sigma_skn': Sigma_skn, # in Hartree 'Z_skn': Z_skn, # dimensionless 'QP_skn': QP_skn # in Hartree } if rank == 0: pickle.dump(data, open(file, 'wb'), -1) def screened_interaction_kernel(self, iq): """Calcuate W_GG(w) for a given q. if static: return W_GG(w=0) is not static: return W_GG(q,w) - Vc_GG """ q = self.ibzq_qc[iq] w = self.w_w.copy()*Hartree optical_limit = False if np.abs(q).sum() < 1e-8: q = np.array([1e-12, 0, 0]) # arbitrary q, not really need to be calculated optical_limit = True hilbert_trans = True if self.ppa or self.static: hilbert_trans = False df = DF(calc=self.calc, q=q.copy(), w=w, nbands=self.nbands, eshift=None, optical_limit=optical_limit, hilbert_trans=hilbert_trans, xc='RPA', time_ordered=True, rpad=self.rpad, vcut=self.vcut, G_plus_q=True, eta=self.eta*Hartree, ecut=self.ecut.copy()*Hartree, txt='df.out', comm=self.dfcomm, kcommsize=self.kcommsize) df.initialize() df.e_skn = self.e_skn.copy() df.calculate() dfinv_wGG = df.get_inverse_dielectric_matrix(xc='RPA') assert df.ecut[0] == self.ecut[0] if not self.static and not self.ppa: assert df.eta == self.eta assert df.Nw == self.Nw assert df.dw == self.dw # calculate Coulomb kernel and use truncation in 2D delta_GG = np.eye(df.npw) Vq_G = np.diag(calculate_Kc(q, df.Gvec_Gc, self.acell_cv, self.bcell_cv, self.pbc, integrate_gamma=True, N_k=self.kd.N_c, vcut=self.vcut))**0.5 if (self.vcut == '2D' and df.optical_limit) or self.numint: for iG in range(len(df.Gvec_Gc)): if df.Gvec_Gc[iG, 0] == 0 and df.Gvec_Gc[iG, 1] == 0: v_q, v0_q = calculate_Kc_q(self.acell_cv, self.bcell_cv, self.pbc, self.kd.N_c, vcut=self.vcut, q_qc=np.array([q]), Gvec_c=df.Gvec_Gc[iG]) Vq_G[iG] = v_q[0]**0.5 self.Kc_GG = np.outer(Vq_G, Vq_G) if self.ppa: dfinv1_GG = dfinv_wGG[0] - delta_GG dfinv2_GG = dfinv_wGG[1] - delta_GG self.wt_GG = self.E0 * np.sqrt(dfinv2_GG / (dfinv1_GG - dfinv2_GG)) self.R_GG = - self.wt_GG / 2 * dfinv1_GG del dfinv_wGG dfinv_wGG = np.array([1j*pi*self.R_GG + delta_GG]) if self.static: assert len(dfinv_wGG) == 1 W_GG = dfinv_wGG[0] * self.Kc_GG return df, W_GG else: Nw = np.shape(dfinv_wGG)[0] W_wGG = np.zeros_like(dfinv_wGG) for iw in range(Nw): dfinv_wGG[iw] -= delta_GG W_wGG[iw] = dfinv_wGG[iw] * self.Kc_GG return df, W_wGG def get_self_energy(self, df, W_wGG): Sigma_skn = np.zeros((self.nspins, self.gwnkpt, self.gwnband), dtype=float) dSigma_skn = np.zeros((self.nspins, self.gwnkpt, self.gwnband), dtype=float) wcomm = df.wcomm if self.static: W_wGG = np.array([W_wGG]) if not self.hilbert_trans: #method 1 Wbackup_wG0 = W_wGG[:,:,0].copy() Wbackup_w0G = W_wGG[:,0,:].copy() else: #method 2, perform Hilbert transform nG = np.shape(W_wGG)[1] coords = np.zeros(wcomm.size, dtype=int) nG_local = nG**2 // wcomm.size if wcomm.rank == wcomm.size - 1: nG_local = nG**2 - (wcomm.size - 1) * nG_local wcomm.all_gather(np.array([nG_local]), coords) W_Wg = SliceAlongFrequency(W_wGG, coords, wcomm) ng = np.shape(W_Wg)[1] Nw = int(self.w_w[-1] / self.dw) w1_ww = np.zeros((Nw, df.Nw), dtype=complex) for iw in range(Nw): w1 = iw * self.dw w1_ww[iw] = 1./(w1 + self.w_w + 1j*self.eta_w) + 1./(w1 - self.w_w + 1j*self.eta_w) w1_ww[iw,0] -= 1./(w1 + 1j*self.eta_w[0]) # correct w'=0 w1_ww[iw] *= self.dw_w Cplus_Wg = np.zeros((Nw, ng), dtype=complex) Cminus_Wg = np.zeros((Nw, ng), dtype=complex) Cplus_Wg = gemmdot(w1_ww, W_Wg, beta=0.0) Cminus_Wg = gemmdot(w1_ww.conj(), W_Wg, beta=0.0) for s in range(self.nspins): for i, k in enumerate(self.gwkpt_k): # k is bzk index if df.optical_limit: kq_c = df.kd.bzk_kc[k] else: kq_c = df.kd.bzk_kc[k] - df.q_c # k - q kq = df.kd.where_is_q(kq_c, df.kd.bzk_kc) assert df.kq_k[kq] == k ibzkpt1 = df.kd.bz2ibz_k[k] ibzkpt2 = df.kd.bz2ibz_k[kq] for j, n in enumerate(self.bands): for m in range(self.m_start, self.m_end): if self.e_skn[s][ibzkpt2, m] > self.eFermi: sign = 1. else: sign = -1. rho_G = df.density_matrix(m, n, kq, spin1=s, spin2=s) if not self.hilbert_trans: #method 1 W_wGG[:,:,0] = Wbackup_wG0 W_wGG[:,0,:] = Wbackup_w0G # w1 = w - epsilon_m,k-q w1 = self.e_skn[s][ibzkpt1,n] - self.e_skn[s][ibzkpt2,m] if self.ppa: # analytical expression for Plasmon Pole Approximation W_GG = sign * W_wGG[0] * (1./(w1 + self.wt_GG - 1j*self.eta) - 1./(w1 - self.wt_GG + 1j*self.eta)) W_GG -= W_wGG[0] * (1./(w1 + self.wt_GG + 1j*self.eta*sign) + 1./(w1 - self.wt_GG + 1j*self.eta*sign)) W_G = gemmdot(W_GG, rho_G, beta=0.0) Sigma_skn[s,i,j] += np.real(gemmdot(W_G, rho_G, alpha=self.alpha, beta=0.0,trans='c')) W_GG = sign * W_wGG[0] * (1./(w1 - self.wt_GG + 1j*self.eta)**2 - 1./(w1 + self.wt_GG - 1j*self.eta)**2) W_GG += W_wGG[0] * (1./(w1 - self.wt_GG + 1j*self.eta*sign)**2 + 1./(w1 + self.wt_GG + 1j*self.eta*sign)**2) W_G = gemmdot(W_GG, rho_G, beta=0.0) dSigma_skn[s,i,j] += np.real(gemmdot(W_G, rho_G, alpha=self.alpha, beta=0.0,trans='c')) elif self.static: W1_GG = W_wGG[0] - np.eye(df.npw)*self.Kc_GG W2_GG = W_wGG[0] # perform W_GG * np.outer(rho_G.conj(), rho_G).sum(GG) W_G = gemmdot(W1_GG, rho_G, beta=0.0) # Coulomb Hole Sigma_skn[s,i,j] += np.real(gemmdot(W_G, rho_G, alpha=self.alpha*pi/1j, beta=0.0,trans='c')) if sign == -1: W_G = gemmdot(W2_GG, rho_G, beta=0.0) # Screened Exchange Sigma_skn[s,i,j] -= np.real(gemmdot(W_G, rho_G, alpha=2*self.alpha*pi/1j, beta=0.0,trans='c')) del W1_GG, W2_GG, W_G, rho_G else: # perform W_wGG * np.outer(rho_G.conj(), rho_G).sum(GG) W_wG = gemmdot(W_wGG, rho_G, beta=0.0) C_wlocal = gemmdot(W_wG, rho_G, alpha=self.alpha, beta=0.0,trans='c') del W_wG, rho_G C_w = np.zeros(df.Nw, dtype=complex) wcomm.all_gather(C_wlocal, C_w) del C_wlocal # calculate self energy w1_w = 1./(w1 - self.w_w + 1j*self.eta_w*sign) + 1./(w1 + self.w_w + 1j*self.eta_w*sign) w1_w[0] -= 1./(w1 + 1j*self.eta_w[0]*sign) # correct w'=0 w1_w *= self.dw_w Sigma_skn[s,i,j] += np.real(gemmdot(C_w, w1_w, beta=0.0)) # calculate derivate of self energy with respect to w w1_w = 1./(w1 - self.w_w + 1j*self.eta_w*sign)**2 + 1./(w1 + self.w_w + 1j*self.eta_w*sign)**2 w1_w[0] -= 1./(w1 + 1j*self.eta_w[0]*sign)**2 # correct w'=0 w1_w *= self.dw_w dSigma_skn[s,i,j] -= np.real(gemmdot(C_w, w1_w, beta=0.0)) else: #method 2 if not np.abs(self.e_skn[s][ibzkpt2,m] - self.e_skn[s][ibzkpt1,n]) < 1e-10: sign *= np.sign(self.e_skn[s][ibzkpt1,n] - self.e_skn[s][ibzkpt2,m]) # find points on frequency grid w0 = self.e_skn[s][ibzkpt1,n] - self.e_skn[s][ibzkpt2,m] w0_id = np.abs(int(w0 / self.dw)) w1 = w0_id * self.dw w2 = (w0_id + 1) * self.dw # choose plus or minus, treat optical limit: if sign == 1: C_Wg = Cplus_Wg[w0_id:w0_id+2] # only two grid points needed for each w0 if sign == -1: C_Wg = Cminus_Wg[w0_id:w0_id+2] # only two grid points needed for each w0 C_wGG = GatherOrbitals(C_Wg, coords, wcomm).copy() del C_Wg # special treat of w0 = 0 (degenerate states): if w0_id == 0: Cplustmp_GG = GatherOrbitals(Cplus_Wg[1], coords, wcomm).copy() Cminustmp_GG = GatherOrbitals(Cminus_Wg[1], coords, wcomm).copy() # perform C_wGG * np.outer(rho_G.conj(), rho_G).sum(GG) if w0_id == 0: Sw0_G = gemmdot(C_wGG[0], rho_G, beta=0.0) Sw0 = np.real(gemmdot(Sw0_G, rho_G, alpha=self.alpha, beta=0.0, trans='c')) Sw1_G = gemmdot(Cplustmp_GG, rho_G, beta=0.0) Sw1 = np.real(gemmdot(Sw1_G, rho_G, alpha=self.alpha, beta=0.0, trans='c')) Sw2_G = gemmdot(Cminustmp_GG, rho_G, beta=0.0) Sw2 = np.real(gemmdot(Sw2_G, rho_G, alpha=self.alpha, beta=0.0, trans='c')) Sigma_skn[s,i,j] += Sw0 dSigma_skn[s,i,j] += (Sw1 + Sw2)/(2*self.dw) else: Sw1_G = gemmdot(C_wGG[0], rho_G, beta=0.0) Sw1 = np.real(gemmdot(Sw1_G, rho_G, alpha=self.alpha, beta=0.0, trans='c')) Sw2_G = gemmdot(C_wGG[1], rho_G, beta=0.0) Sw2 = np.real(gemmdot(Sw2_G, rho_G, alpha=self.alpha, beta=0.0, trans='c')) Sw0 = (w2-np.abs(w0))/self.dw * Sw1 + (np.abs(w0)-w1)/self.dw * Sw2 Sigma_skn[s,i,j] += np.sign(self.e_skn[s][ibzkpt1,n] - self.e_skn[s][ibzkpt2,m]) * Sw0 dSigma_skn[s,i,j] += (Sw2 - Sw1)/self.dw self.ncomm.barrier() self.ncomm.sum(Sigma_skn) self.ncomm.sum(dSigma_skn) return Sigma_skn, dSigma_skn def get_exact_exchange(self, ecut=None, communicator=world, file='EXX.pckl'): try: self.ini except: self.initialize() self.printtxt('------------------------------------------------') self.printtxt("calculating Exact exchange and E_XC") calc = GPAW(self.file, communicator=communicator, parallel={'domain':1, 'band':1}, txt=None) v_xc = vxc(calc) if ecut is None: ecut = self.ecut.max() else: ecut /= Hartree if self.pwmode: # planewave mode from gpaw.xc.hybridg import HybridXC self.printtxt('Use planewave ecut from groundstate calculator: %4.1f eV' % (calc.wfs.pd.ecut*Hartree) ) exx = HybridXC('EXX', alpha=5.0, bandstructure=True, bands=self.bands) else: # grid mode from gpaw.xc.hybridk import HybridXC self.printtxt('Planewave ecut (eV): %4.1f' % (ecut*Hartree) ) exx = HybridXC('EXX', alpha=5.0, ecut=ecut, bands=self.bands) calc.get_xc_difference(exx) e_skn = np.zeros((self.nspins, self.gwnkpt, self.gwnband), dtype=float) f_skn = np.zeros((self.nspins, self.gwnkpt, self.gwnband), dtype=float) vxc_skn = np.zeros((self.nspins, self.gwnkpt, self.gwnband), dtype=float) exx_skn = np.zeros((self.nspins, self.gwnkpt, self.gwnband), dtype=float) for s in range(self.nspins): for i, k in enumerate(self.gwkpt_k): ik = self.kd.bz2ibz_k[k] for j, n in enumerate(self.gwbands_n): e_skn[s][i][j] = self.e_skn[s][ik][n] f_skn[s][i][j] = self.f_skn[s][ik][n] vxc_skn[s][i][j] = v_xc[s][ik][n] / Hartree exx_skn[s][i][j] = exx.exx_skn[s][ik][n] if self.eshift is not None: if e_skn[s][i][j] > self.eFermi: vxc_skn[s][i][j] += self.eshift / Hartree data = { 'e_skn': e_skn, # in Hartree 'vxc_skn': vxc_skn, # in Hartree 'exx_skn': exx_skn, # in Hartree 'f_skn': f_skn, 'gwkpt_k': self.gwkpt_k, 'gwbands_n': self.gwbands_n } if rank == 0: pickle.dump(data, open(file, 'wb'), -1) self.printtxt("------------------------------------------------") self.printtxt("non-selfconsistent HF eigenvalues are (eV):") self.printtxt((e_skn - vxc_skn + exx_skn)*Hartree) def print_gw_init(self): if self.eshift is not None: self.printtxt('Shift unoccupied bands by %f eV' % (self.eshift)) for s in range(self.nspins): self.printtxt('Lowest eigenvalue (spin=%s) : %f eV' %(s, self.e_skn[s][:, 0].min()*Hartree)) self.printtxt('Highest eigenvalue (spin=%s): %f eV' %(s, self.e_skn[s][:, self.nbands-1].max()*Hartree)) self.printtxt('') if self.ecut[0] == self.ecut[1] and self.ecut[0] == self.ecut[2]: self.printtxt('Plane wave ecut (eV) : %4.1f' % (self.ecut[0]*Hartree)) else: self.printtxt('Plane wave ecut (eV) : (%f, %f, %f)' % (self.ecut[0]*Hartree,self.ecut[1]*Hartree,self.ecut[2]*Hartree) ) self.printtxt('Number of plane waves used : %d' %(self.npw) ) self.printtxt('Number of bands : %d' %(self.nbands) ) self.printtxt('Number of k points : %d' %(self.kd.nbzkpts) ) self.printtxt("Number of IBZ k points : %d" %(self.kd.nibzkpts)) self.printtxt("Number of spins : %d" %(self.nspins)) self.printtxt('') if self.ppa: self.printtxt("Use Plasmon Pole Approximation") self.printtxt("imaginary frequency (eV) : %.2f" %(self.E0*Hartree)) self.printtxt("broadening (eV) : %.2f" %(self.eta*Hartree)) elif self.static: self.printtxt("Use static COHSEX") else: self.printtxt("Linear frequency grid (eV) : %.2f - %.2f in %.2f" %(self.wmin*Hartree, self.wcut, self.dw*Hartree)) self.printtxt("Maximum frequency (eV) : %.2f" %(self.wmax*Hartree)) self.printtxt("Number of frequency points : %d" %(self.Nw)) self.printtxt("Use Hilbert transform : %s" %(self.hilbert_trans)) self.printtxt('') self.printtxt('Coulomb interaction cutoff : %s' % self.vcut) self.printtxt('') self.printtxt('Calculate matrix elements for k = :') for k in self.gwkpt_k: self.printtxt(self.kd.bzk_kc[k]) self.printtxt('') self.printtxt('Calculate matrix elements for n = :') self.printtxt(self.gwbands_n) self.printtxt('') def print_gw_finish(self, e_skn, f_skn, vxc_skn, exx_skn, Sigma_skn, Z_skn, QP_skn): self.printtxt("------------------------------------------------") self.printtxt("Kohn-Sham eigenvalues are (eV): ") self.printtxt("%s \n" %(e_skn*Hartree)) self.printtxt("Occupation numbers are: ") self.printtxt("%s \n" %(f_skn*self.kd.nbzkpts)) self.printtxt("Kohn-Sham exchange-correlation contributions are (eV): ") self.printtxt("%s \n" %(vxc_skn*Hartree)) self.printtxt("Exact exchange contributions are (eV): ") self.printtxt("%s \n" %(exx_skn*Hartree)) self.printtxt("Self energy contributions are (eV):") self.printtxt("%s \n" %(Sigma_skn*Hartree)) if not self.static: self.printtxt("Renormalization factors are:") self.printtxt("%s \n" %(Z_skn)) totaltime = round(time() - self.starttime) self.printtxt("GW calculation finished in %s " %(timedelta(seconds=totaltime))) self.printtxt("------------------------------------------------") self.printtxt("Quasi-particle energies are (eV): ") self.printtxt(QP_skn*Hartree) gpaw-0.11.0.13004/gpaw/response/math_func.py0000664000175000017500000002165012553643470020572 0ustar jensjjensj00000000000000from math import sqrt, pi import numpy as np from scipy.special.specfun import sphj from gpaw.utilities.blas import gemmdot from gpaw.gaunt import nabla, gaunt from gpaw.spherical_harmonics import Y def delta_function(x0, dx, Nx, sigma): deltax = np.zeros(Nx) for i in range(Nx): deltax[i] = np.exp(-(i * dx - x0)**2 / (4. * sigma)) return deltax / (2. * sqrt(pi * sigma)) def hilbert_transform(specfunc_wGG, w_w, Nw, dw, eta, fullresponse=False): NwS = specfunc_wGG.shape[0] tmp_ww = np.zeros((Nw, NwS), dtype=complex) ww_w = np.linspace(0., (NwS - 1) * dw, NwS) for iw in range(Nw): if fullresponse is False: tmp_ww[iw] = (1. / (w_w[iw] - ww_w + 1j * eta) - 1. / (w_w[iw] + ww_w + 1j * eta)) else: tmp_ww[iw] = (1. / (w_w[iw] - ww_w + 1j * eta) - 1. / (w_w[iw] + ww_w - 1j * eta)) chi0_wGG = gemmdot(tmp_ww, specfunc_wGG, beta=0.) return chi0_wGG * dw def two_phi_planewave_integrals(k_Gv, setup=None, Gstart=0, Gend=None, rgd=None, phi_jg=None, phit_jg=None, l_j=None): """Calculate PAW-correction matrix elements with planewaves. :: / _ _ ik.r _ ~ _ ik.r ~ _ | dr [phi (r) e phi (r) - phi (r) e phi (r)] / 1 2 1 2 ll - / 2 ~ ~ = 4pi \sum_lm i Y (k) | dr r [ phi (r) phi (r) - phi (r) phi (r) j (kr) lm / 1 2 1 2 ll / * | d\Omega Y Y Y / l1m1 l2m2 lm """ if Gend is None: Gend = len(k_Gv) if setup is not None: rgd = setup.rgd l_j = setup.l_j # Obtain the phi_j and phit_j phi_jg = [] phit_jg = [] rcut2 = 2 * max(setup.rcut_j) gcut2 = rgd.ceil(rcut2) for phi_g, phit_g in zip(setup.data.phi_jg, setup.data.phit_jg): phi_g = phi_g.copy() phit_g = phit_g.copy() phi_g[gcut2:] = phit_g[gcut2:] = 0. phi_jg.append(phi_g) phit_jg.append(phit_g) else: assert rgd is not None assert phi_jg is not None assert l_j is not None ng = rgd.N r_g = rgd.r_g dr_g = rgd.dr_g # Construct L (l**2 + m) and j (nl) index L_i = [] j_i = [] for j, l in enumerate(l_j): for m in range(2 * l + 1): L_i.append(l**2 + m) j_i.append(j) ni = len(L_i) nj = len(l_j) lmax = max(l_j) * 2 + 1 if setup is not None: assert ni == setup.ni and nj == setup.nj # Initialize npw = k_Gv.shape[0] R_jj = np.zeros((nj, nj)) R_ii = np.zeros((ni, ni)) phi_Gii = np.zeros((npw, ni, ni), dtype=complex) j_lg = np.zeros((lmax, ng)) # Store (phi_j1 * phi_j2 - phit_j1 * phit_j2 ) for further use tmp_jjg = np.zeros((nj, nj, ng)) for j1 in range(nj): for j2 in range(nj): tmp_jjg[j1, j2] = (phi_jg[j1] * phi_jg[j2] - phit_jg[j1] * phit_jg[j2]) G_LLL = gaunt(max(l_j)) # Loop over G vectors for iG in range(Gstart, Gend): kk = k_Gv[iG] k = np.sqrt(np.dot(kk, kk)) # calculate length of q+G # Calculating spherical bessel function for g, r in enumerate(r_g): j_lg[:, g] = sphj(lmax - 1, k * r)[1] for li in range(lmax): # Radial part for j1 in range(nj): for j2 in range(nj): R_jj[j1, j2] = np.dot(r_g**2 * dr_g, tmp_jjg[j1, j2] * j_lg[li]) for mi in range(2 * li + 1): # Angular part for i1 in range(ni): L1 = L_i[i1] j1 = j_i[i1] for i2 in range(ni): L2 = L_i[i2] j2 = j_i[i2] R_ii[i1, i2] = G_LLL[L1, L2, li**2 + mi] * R_jj[j1, j2] phi_Gii[iG] += R_ii * Y(li**2 + mi, kk[0] / k, kk[1] / k, kk[2] / k) * (-1j)**li phi_Gii *= 4 * pi return phi_Gii.reshape(npw, ni * ni) def two_phi_nabla_planewave_integrals(k_Gv, setup=None, Gstart=0, Gend=None, rgd=None, phi_jg=None, phit_jg=None, l_j=None): """Calculate PAW-correction matrix elements with planewaves and gradient. :: / _ _ ik.r d _ ~ _ ik.r d ~ _ | dr [phi (r) e -- phi (r) - phi (r) e -- phi (r)] / 1 dx 2 1 dx 2 and similar for y and z.""" if Gend is None: Gend = len(k_Gv) if setup is not None: rgd = setup.rgd l_j = setup.l_j # Obtain the phi_j and phit_j phi_jg = [] phit_jg = [] rcut2 = 2 * max(setup.rcut_j) gcut2 = rgd.ceil(rcut2) for phi_g, phit_g in zip(setup.data.phi_jg, setup.data.phit_jg): phi_g = phi_g.copy() phit_g = phit_g.copy() phi_g[gcut2:] = phit_g[gcut2:] = 0. phi_jg.append(phi_g) phit_jg.append(phit_g) else: assert rgd is not None assert phi_jg is not None assert l_j is not None ng = rgd.N r_g = rgd.r_g dr_g = rgd.dr_g # Construct L (l**2 + m) and j (nl) index L_i = [] j_i = [] for j, l in enumerate(l_j): for m in range(2 * l + 1): L_i.append(l**2 + m) j_i.append(j) ni = len(L_i) nj = len(l_j) lmax = max(l_j) * 2 + 1 ljdef = 3 l2max = max(l_j) * (max(l_j) > ljdef) + ljdef * (max(l_j) <= ljdef) G_LLL = gaunt(l2max) Y_LLv = nabla(2 * l2max) if setup is not None: assert ni == setup.ni and nj == setup.nj # Initialize npw = k_Gv.shape[0] R1_jj = np.zeros((nj, nj)) R2_jj = np.zeros((nj, nj)) R_vii = np.zeros((3, ni, ni)) phi_vGii = np.zeros((3, npw, ni, ni), dtype=complex) j_lg = np.zeros((lmax, ng)) # Store (phi_j1 * dphidr_j2 - phit_j1 * dphitdr_j2) for further use tmp_jjg = np.zeros((nj, nj, ng)) tmpder_jjg = np.zeros((nj, nj, ng)) for j1 in range(nj): for j2 in range(nj): dphidr_g = np.empty_like(phi_jg[j2]) rgd.derivative(phi_jg[j2], dphidr_g) dphitdr_g = np.empty_like(phit_jg[j2]) rgd.derivative(phit_jg[j2], dphitdr_g) tmpder_jjg[j1, j2] = (phi_jg[j1] * dphidr_g - phit_jg[j1] * dphitdr_g) tmp_jjg[j1, j2] = (phi_jg[j1] * phi_jg[j2] - phit_jg[j1] * phit_jg[j2]) # Loop over G vectors for iG in range(Gstart, Gend): kk = k_Gv[iG] k = np.sqrt(np.dot(kk, kk)) # calculate length of q+G # Calculating spherical bessel function for g, r in enumerate(r_g): j_lg[:, g] = sphj(lmax - 1, k * r)[1] for li in range(lmax): # Radial part for j1 in range(nj): for j2 in range(nj): R1_jj[j1, j2] = np.dot(r_g**2 * dr_g, tmpder_jjg[j1, j2] * j_lg[li]) R2_jj[j1, j2] = np.dot(r_g * dr_g, tmp_jjg[j1, j2] * j_lg[li]) for mi in range(2 * li + 1): if k == 0: Ytmp = Y(li**2 + mi, 1.0, 0, 0) else: # Note the spherical bessel gives # zero when k == 0 for li != 0 Ytmp = Y(li**2 + mi, kk[0] / k, kk[1] / k, kk[2] / k) for v in range(3): Lv = 1 + (v + 2) % 3 # Angular part for i1 in range(ni): L1 = L_i[i1] j1 = j_i[i1] for i2 in range(ni): L2 = L_i[i2] j2 = j_i[i2] l2 = l_j[j2] R_vii[v, i1, i2] = ((4 * pi / 3)**0.5 * np.dot(G_LLL[L1, L2], G_LLL[Lv, li**2 + mi]) * (R1_jj[j1, j2] - l2 * R2_jj[j1, j2])) R_vii[v, i1, i2] += (R2_jj[j1, j2] * np.dot(G_LLL[L1, li**2 + mi], Y_LLv[:, L2, v])) phi_vGii[:, iG] += (R_vii * Ytmp * (-1j)**li) phi_vGii *= 4 * pi return phi_vGii.reshape(3, npw, ni * ni) gpaw-0.11.0.13004/gpaw/response/chi.py0000664000175000017500000006642412553643470017401 0ustar jensjjensj00000000000000from __future__ import print_function import sys from time import time, ctime import numpy as np from math import sqrt, pi from ase.units import Hartree, Bohr from gpaw import extra_parameters from gpaw.utilities.blas import gemv, scal, axpy, czher from gpaw.mpi import world, rank, size, serial_comm from gpaw.fd_operators import Gradient from gpaw.response.math_func import hilbert_transform from gpaw.response.parallel import set_communicator, \ parallel_partition, parallel_partition_list, SliceAlongFrequency, SliceAlongOrbitals from gpaw.response.kernel import calculate_Kxc, calculate_Kc from gpaw.response.kernel import CoulombKernel from gpaw.utilities.memory import maxrss from gpaw.response.base import BASECHI class CHI(BASECHI): """This class is a calculator for the linear density response function. Parameters: nband: int Number of bands. wmax: floadent Maximum energy for spectrum. dw: float Frequency interval. wlist: tuple Frequency points. q: ndarray Momentum transfer in reduced coordinate. Ecut: ndarray Planewave cutoff energy. eta: float Spectrum broadening factor. sigma: float Width for delta function. """ def __init__(self, calc=None, nbands=None, w=None, q=None, eshift=None, ecut=10., density_cut=None, G_plus_q=False, eta=0.2, rpad=None, vcut=None, ftol=1e-5, txt=None, xc='ALDA', hilbert_trans=True, time_ordered=False, optical_limit=False, comm=None, kcommsize=None): BASECHI.__init__(self, calc=calc, nbands=nbands, w=w, q=q, eshift=eshift, ecut=ecut, density_cut=density_cut, G_plus_q=G_plus_q, eta=eta, rpad=rpad, ftol=ftol, txt=txt, optical_limit=optical_limit) #if vcut is None: # vcut = '%dD' % self.calc.wfs.gd.pbc_c.sum() self.vcut = vcut self.xc = xc self.hilbert_trans = hilbert_trans self.full_hilbert_trans = time_ordered self.kcommsize = kcommsize self.comm = comm if self.comm is None: self.comm = world self.chi0_wGG = None def initialize(self, simple_version=False): self.printtxt('') self.printtxt('-----------------------------------------') self.printtxt('Response function calculation started at:') self.starttime = time() self.printtxt(ctime()) BASECHI.initialize(self) # Frequency init self.dw = None if len(self.w_w) == 1: self.hilbert_trans = False if self.hilbert_trans: self.dw = self.w_w[1] - self.w_w[0] # assert ((self.w_w[1:] - self.w_w[:-1] - self.dw) < 1e-10).all() # make sure its linear w grid assert self.w_w.max() == self.w_w[-1] self.dw /= Hartree self.w_w /= Hartree self.wmax = self.w_w[-1] self.wcut = self.wmax + 5. / Hartree # self.Nw = int(self.wmax / self.dw) + 1 self.Nw = len(self.w_w) self.NwS = int(self.wcut / self.dw) + 1 else: self.Nw = len(self.w_w) self.NwS = 0 if len(self.w_w) > 2: self.dw = self.w_w[1] - self.w_w[0] assert ((self.w_w[1:] - self.w_w[:-1] - self.dw) < 1e-10).all() self.dw /= Hartree self.nvalbands = self.nbands tmpn = np.zeros(self.nspins, dtype=int) for spin in range(self.nspins): for n in range(self.nbands): if (self.f_skn[spin][:, n] - self.ftol < 0).all(): tmpn[spin] = n break if tmpn.max() > 0: self.nvalbands = tmpn.max() # Parallelization initialize self.parallel_init() # Printing calculation information self.print_chi() if extra_parameters.get('df_dry_run'): raise SystemExit calc = self.calc # For LCAO wfs if calc.input_parameters['mode'] == 'lcao': calc.initialize_positions() self.printtxt(' Max mem sofar : %f M / cpu' %(maxrss() / 1024**2)) if simple_version is True: return # PAW part init # calculate # G != 0 part self.phi_aGp, self.phiG0_avp = self.get_phi_aGp(alldir=True) self.printtxt('Finished phi_aGp !') mem = np.array([self.phi_aGp[i].size * 16 /1024.**2 for i in range(len(self.phi_aGp))]) self.printtxt(' Phi_aGp : %f M / cpu' %(mem.sum())) # Calculate ALDA kernel (not used in chi0) R_av = calc.atoms.positions / Bohr if self.xc == 'RPA': #type(self.w_w[0]) is float: self.Kc_GG = None self.printtxt('RPA calculation.') elif self.xc == 'ALDA' or self.xc == 'ALDA_X': #self.Kc_GG = calculate_Kc(self.q_c, # self.Gvec_Gc, # self.acell_cv, # self.bcell_cv, # self.calc.atoms.pbc, # self.vcut) # Initialize a CoulombKernel instance kernel = CoulombKernel(vcut=self.vcut, pbc=self.calc.atoms.pbc, cell=self.acell_cv) self.Kc_GG = kernel.calculate_Kc(self.q_c, self.Gvec_Gc, self.bcell_cv) self.Kxc_sGG = calculate_Kxc(self.gd, # global grid self.gd.zero_pad(calc.density.nt_sG), self.npw, self.Gvec_Gc, self.gd.N_c, self.vol, self.bcell_cv, R_av, calc.wfs.setups, calc.density.D_asp, functional=self.xc, density_cut=self.density_cut) self.printtxt('Finished %s kernel ! ' % self.xc) return def pawstuff(self, psit_g, k, n, spin, u, ibzkpt): if not self.pwmode: if self.calc.wfs.world.size > 1 or self.kd.nbzkpts == 1: P_ai = self.pt.dict() self.pt.integrate(psit_g, P_ai, k) else: P_ai = self.get_P_ai(k, n, spin) else: # first calculate P_ai at ibzkpt, then rotate to k Ptmp_ai = self.pt.dict() kpt = self.calc.wfs.kpt_u[u] self.pt.integrate(kpt.psit_nG[n], Ptmp_ai, ibzkpt) P_ai = self.get_P_ai(k, n, spin, Ptmp_ai) return P_ai def calculate(self, seperate_spin=None): """Calculate the non-interacting density response function. """ calc = self.calc kd = self.kd gd = self.gd sdisp_cd = gd.sdisp_cd ibzk_kc = kd.ibzk_kc bzk_kc = kd.bzk_kc kq_k = self.kq_k f_skn = self.f_skn e_skn = self.e_skn # Matrix init chi0_wGG = np.zeros((self.Nw_local, self.npw, self.npw), dtype=complex) if self.hilbert_trans: specfunc_wGG = np.zeros((self.NwS_local, self.npw, self.npw), dtype = complex) # Prepare for the derivative of pseudo-wavefunction if self.optical_limit: d_c = [Gradient(gd, i, n=4, dtype=complex).apply for i in range(3)] dpsit_g = gd.empty(dtype=complex) tmp = np.zeros((3), dtype=complex) rhoG0_v = np.zeros(3, dtype=complex) self.chi0G0_wGv = np.zeros((self.Nw_local, self.npw, 3), dtype=complex) self.chi00G_wGv = np.zeros((self.Nw_local, self.npw, 3), dtype=complex) specfuncG0_wGv = np.zeros((self.NwS_local, self.npw, 3), dtype=complex) specfunc0G_wGv = np.zeros((self.NwS_local, self.npw, 3), dtype=complex) use_zher = False if self.eta < 1e-5: use_zher = True rho_G = np.zeros(self.npw, dtype=complex) t0 = time() if seperate_spin is None: spinlist = np.arange(self.nspins) else: spinlist = [seperate_spin] for spin in spinlist: if not (f_skn[spin] > self.ftol).any(): self.chi0_wGG = chi0_wGG continue for k in range(self.kstart, self.kend): k_pad = False if k >= self.kd.nbzkpts: k = 0 k_pad = True # Find corresponding kpoint in IBZ ibzkpt1 = kd.bz2ibz_k[k] if self.optical_limit: ibzkpt2 = ibzkpt1 else: ibzkpt2 = kd.bz2ibz_k[kq_k[k]] if self.pwmode: N_c = self.gd.N_c k_c = self.kd.ibzk_kc[ibzkpt1] eikr1_R = np.exp(2j * pi * np.dot(np.indices(N_c).T, k_c / N_c).T) k_c = self.kd.ibzk_kc[ibzkpt2] eikr2_R = np.exp(2j * pi * np.dot(np.indices(N_c).T, k_c / N_c).T) index1_g, phase1_g = kd.get_transform_wavefunction_index(self.gd.N_c - (self.pbc == False), k) index2_g, phase2_g = kd.get_transform_wavefunction_index(self.gd.N_c - (self.pbc == False), kq_k[k]) for n in range(self.nvalbands): if self.calc.wfs.world.size == 1: if (self.f_skn[spin][ibzkpt1, n] - self.ftol < 0): continue t1 = time() if self.pwmode: u = self.kd.get_rank_and_index(spin, ibzkpt1)[1] psitold_g = calc.wfs._get_wave_function_array(u, n, realspace=True, phase=eikr1_R) else: u = None psitold_g = self.get_wavefunction(ibzkpt1, n, True, spin=spin) psit1new_g = kd.transform_wave_function(psitold_g,k,index1_g,phase1_g) P1_ai = self.pawstuff(psit1new_g, k, n, spin, u, ibzkpt1) psit1_g = psit1new_g.conj() * self.expqr_g for m in self.mlist: if self.nbands > 1000 and m % 200 == 0: print(' ', k, n, m, time() - t0, file=self.txt) check_focc = (f_skn[spin][ibzkpt1, n] - f_skn[spin][ibzkpt2, m]) > self.ftol if not self.pwmode: psitold_g = self.get_wavefunction(ibzkpt2, m, check_focc, spin=spin) if check_focc: if self.pwmode: u = self.kd.get_rank_and_index(spin, ibzkpt2)[1] psitold_g = calc.wfs._get_wave_function_array(u, m, realspace=True, phase=eikr2_R) psit2_g = kd.transform_wave_function(psitold_g, kq_k[k], index2_g, phase2_g) # zero padding is included through the FFT rho_g = np.fft.fftn(psit2_g * psit1_g, s=self.nGrpad) * self.vol / self.nG0rpad # Here, planewave cutoff is applied rho_G = rho_g.ravel()[self.Gindex_G] if self.optical_limit: phase_cd = np.exp(2j * pi * sdisp_cd * kd.bzk_kc[kq_k[k], :, np.newaxis]) for ix in range(3): d_c[ix](psit2_g, dpsit_g, phase_cd) tmp[ix] = gd.integrate(psit1_g * dpsit_g) rho_G[0] = -1j * np.dot(self.qq_v, tmp) for ix in range(3): q2_c = np.diag((1,1,1))[ix] * self.qopt qq2_v = np.dot(q2_c, self.bcell_cv) # summation over c rhoG0_v[ix] = -1j * np.dot(qq2_v, tmp) P2_ai = self.pawstuff(psit2_g, kq_k[k], m, spin, u, ibzkpt2) for a, id in enumerate(calc.wfs.setups.id_a): P_p = np.outer(P1_ai[a].conj(), P2_ai[a]).ravel() gemv(1.0, self.phi_aGp[a], P_p, 1.0, rho_G) if self.optical_limit: gemv(1.0, self.phiG0_avp[a], P_p, 1.0, rhoG0_v) if self.optical_limit: if np.abs(self.enoshift_skn[spin][ibzkpt2, m] - self.enoshift_skn[spin][ibzkpt1, n]) > 0.1/Hartree: rho_G[0] /= self.enoshift_skn[spin][ibzkpt2, m] \ - self.enoshift_skn[spin][ibzkpt1, n] rhoG0_v /= self.enoshift_skn[spin][ibzkpt2, m] \ - self.enoshift_skn[spin][ibzkpt1, n] else: rho_G[0] = 0. rhoG0_v[:] = 0. if k_pad: rho_G[:] = 0. if self.optical_limit: rho0G_Gv = np.outer(rho_G.conj(), rhoG0_v) rhoG0_Gv = np.outer(rho_G, rhoG0_v.conj()) rho0G_Gv[0,:] = rhoG0_v * rhoG0_v.conj() rhoG0_Gv[0,:] = rhoG0_v * rhoG0_v.conj() if not self.hilbert_trans: if not use_zher: rho_GG = np.outer(rho_G, rho_G.conj()) for iw in range(self.Nw_local): w = self.w_w[iw + self.wstart] / Hartree coef = ( 1. / (w + e_skn[spin][ibzkpt1, n] - e_skn[spin][ibzkpt2, m] + 1j * self.eta) - 1. / (w - e_skn[spin][ibzkpt1, n] + e_skn[spin][ibzkpt2, m] + 1j * self.eta) ) C = (f_skn[spin][ibzkpt1, n] - f_skn[spin][ibzkpt2, m]) * coef if use_zher: czher(C.real, rho_G.conj(), chi0_wGG[iw]) else: axpy(C, rho_GG, chi0_wGG[iw]) if self.optical_limit: axpy(C, rho0G_Gv, self.chi00G_wGv[iw]) axpy(C, rhoG0_Gv, self.chi0G0_wGv[iw]) else: rho_GG = np.outer(rho_G, rho_G.conj()) focc = f_skn[spin][ibzkpt1,n] - f_skn[spin][ibzkpt2,m] w0 = e_skn[spin][ibzkpt2,m] - e_skn[spin][ibzkpt1,n] scal(focc, rho_GG) if self.optical_limit: scal(focc, rhoG0_Gv) scal(focc, rho0G_Gv) # calculate delta function w0_id = int(w0 / self.dw) if w0_id + 1 < self.NwS: # rely on the self.NwS_local is equal in each node! if self.wScomm.rank == w0_id // self.NwS_local: alpha = (w0_id + 1 - w0/self.dw) / self.dw axpy(alpha, rho_GG, specfunc_wGG[w0_id % self.NwS_local] ) if self.optical_limit: axpy(alpha, rho0G_Gv, specfunc0G_wGv[w0_id % self.NwS_local] ) axpy(alpha, rhoG0_Gv, specfuncG0_wGv[w0_id % self.NwS_local] ) if self.wScomm.rank == (w0_id+1) // self.NwS_local: alpha = (w0 / self.dw - w0_id) / self.dw axpy(alpha, rho_GG, specfunc_wGG[(w0_id+1) % self.NwS_local] ) if self.optical_limit: axpy(alpha, rho0G_Gv, specfunc0G_wGv[(w0_id+1) % self.NwS_local] ) axpy(alpha, rhoG0_Gv, specfuncG0_wGv[(w0_id+1) % self.NwS_local] ) # deltaw = delta_function(w0, self.dw, self.NwS, self.sigma) # for wi in range(self.NwS_local): # if deltaw[wi + self.wS1] > 1e-8: # specfunc_wGG[wi] += tmp_GG * deltaw[wi + self.wS1] if self.kd.nbzkpts == 1: if n == 0: dt = time() - t0 totaltime = dt * self.nvalbands * self.nspins self.printtxt('Finished n 0 in %d seconds, estimate %d seconds left.' %(dt, totaltime) ) if rank == 0 and self.nvalbands // 5 > 0: if n > 0 and n % (self.nvalbands // 5) == 0: dt = time() - t0 self.printtxt('Finished n %d in %d seconds, estimate %d seconds left.'%(n, dt, totaltime-dt)) if calc.wfs.world.size != 1: self.kcomm.barrier() if k == 0: dt = time() - t0 totaltime = dt * self.nkpt_local * self.nspins self.printtxt('Finished k 0 in %d seconds, estimate %d seconds left.' %(dt, totaltime)) if rank == 0 and self.nkpt_local // 5 > 0: if k > 0 and k % (self.nkpt_local // 5) == 0: dt = time() - t0 self.printtxt('Finished k %d in %d seconds, estimate %d seconds left. '%(k, dt, totaltime - dt) ) self.printtxt('Finished summation over k') self.kcomm.barrier() # Hilbert Transform if not self.hilbert_trans: for iw in range(self.Nw_local): self.kcomm.sum(chi0_wGG[iw]) if self.optical_limit: self.kcomm.sum(self.chi0G0_wGv[iw]) self.kcomm.sum(self.chi00G_wGv[iw]) if use_zher: assert (np.abs(chi0_wGG[0,1:,0]) < 1e-10).all() for iw in range(self.Nw_local): chi0_wGG[iw] += chi0_wGG[iw].conj().T for iG in range(self.npw): chi0_wGG[iw, iG, iG] /= 2. assert np.abs(np.imag(chi0_wGG[iw, iG, iG])) < 1e-10 else: for iw in range(self.NwS_local): self.kcomm.sum(specfunc_wGG[iw]) if self.optical_limit: self.kcomm.sum(specfuncG0_wGv[iw]) self.kcomm.sum(specfunc0G_wGv[iw]) if self.wScomm.size == 1: chi0_wGG = hilbert_transform(specfunc_wGG, self.w_w, self.Nw, self.dw, self.eta, self.full_hilbert_trans)[self.wstart:self.wend] self.printtxt('Finished hilbert transform !') del specfunc_wGG else: # redistribute specfunc_wGG to all nodes size = self.comm.size assert self.NwS % size == 0 NwStmp1 = (rank % self.kcomm.size) * self.NwS // size NwStmp2 = (rank % self.kcomm.size + 1) * self.NwS // size specfuncnew_wGG = specfunc_wGG[NwStmp1:NwStmp2] del specfunc_wGG coords = np.zeros(self.wcomm.size, dtype=int) nG_local = self.npw**2 // self.wcomm.size if self.wcomm.rank == self.wcomm.size - 1: nG_local = self.npw**2 - (self.wcomm.size - 1) * nG_local self.wcomm.all_gather(np.array([nG_local]), coords) specfunc_Wg = SliceAlongFrequency(specfuncnew_wGG, coords, self.wcomm) self.printtxt('Finished Slice Along Frequency !') chi0_Wg = hilbert_transform(specfunc_Wg, self.w_w, self.Nw, self.dw, self.eta, self.full_hilbert_trans)[:self.Nw] self.printtxt('Finished hilbert transform !') self.comm.barrier() del specfunc_Wg chi0_wGG = SliceAlongOrbitals(chi0_Wg, coords, self.wcomm) self.printtxt('Finished Slice along orbitals !') self.comm.barrier() del chi0_Wg if self.optical_limit: specfuncG0_WGv = np.zeros((self.NwS, self.npw, 3), dtype=complex) specfunc0G_WGv = np.zeros((self.NwS, self.npw, 3), dtype=complex) self.wScomm.all_gather(specfunc0G_wGv, specfunc0G_WGv) self.wScomm.all_gather(specfuncG0_wGv, specfuncG0_WGv) specfunc0G_wGv = specfunc0G_WGv specfuncG0_wGv = specfuncG0_WGv if self.optical_limit: self.chi00G_wGv = hilbert_transform(specfunc0G_wGv, self.w_w, self.Nw, self.dw, self.eta, self.full_hilbert_trans)[self.wstart:self.wend] self.chi0G0_wGv = hilbert_transform(specfuncG0_wGv, self.w_w, self.Nw, self.dw, self.eta, self.full_hilbert_trans)[self.wstart:self.wend] if self.optical_limit: self.chi00G_wGv /= self.vol self.chi0G0_wGv /= self.vol self.chi0_wGG = chi0_wGG self.chi0_wGG /= self.vol self.printtxt('') self.printtxt('Finished chi0 !') def parallel_init(self): """Parallel initialization. By default, only use kcomm and wcomm. Parameters: kcomm: kpoint communicator wScomm: spectral function communicator wcomm: frequency communicator """ if extra_parameters.get('df_dry_run'): from gpaw.mpi import DryRunCommunicator size = extra_parameters['df_dry_run'] world = DryRunCommunicator(size) rank = world.rank self.comm = world else: world = self.comm rank = self.comm.rank size = self.comm.size wcommsize = int(self.NwS * self.npw**2 * 16. / 1024**2) // 1500 # megabyte wcommsize += 1 if size < wcommsize: raise ValueError('Number of cpus are not enough ! ') if self.kcommsize is None: self.kcommsize = world.size if wcommsize > size // self.kcommsize: # if matrix too large, overwrite kcommsize and distribute matrix self.printtxt('kcommsize is over written ! ') while size % wcommsize != 0: wcommsize += 1 self.kcommsize = size // wcommsize assert self.kcommsize * wcommsize == size if self.kcommsize < 1: raise ValueError('Number of cpus are not enough ! ') self.kcomm, self.wScomm, self.wcomm = set_communicator(world, rank, size, self.kcommsize) if self.kd.nbzkpts >= world.size: self.nkpt_reshape = self.kd.nbzkpts self.nkpt_reshape, self.nkpt_local, self.kstart, self.kend = parallel_partition( self.nkpt_reshape, self.kcomm.rank, self.kcomm.size, reshape=True, positive=True) self.mband_local = self.nvalbands self.mlist = np.arange(self.nbands) else: # if number of kpoints == 1, use band parallelization self.nkpt_local = self.kd.nbzkpts self.kstart = 0 self.kend = self.kd.nbzkpts self.nkpt_reshape = self.kd.nbzkpts self.nbands, self.mband_local, self.mlist = parallel_partition_list( self.nbands, self.kcomm.rank, self.kcomm.size) if self.NwS % size != 0: self.NwS -= self.NwS % size self.NwS, self.NwS_local, self.wS1, self.wS2 = parallel_partition( self.NwS, self.wScomm.rank, self.wScomm.size, reshape=False) if self.hilbert_trans: self.Nw, self.Nw_local, self.wstart, self.wend = parallel_partition( self.Nw, self.wcomm.rank, self.wcomm.size, reshape=True) else: if self.Nw > 1: # assert self.Nw % (self.comm.size / self.kcomm.size) == 0 self.wcomm = self.wScomm self.Nw, self.Nw_local, self.wstart, self.wend = parallel_partition( self.Nw, self.wcomm.rank, self.wcomm.size, reshape=False) else: # if frequency point is too few, then dont parallelize self.wcomm = serial_comm self.wstart = 0 self.wend = self.Nw self.Nw_local = self.Nw return def print_chi(self): printtxt = self.printtxt printtxt('Use Hilbert Transform: %s' %(self.hilbert_trans) ) printtxt('Calculate time-ordered Response Function: %s' %(self.full_hilbert_trans) ) printtxt('') printtxt('Number of frequency points : %d' %(self.Nw) ) if self.hilbert_trans: printtxt('Number of specfunc points : %d' % (self.NwS)) printtxt('') printtxt('Parallelization scheme:') printtxt(' Total cpus : %d' %(self.comm.size)) if self.kd.nbzkpts == 1: printtxt(' nbands parsize : %d' %(self.kcomm.size)) else: printtxt(' kpoint parsize : %d' %(self.kcomm.size)) if self.nkpt_reshape > self.kd.nbzkpts: self.printtxt(' kpoints (%d-%d) are padded with zeros' % (self.kd.nbzkpts, self.nkpt_reshape)) if self.hilbert_trans: printtxt(' specfunc parsize: %d' %(self.wScomm.size)) printtxt(' w parsize : %d' %(self.wcomm.size)) printtxt('') printtxt('Memory usage estimation:') printtxt(' chi0_wGG : %f M / cpu' %(self.Nw_local * self.npw**2 * 16. / 1024**2) ) if self.hilbert_trans: printtxt(' specfunc_wGG : %f M / cpu' %(self.NwS_local *self.npw**2 * 16. / 1024**2) ) gpaw-0.11.0.13004/gpaw/response/chi0.py0000664000175000017500000006064112553643470017454 0ustar jensjjensj00000000000000from __future__ import print_function, division import sys from time import ctime import numpy as np from ase.units import Hartree from ase.utils.timing import timer import gpaw.mpi as mpi from gpaw import extra_parameters from gpaw.blacs import (BlacsGrid, BlacsDescriptor, Redistributor, DryRunBlacsGrid) from gpaw.kpt_descriptor import KPointDescriptor from gpaw.occupations import FermiDirac from gpaw.response.pair import PairDensity from gpaw.utilities.memory import maxrss from gpaw.utilities.blas import gemm, rk, czher, mmm from gpaw.wavefunctions.pw import PWDescriptor from gpaw.response.pair import PWSymmetryAnalyzer def frequency_grid(domega0, omega2, omegamax): beta = (2**0.5 - 1) * domega0 / omega2 wmax = int(omegamax / (domega0 + beta * omegamax)) + 2 w = np.arange(wmax) omega_w = w * domega0 / (1 - beta * w) return omega_w class Chi0(PairDensity): def __init__(self, calc, frequencies=None, domega0=0.1, omega2=10.0, omegamax=None, ecut=50, hilbert=True, nbands=None, timeordered=False, eta=0.2, ftol=1e-6, threshold=1, real_space_derivatives=False, intraband=True, world=mpi.world, txt=sys.stdout, timer=None, nblocks=1, no_optical_limit=False, keep_occupied_states=False, gate_voltage=None, disable_point_group=False, disable_time_reversal=False, use_more_memory=0, unsymmetrized=True): PairDensity.__init__(self, calc, ecut, ftol, threshold, real_space_derivatives, world, txt, timer, nblocks=nblocks, gate_voltage=gate_voltage) self.eta = eta / Hartree self.domega0 = domega0 / Hartree self.omega2 = omega2 / Hartree self.omegamax = None if omegamax is None else omegamax / Hartree self.nbands = nbands or self.calc.wfs.bd.nbands self.keep_occupied_states = keep_occupied_states self.intraband = intraband self.no_optical_limit = no_optical_limit self.disable_point_group = disable_point_group self.disable_time_reversal = disable_time_reversal self.use_more_memory = use_more_memory self.unsymmetrized = unsymmetrized omax = self.find_maximum_frequency() if frequencies is None: if self.omegamax is None: self.omegamax = omax print('Using nonlinear frequency grid from 0 to %.3f eV' % (self.omegamax * Hartree), file=self.fd) self.omega_w = frequency_grid(self.domega0, self.omega2, self.omegamax) else: self.omega_w = np.asarray(frequencies) / Hartree assert not hilbert self.hilbert = hilbert self.timeordered = bool(timeordered) if self.eta == 0.0: assert not hilbert assert not timeordered assert not self.omega_w.real.any() # Occupied states: wfs = self.calc.wfs self.mysKn1n2 = None # my (s, K, n1, n2) indices self.distribute_k_points_and_bands(0, self.nocc2, kpts=range(wfs.kd.nibzkpts)) self.mykpts = None self.prefactor = 2 / self.vol / wfs.kd.nbzkpts / wfs.nspins self.chi0_vv = None # strength of intraband peak def find_maximum_frequency(self): self.epsmin = 10000.0 self.epsmax = -10000.0 for kpt in self.calc.wfs.kpt_u: self.epsmin = min(self.epsmin, kpt.eps_n[0]) self.epsmax = max(self.epsmax, kpt.eps_n[self.nbands - 1]) print('Minimum eigenvalue: %10.3f eV' % (self.epsmin * Hartree), file=self.fd) print('Maximum eigenvalue: %10.3f eV' % (self.epsmax * Hartree), file=self.fd) return self.epsmax - self.epsmin def calculate(self, q_c, spin='all', A_x=None): wfs = self.calc.wfs if spin == 'all': spins = range(wfs.nspins) else: assert spin in range(wfs.nspins) spins = [spin] q_c = np.asarray(q_c, dtype=float) qd = KPointDescriptor([q_c]) pd = PWDescriptor(self.ecut, wfs.gd, complex, qd) self.print_chi(pd) if extra_parameters.get('df_dry_run'): print(' Dry run exit', file=self.fd) raise SystemExit nG = pd.ngmax nw = len(self.omega_w) mynG = (nG + self.blockcomm.size - 1) // self.blockcomm.size self.Ga = self.blockcomm.rank * mynG self.Gb = min(self.Ga + mynG, nG) assert mynG * (self.blockcomm.size - 1) < nG if A_x is not None: nx = nw * (self.Gb - self.Ga) * nG chi0_wGG = A_x[:nx].reshape((nw, self.Gb - self.Ga, nG)) chi0_wGG[:] = 0.0 else: chi0_wGG = np.zeros((nw, self.Gb - self.Ga, nG), complex) if np.allclose(q_c, 0.0): chi0_wxvG = np.zeros((len(self.omega_w), 2, 3, nG), complex) chi0_wvv = np.zeros((len(self.omega_w), 3, 3), complex) self.chi0_vv = np.zeros((3, 3), complex) else: chi0_wxvG = None chi0_wvv = None # Do all empty bands: m1 = self.nocc1 m2 = self.nbands self._calculate(pd, chi0_wGG, chi0_wxvG, chi0_wvv, m1, m2, spins) return pd, chi0_wGG, chi0_wxvG, chi0_wvv @timer('Calculate CHI_0') def _calculate(self, pd, chi0_wGG, chi0_wxvG, chi0_wvv, m1, m2, spins): # Choose which update method to use if self.eta == 0.0: update = self.update_hermitian elif self.hilbert: update = self.update_hilbert else: update = self.update q_c = pd.kd.bzk_kc[0] optical_limit = not self.no_optical_limit and np.allclose(q_c, 0.0) generator = self.generate_pair_densities # Use symmetries PWSA = PWSymmetryAnalyzer PWSA = PWSA(self.calc.wfs.kd, pd, disable_point_group=self.disable_point_group, disable_time_reversal=self.disable_time_reversal, timer=self.timer, txt=self.fd) # If chi's are supplied it # is assumed that they are symmetric # and we have to divide by the number of # symmetries if we are adding # the unsymmetric chi if self.unsymmetrized: nsym = PWSA.how_many_symmetries() if nsym > 1: chi0_wGG /= nsym if chi0_wxvG is not None: chi0_wxvG /= nsym if chi0_wvv is not None: chi0_wvv /= nsym # Calculate unsymmetrized chi or spectral function self.timer.start('Loop') for f2_m, df_m, deps_m, n_mG, n_mv, vel_mv in \ generator(pd, m1, m2, spins, PWSA=PWSA, disable_optical_limit=not optical_limit, intraband=self.intraband, use_more_memory=self.use_more_memory, unsymmetrized=self.unsymmetrized): # If the generator returns None for a pair-density # then skip updating if n_mG is not None: update(np.ascontiguousarray(n_mG), deps_m, df_m, chi0_wGG) if optical_limit and n_mv is not None: self.update_optical_limit(n_mv, deps_m, df_m, n_mG, chi0_wxvG, chi0_wvv) if optical_limit and self.intraband and vel_mv is not None: self.update_intraband(f2_m, vel_mv, self.chi0_vv) self.timer.stop('Loop') # Sum chi with self.timer('Sum CHI_0'): for chi0_GG in chi0_wGG: self.kncomm.sum(chi0_GG) if optical_limit: self.kncomm.sum(chi0_wxvG) self.kncomm.sum(chi0_wvv) if self.intraband: self.kncomm.sum(self.chi0_vv) print('Memory used: {0:.3f} MB / CPU'.format(maxrss() / 1024**2), file=self.fd) if (self.eta == 0.0 or self.hilbert) and self.blockcomm.size == 1: # Fill in upper/lower triangle also: nG = pd.ngmax il = np.tril_indices(nG, -1) iu = il[::-1] if self.hilbert: for chi0_GG in chi0_wGG: chi0_GG[il] = chi0_GG[iu].conj() else: for chi0_GG in chi0_wGG: chi0_GG[iu] = chi0_GG[il].conj() if self.hilbert: with self.timer('Hilbert transform'): ht = HilbertTransform(self.omega_w, self.eta, self.timeordered) ht(chi0_wGG) if optical_limit: ht(chi0_wvv) ht(chi0_wxvG) print('Hilbert transform done', file=self.fd) if optical_limit and self.intraband: # Add intraband contribution omega_w = self.omega_w.copy() if omega_w[0] == 0.0: omega_w[0] = 1e-14 chi0_vv = self.chi0_vv self.world.broadcast(chi0_vv, 0) chi0_wvv += (chi0_vv[np.newaxis] / (omega_w[:, np.newaxis, np.newaxis] + 1j * self.eta)**2) if self.unsymmetrized: # Carry out symmetrization # Redistribute if block par tmpchi0_wGG = self.redistribute(chi0_wGG) PWSA.symmetrize_wGG(tmpchi0_wGG) self.redistribute(tmpchi0_wGG, chi0_wGG) if optical_limit: PWSA.symmetrize_wxvG(chi0_wxvG) PWSA.symmetrize_wvv(chi0_wvv) # Since chi_wGG is nonanalytic in the head # and wings we have to take care that # these are handled correctly. Note that # it is important that the wings are overwritten first. chi0_wGG[:, :, 0] = chi0_wxvG[:, 1, 0, self.Ga:self.Gb] if self.blockcomm.rank == 0: chi0_wGG[:, 0] = chi0_wxvG[:, 0, 0] chi0_wGG[:, 0, 0] = chi0_wvv[:, 0, 0] return pd, chi0_wGG, chi0_wxvG, chi0_wvv @timer('CHI_0 update') def update(self, n_mG, deps_m, df_m, chi0_wGG): """Update chi.""" if self.timeordered: deps1_m = deps_m + 1j * self.eta * np.sign(deps_m) deps2_m = deps1_m else: deps1_m = deps_m + 1j * self.eta deps2_m = deps_m - 1j * self.eta for omega, chi0_GG in zip(self.omega_w, chi0_wGG): x_m = df_m * (1 / (omega + deps1_m) - 1 / (omega - deps2_m)) if self.blockcomm.size > 1: nx_mG = n_mG[:, self.Ga:self.Gb] * x_m[:, np.newaxis] else: nx_mG = n_mG * x_m[:, np.newaxis] gemm(self.prefactor, n_mG.conj(), np.ascontiguousarray(nx_mG.T), 1.0, chi0_GG) @timer('CHI_0 hermetian update') def update_hermitian(self, n_mG, deps_m, df_m, chi0_wGG): """If eta=0 use hermitian update.""" for w, omega in enumerate(self.omega_w): if self.blockcomm.size == 1: x_m = (-2 * df_m * deps_m / (omega.imag**2 + deps_m**2))**0.5 nx_mG = n_mG.conj() * x_m[:, np.newaxis] rk(-self.prefactor, nx_mG, 1.0, chi0_wGG[w], 'n') else: x_m = 2 * df_m * deps_m / (omega.imag**2 + deps_m**2) mynx_mG = n_mG[:, self.Ga:self.Gb] * x_m[:, np.newaxis] mmm(self.prefactor, mynx_mG, 'c', n_mG, 'n', 1.0, chi0_wGG[w]) @timer('CHI_0 spectral function update') def update_hilbert(self, n_mG, deps_m, df_m, chi0_wGG): """Update spectral function. Updates spectral function A_wGG and saves it to chi0_wGG for later hilbert-transform.""" self.timer.start('prep') beta = (2**0.5 - 1) * self.domega0 / self.omega2 o_m = abs(deps_m) w_m = (o_m / (self.domega0 + beta * o_m)).astype(int) o1_m = self.omega_w[w_m] o2_m = self.omega_w[w_m + 1] p_m = self.prefactor * abs(df_m) / (o2_m - o1_m)**2 # XXX abs()? p1_m = p_m * (o2_m - o_m) p2_m = p_m * (o_m - o1_m) self.timer.stop('prep') if self.blockcomm.size > 1: for p1, p2, n_G, w in zip(p1_m, p2_m, n_mG, w_m): myn_G = n_G[self.Ga:self.Gb].reshape((-1, 1)) gemm(p1, n_G.reshape((-1, 1)), myn_G, 1.0, chi0_wGG[w], 'c') gemm(p2, n_G.reshape((-1, 1)), myn_G, 1.0, chi0_wGG[w + 1], 'c') return for p1, p2, n_G, w in zip(p1_m, p2_m, n_mG, w_m): czher(p1, n_G.conj(), chi0_wGG[w]) czher(p2, n_G.conj(), chi0_wGG[w + 1]) @timer('CHI_0 optical limit update') def update_optical_limit(self, n0_mv, deps_m, df_m, n_mG, chi0_wxvG, chi0_wvv): """Optical limit update of chi.""" if self.hilbert: # Do something special when hilbert transforming self.update_optical_limit_hilbert(n0_mv, deps_m, df_m, n_mG, chi0_wxvG, chi0_wvv) return if self.timeordered: # avoid getting a zero from np.sign(): deps1_m = deps_m + 1j * self.eta * np.sign(deps_m + 1e-20) deps2_m = deps1_m else: deps1_m = deps_m + 1j * self.eta deps2_m = deps_m - 1j * self.eta for w, omega in enumerate(self.omega_w): x_m = self.prefactor * df_m * (1 / (omega + deps1_m) - 1 / (omega - deps2_m)) chi0_wvv[w] += np.dot(x_m * n0_mv.T, n0_mv.conj()) chi0_wxvG[w, 0, :, 1:] += np.dot(x_m * n0_mv.T, n_mG[:, 1:].conj()) chi0_wxvG[w, 1, :, 1:] += np.dot(x_m * n0_mv.T.conj(), n_mG[:, 1:]) @timer('CHI_0 optical limit hilbert-update') def update_optical_limit_hilbert(self, n0_mv, deps_m, df_m, n_mG, chi0_wxvG, chi0_wvv): """Optical limit update of chi-head and -wings.""" beta = (2**0.5 - 1) * self.domega0 / self.omega2 for deps, df, n0_v, n_G in zip(deps_m, df_m, n0_mv, n_mG): o = abs(deps) w = int(o / (self.domega0 + beta * o)) if w + 2 > len(self.omega_w): break o1, o2 = self.omega_w[w:w + 2] assert o1 <= o <= o2, (o1, o, o2) p = self.prefactor * abs(df) / (o2 - o1)**2 # XXX abs()? p1 = p * (o2 - o) p2 = p * (o - o1) x_vv = np.outer(n0_v, n0_v.conj()) chi0_wvv[w] += p1 * x_vv chi0_wvv[w + 1] += p2 * x_vv x_vG = np.outer(n0_v, n_G[1:].conj()) chi0_wxvG[w, 0, :, 1:] += p1 * x_vG chi0_wxvG[w + 1, 0, :, 1:] += p2 * x_vG chi0_wxvG[w, 1, :, 1:] += p1 * x_vG.conj() chi0_wxvG[w + 1, 1, :, 1:] += p2 * x_vG.conj() @timer('CHI_0 intraband update') def update_intraband(self, f_m, vel_mv, chi0_vv): """Add intraband contributions""" assert len(f_m) == len(vel_mv), print(len(f_m), len(vel_mv)) width = self.calc.occupations.width if width == 0.0: return assert isinstance(self.calc.occupations, FermiDirac) dfde_m = - 1. / width * (f_m - f_m**2.0) partocc_m = np.abs(dfde_m) > 1e-5 if not partocc_m.any(): return for dfde, vel_v in zip(dfde_m, vel_mv): x_vv = (-self.prefactor * dfde * np.outer(vel_v, vel_v)) chi0_vv += x_vv @timer('redist') def redistribute(self, in_wGG, out_x=None): """Redistribute array. Switch between two kinds of parallel distributions: 1) parallel over G-vectors (second dimension of in_wGG) 2) parallel over frequency (first dimension of in_wGG) Returns new array using the memory in the 1-d array out_x. """ comm = self.blockcomm if comm.size == 1: return in_wGG nw = len(self.omega_w) nG = in_wGG.shape[2] mynw = (nw + comm.size - 1) // comm.size mynG = (nG + comm.size - 1) // comm.size bg1 = BlacsGrid(comm, comm.size, 1) bg2 = BlacsGrid(comm, 1, comm.size) md1 = BlacsDescriptor(bg1, nw, nG**2, mynw, nG**2) md2 = BlacsDescriptor(bg2, nw, nG**2, nw, mynG * nG) if len(in_wGG) == nw: mdin = md2 mdout = md1 else: mdin = md1 mdout = md2 r = Redistributor(comm, mdin, mdout) outshape = (mdout.shape[0], mdout.shape[1] // nG, nG) if out_x is None: out_wGG = np.empty(outshape, complex) else: out_wGG = out_x[:np.product(outshape)].reshape(outshape) r.redistribute(in_wGG.reshape(mdin.shape), out_wGG.reshape(mdout.shape)) return out_wGG @timer('dist freq') def distribute_frequencies(self, chi0_wGG): """Distribute frequencies to all cores.""" world = self.world comm = self.blockcomm if world.size == 1: return chi0_wGG nw = len(self.omega_w) nG = chi0_wGG.shape[2] mynw = (nw + world.size - 1) // world.size mynG = (nG + comm.size - 1) // comm.size wa = min(world.rank * mynw, nw) wb = min(wa + mynw, nw) if self.blockcomm.size == 1: return chi0_wGG[wa:wb].copy() if self.kncomm.rank == 0: bg1 = BlacsGrid(comm, 1, comm.size) in_wGG = chi0_wGG.reshape((nw, -1)) else: bg1 = DryRunBlacsGrid(mpi.serial_comm, 1, 1) in_wGG = np.zeros((0, 0), complex) md1 = BlacsDescriptor(bg1, nw, nG**2, nw, mynG * nG) bg2 = BlacsGrid(world, world.size, 1) md2 = BlacsDescriptor(bg2, nw, nG**2, mynw, nG**2) r = Redistributor(world, md1, md2) shape = (wb - wa, nG, nG) out_wGG = np.empty(shape, complex) r.redistribute(in_wGG, out_wGG.reshape((wb - wa, nG**2))) return out_wGG def print_chi(self, pd): calc = self.calc gd = calc.wfs.gd if extra_parameters.get('df_dry_run'): from gpaw.mpi import DryRunCommunicator size = extra_parameters['df_dry_run'] world = DryRunCommunicator(size) else: world = self.world print('%s' % ctime(), file=self.fd) print('Called response.chi0.calculate with', file=self.fd) q_c = pd.kd.bzk_kc[0] print(' q_c: [%f, %f, %f]' % (q_c[0], q_c[1], q_c[2]), file=self.fd) nw = len(self.omega_w) print(' Number of frequency points: %d' % nw, file=self.fd) ecut = self.ecut * Hartree print(' Planewave cutoff: %f' % ecut, file=self.fd) ns = calc.wfs.nspins print(' Number of spins: %d' % ns, file=self.fd) nbands = self.nbands print(' Number of bands: %d' % nbands, file=self.fd) nk = calc.wfs.kd.nbzkpts print(' Number of kpoints: %d' % nk, file=self.fd) nik = calc.wfs.kd.nibzkpts print(' Number of irredicible kpoints: %d' % nik, file=self.fd) ngmax = pd.ngmax print(' Number of planewaves: %d' % ngmax, file=self.fd) eta = self.eta * Hartree print(' Broadening (eta): %f' % eta, file=self.fd) wsize = world.size print(' world.size: %d' % wsize, file=self.fd) knsize = self.kncomm.size print(' kncomm.size: %d' % knsize, file=self.fd) bsize = self.blockcomm.size print(' blockcomm.size: %d' % bsize, file=self.fd) nocc = self.nocc1 print(' Number of completely occupied states: %d' % nocc, file=self.fd) npocc = self.nocc2 print(' Number of partially occupied states: %d' % npocc, file=self.fd) keep = self.keep_occupied_states print(' Keep occupied states: %s' % keep, file=self.fd) print('', file=self.fd) print(' Memory estimate of potentially large arrays:', file=self.fd) chisize = nw * pd.ngmax**2 * 16. / 1024**2 print(' chi0_wGG: %f M / cpu' % chisize, file=self.fd) ngridpoints = gd.N_c[0] * gd.N_c[1] * gd.N_c[2] if self.keep_occupied_states: nstat = (ns * nk * npocc + world.size - 1) // world.size else: nstat = (ns * npocc + world.size - 1) // world.size occsize = nstat * ngridpoints * 16. / 1024**2 print(' Occupied states: %f M / cpu' % occsize, file=self.fd) print(' Memory usage before allocation: %f M / cpu' % (maxrss() / 1024**2), file=self.fd) print('', file=self.fd) class HilbertTransform: def __init__(self, omega_w, eta, timeordered=False, gw=False, blocksize=500): """Analytic Hilbert transformation using linear interpolation. Hilbert transform:: oo / 1 1 |dw' (-------------- - --------------) S(w'). / w - w' + i eta w + w' + i eta 0 With timeordered=True, you get:: oo / 1 1 |dw' (-------------- - --------------) S(w'). / w - w' - i eta w + w' + i eta 0 With gw=True, you get:: oo / 1 1 |dw' (-------------- + --------------) S(w'). / w - w' + i eta w + w' + i eta 0 """ self.blocksize = blocksize if timeordered: self.H_ww = self.H(omega_w, -eta) + self.H(omega_w, -eta, -1) elif gw: self.H_ww = self.H(omega_w, eta) - self.H(omega_w, -eta, -1) else: self.H_ww = self.H(omega_w, eta) + self.H(omega_w, -eta, -1) def H(self, o_w, eta, sign=1): """Calculate transformation matrix. With s=sign (+1 or -1):: oo / dw' X (w, eta) = | ---------------- S(w'). s / s w - w' + i eta 0 Returns H_ij so that X_i = np.dot(H_ij, S_j), where:: X_i = X (omega_w[i]) and S_j = S(omega_w[j]) s """ nw = len(o_w) H_ij = np.zeros((nw, nw), complex) do_j = o_w[1:] - o_w[:-1] for i, o in enumerate(o_w): d_j = o_w - o * sign y_j = 1j * np.arctan(d_j / eta) + 0.5 * np.log(d_j**2 + eta**2) y_j = (y_j[1:] - y_j[:-1]) / do_j H_ij[i, :-1] = 1 - (d_j[1:] - 1j * eta) * y_j H_ij[i, 1:] -= 1 - (d_j[:-1] - 1j * eta) * y_j return H_ij def __call__(self, S_wx): """Inplace transform""" B_wx = S_wx.reshape((len(S_wx), -1)) nw, nx = B_wx.shape tmp_wx = np.zeros((nw, min(nx, self.blocksize)), complex) for x in range(0, nx, self.blocksize): b_wx = B_wx[:, x:x + self.blocksize] c_wx = tmp_wx[:, :b_wx.shape[1]] gemm(1.0, b_wx, self.H_ww, 0.0, c_wx) b_wx[:] = c_wx if __name__ == '__main__': do = 0.025 eta = 0.1 omega_w = frequency_grid(do, 10.0, 3) print(len(omega_w)) X_w = omega_w * 0j Xt_w = omega_w * 0j Xh_w = omega_w * 0j for o in -np.linspace(2.5, 2.9, 10): X_w += (1 / (omega_w + o + 1j * eta) - 1 / (omega_w - o + 1j * eta)) / o**2 Xt_w += (1 / (omega_w + o - 1j * eta) - 1 / (omega_w - o + 1j * eta)) / o**2 w = int(-o / do / (1 + 3 * -o / 10)) o1, o2 = omega_w[w:w + 2] assert o1 - 1e-12 <= -o <= o2 + 1e-12, (o1, -o, o2) p = 1 / (o2 - o1)**2 / o**2 Xh_w[w] += p * (o2 - -o) Xh_w[w + 1] += p * (-o - o1) ht = HilbertTransform(omega_w, eta, 1) ht(Xh_w) import matplotlib.pyplot as plt plt.plot(omega_w, X_w.imag, label='ImX') plt.plot(omega_w, X_w.real, label='ReX') plt.plot(omega_w, Xt_w.imag, label='ImXt') plt.plot(omega_w, Xt_w.real, label='ReXt') plt.plot(omega_w, Xh_w.imag, label='ImXh') plt.plot(omega_w, Xh_w.real, label='ReXh') plt.legend() plt.show() gpaw-0.11.0.13004/gpaw/response/pair.py0000664000175000017500000014045112553643470017562 0ustar jensjjensj00000000000000from __future__ import print_function import sys import functools from math import pi import numpy as np from ase.units import Hartree from ase.utils import devnull from ase.utils.timing import timer, Timer import gpaw.mpi as mpi from gpaw import GPAW from gpaw.fd_operators import Gradient from gpaw.occupations import FermiDirac from gpaw.response.math_func import (two_phi_planewave_integrals, two_phi_nabla_planewave_integrals) from gpaw.utilities.blas import gemm from gpaw.utilities.progressbar import ProgressBar from gpaw.wavefunctions.pw import PWLFC import gpaw.io.tar as io class KPoint: def __init__(self, s, K, n1, n2, blocksize, na, nb, ut_nR, eps_n, f_n, P_ani, shift_c): self.s = s # spin index self.K = K # BZ k-point index self.n1 = n1 # first band self.n2 = n2 # first band not included self.blocksize = blocksize self.na = na # first band of block self.nb = nb # first band of block not included self.ut_nR = ut_nR # periodic part of wave functions in real-space self.eps_n = eps_n # eigenvalues self.f_n = f_n # occupation numbers self.P_ani = P_ani # PAW projections self.shift_c = shift_c # long story - see the # PairDensity.construct_symmetry_operators() method class KPointPair: """This class defines the kpoint-pair container object. Used for calculating pair quantities it contains two kpoints, and an associated set of Fourier components.""" def __init__(self, kpt1, kpt2, Q_G): self.kpt1 = kpt1 self.kpt2 = kpt2 self.Q_G = Q_G def get_k1(self): """ Return KPoint object 1.""" return self.kpt1 def get_k2(self): """ Return KPoint object 2.""" return self.kpt2 def get_planewave_indices(self): """ Return the planewave indices associated with this pair.""" return self.Q_G def get_transition_energies(self, n_n, m_m): """Return the energy difference for specified bands.""" kpt1 = self.kpt1 kpt2 = self.kpt2 deps_nm = (kpt1.eps_n[n_n][:, np.newaxis] - kpt2.eps_n[m_m]) return deps_nm def get_occupation_differences(self, n_n, m_m): """Get difference in occupation factor between specified bands.""" kpt1 = self.kpt1 kpt2 = self.kpt2 df_nm = (kpt1.f_n[n_n][:, np.newaxis] - kpt2.f_n[m_m]) return df_nm class PWSymmetryAnalyzer: """Class for handling planewave symmetries.""" def __init__(self, kd, pd, txt=sys.stdout, disable_point_group=False, disable_non_symmorphic=True, disable_time_reversal=False, timer=None): """Creates a PWSymmetryAnalyzer object. Determines which of the symmetries of the atomic structure that is compatible with the reciprocal lattice. Contains the necessary functions for mapping quantities between kpoints, and or symmetrizing arrays. kd: KPointDescriptor The kpoint descriptor containing the information about symmetries and kpoints. pd: PWDescriptor Plane wave descriptor that contains the reciprocal lattice . txt: str Output file. disable_point_group: bool Switch for disabling point group symmetries. disable_non_symmorphic: Switch for disabling non symmorphic symmetries. disable_time_reversal: Switch for disabling time reversal. """ self.pd = pd self.kd = kd self.fd = txt # Caveats assert disable_non_symmorphic, \ print('You are not allowed to use non symmorphic syms, sorry. ', file=self.fd) # Settings self.disable_point_group = disable_point_group self.disable_time_reversal = disable_time_reversal self.disable_non_symmorphic = disable_non_symmorphic if (kd.symmetry.has_inversion or not kd.symmetry.time_reversal) and \ not self.disable_time_reversal: print('\nThe ground calculation does not support time-reversal ' + 'symmetry possibly because it has an inversion center ' + 'or that it has been manually deactivated. \n', file=self.fd) self.disable_time_reversal = True self.disable_symmetries = (self.disable_point_group and self.disable_time_reversal and self.disable_non_symmorphic) # Number of symmetries U_scc = kd.symmetry.op_scc self.nU = len(U_scc) self.nsym = 2 * self.nU self.use_time_reversal = not self.disable_time_reversal # Which timer to use self.timer = timer or Timer() # Initialize self.initialize() @timer('Initialize') def initialize(self): """Initialize relevant quantities.""" self.infostring = '' if self.disable_point_group: self.infostring += 'Point group not included. ' else: self.infostring += 'Point group included. ' if self.disable_time_reversal: self.infostring += 'Time reversal not included. ' else: self.infostring += 'Time reversal included. ' if self.disable_non_symmorphic: self.infostring += 'Disabled non symmorphic symmetries. ' else: self.infostring += 'Time reversal included. ' if self.disable_symmetries: self.infostring += 'All symmetries have been disabled. ' # Do the work self.analyze_symmetries() self.analyze_kpoints() self.initialize_G_maps() # Print info print(self.infostring, file=self.fd) self.print_symmetries() def print_symmetries(self): """Handsome print function for symmetry operations.""" p = functools.partial(print, file=self.fd) p() nx = 6 if self.disable_non_symmorphic else 3 ns = len(self.s_s) y = 0 for y in range((ns + nx - 1) // nx): for c in range(3): for x in range(nx): s = x + y * nx if s == ns: break tmp = self.get_symmetry_operator(self.s_s[s]) op_cc, sign, TR, shift_c, ft_c = tmp op_c = sign * op_cc[c] p(' (%2d %2d %2d)' % tuple(op_c), end='') p() p() @timer('Analyze') def analyze_kpoints(self): """Calculate the reduction in the number of kpoints.""" K_gK = self.group_kpoints() ng = len(K_gK) self.infostring += '{0} groups of equivalent kpoints. '.format(ng) percent = (1. - (ng + 0.) / self.kd.nbzkpts) * 100 self.infostring += '{0}% reduction. '.format(percent) @timer('Analyze symmetries.') def analyze_symmetries(self): """Determine allowed symmetries. An direct symmetry U must fulfill:: U \mathbf{q} = q + \Delta Under time-reversal (indirect) it must fulfill:: -U \mathbf{q} = q + \Delta where :math:`\Delta` is a reciprocal lattice vector. """ pd = self.pd # Shortcuts q_c = pd.kd.bzk_kc[0] kd = self.kd U_scc = kd.symmetry.op_scc nU = self.nU nsym = self.nsym shift_sc = np.zeros((nsym, 3), int) conserveq_s = np.zeros(nsym, bool) newq_sc = np.dot(U_scc, q_c) # Direct symmetries dshift_sc = (newq_sc - q_c[np.newaxis]).round().astype(int) inds_s = np.argwhere((newq_sc == q_c[np.newaxis] + dshift_sc).all(1)) conserveq_s[inds_s] = True shift_sc[:nU] = dshift_sc # Time reversal trshift_sc = (-newq_sc - q_c[np.newaxis]).round().astype(int) trinds_s = np.argwhere((-newq_sc == q_c[np.newaxis] + trshift_sc).all(1)) + nU conserveq_s[trinds_s] = True shift_sc[nU:nsym] = trshift_sc # The indices of the allowed symmetries s_s = conserveq_s.nonzero()[0] # Filter out disabled symmetries if self.disable_point_group: s_s = [s for s in s_s if self.is_not_point_group(s)] if self.disable_time_reversal: s_s = [s for s in s_s if self.is_not_time_reversal(s)] if self.disable_non_symmorphic: s_s = [s for s in s_s if self.is_not_non_symmorphic(s)] stmp_s = [] for s in s_s: if self.kd.bz2bz_ks[0, s] == -1: assert (self.kd.bz2bz_ks[:, s] == -1).all() else: stmp_s.append(s) s_s = stmp_s self.infostring += 'Found {0} allowed symmetries. '.format(len(s_s)) self.s_s = s_s self.shift_sc = shift_sc def is_not_point_group(self, s): U_scc = self.kd.symmetry.op_scc nU = self.nU return (U_scc[s % nU] == np.eye(3)).all() def is_not_time_reversal(self, s): nU = self.nU return not bool(s // nU) def is_not_non_symmorphic(self, s): ft_sc = self.kd.symmetry.ft_sc nU = self.nU return not bool(ft_sc[s % nU].any()) def how_many_symmetries(self): """Return number of symmetries.""" return len(self.s_s) @timer('Group kpoints') def group_kpoints(self, K_k=None): """Group kpoints according to the reduced symmetries""" if K_k is None: K_k = np.arange(self.kd.nbzkpts) s_s = self.s_s bz2bz_ks = self.kd.bz2bz_ks nk = len(bz2bz_ks) sbz2sbz_ks = bz2bz_ks[K_k][:, s_s] # Reduced number of symmetries # Avoid -1 (see documentation in gpaw.symmetry) sbz2sbz_ks[sbz2sbz_ks == -1] = nk smallestk_k = np.sort(sbz2sbz_ks)[:, 0] k2g_g = np.unique(smallestk_k, return_index=True)[1] K_gs = sbz2sbz_ks[k2g_g] K_gk = [np.unique(K_s[K_s != nk]) for K_s in K_gs] return K_gk def get_kpoint_mapping(self, K1, K2): """Get index of symmetry for mapping between K1 and K2""" s_s = self.s_s bz2bz_ks = self.kd.bz2bz_ks bzk2rbz_s = bz2bz_ks[K1][s_s] try: s = np.argwhere(bzk2rbz_s == K2)[0][0] except IndexError: print('K = {0} cannot be mapped into K = {1}'.format(K1, K2), file=self.fd) raise return s_s[s] def get_shift(self, K1, K2, U_cc, sign): """Get shift for mapping between K1 and K2.""" kd = self.kd k1_c = kd.bzk_kc[K1] k2_c = kd.bzk_kc[K2] shift_c = np.dot(U_cc, k1_c) - k2_c * sign assert np.allclose(shift_c.round(), shift_c) shift_c = shift_c.round().astype(int) return shift_c @timer('map_G') def map_G(self, K1, K2, a_MG): """Map a function of G from K1 to K2. """ if len(a_MG) == 0: return [] if K1 == K2: return a_MG G_G, sign = self.map_G_vectors(K1, K2) s = self.get_kpoint_mapping(K1, K2) U_cc, _, TR, shift_c, ft_c = self.get_symmetry_operator(s) return TR(a_MG[..., G_G]) def symmetrize_wGG(self, A_wGG): """Symmetrize an array in GG'.""" tmp_wGG = np.zeros_like(A_wGG) if self.use_time_reversal: AT_wGG = np.transpose(A_wGG, (0, 2, 1)) for s in self.s_s: G_G, sign, _ = self.G_sG[s] if sign == 1: tmp_wGG += A_wGG[:, G_G, :][:, :, G_G] if sign == -1: tmp_wGG += AT_wGG[:, G_G, :][:, :, G_G] # Inplace overwriting A_wGG[:] = tmp_wGG def symmetrize_wxvG(self, A_wxvG): """Symmetrize chi0_wxvG""" A_cv = self.pd.gd.cell_cv iA_cv = self.pd.gd.icell_cv if self.use_time_reversal: # ::-1 corresponds to transpose in wing indices AT_wxvG = A_wxvG[:, ::-1] tmp_wxvG = np.zeros_like(A_wxvG) for s in self.s_s: G_G, sign, shift_c = self.G_sG[s] U_cc, _, TR, shift_c, ft_c = self.get_symmetry_operator(s) M_vv = np.dot(np.dot(A_cv.T, U_cc.T), iA_cv) if sign == 1: tmp = sign * np.dot(M_vv.T, A_wxvG[..., G_G]) elif sign == -1: tmp = sign * np.dot(M_vv.T, AT_wxvG[..., G_G]) tmp_wxvG += np.transpose(tmp, (1, 2, 0, 3)) # Overwrite the input A_wxvG[:] = tmp_wxvG def symmetrize_wvv(self, A_wvv): """Symmetrize chi_wvv.""" A_cv = self.pd.gd.cell_cv iA_cv = self.pd.gd.icell_cv tmp_wvv = np.zeros_like(A_wvv) if self.use_time_reversal: AT_wvv = np.transpose(A_wvv, (0, 2, 1)) for s in self.s_s: G_G, sign, shift_c = self.G_sG[s] U_cc, _, TR, shift_c, ft_c = self.get_symmetry_operator(s) M_vv = np.dot(np.dot(A_cv.T, U_cc.T), iA_cv) if sign == 1: tmp = np.dot(np.dot(M_vv.T, A_wvv), M_vv) elif sign == -1: tmp = np.dot(np.dot(M_vv.T, AT_wvv), M_vv) tmp_wvv += np.transpose(tmp, (1, 0, 2)) # Overwrite the input A_wvv[:] = tmp_wvv @timer('map_v') def map_v(self, K1, K2, a_Mv): """Map a function of v (cartesian component) from K1 to K2.""" if len(a_Mv) == 0: return [] if K1 == K2: return a_Mv A_cv = self.pd.gd.cell_cv iA_cv = self.pd.gd.icell_cv # Get symmetry s = self.get_kpoint_mapping(K1, K2) U_cc, sign, TR, _, ft_c = self.get_symmetry_operator(s) # Create cartesian operator M_vv = np.dot(np.dot(A_cv.T, U_cc.T), iA_cv) return sign * np.dot(TR(a_Mv), M_vv) def timereversal(self, s): """Is this a time-reversal symmetry?""" tr = bool(s // self.nU) return tr def get_symmetry_operator(self, s): """Return symmetry operator s.""" U_scc = self.kd.symmetry.op_scc ft_sc = self.kd.symmetry.op_scc reds = s % self.nU if self.timereversal(s): TR = lambda x: x.conj() sign = -1 else: sign = 1 TR = lambda x: x return U_scc[reds], sign, TR, self.shift_sc[s], ft_sc[reds] @timer('map_G_vectors') def map_G_vectors(self, K1, K2): """Return G vector mapping.""" s = self.get_kpoint_mapping(K1, K2) G_G, sign, shift_c = self.G_sG[s] return G_G, sign def initialize_G_maps(self): """Calculate the Gvector mappings.""" pd = self.pd B_cv = 2.0 * np.pi * pd.gd.icell_cv G_Gv = pd.get_reciprocal_vectors(add_q=False) G_Gc = np.dot(G_Gv, np.linalg.inv(B_cv)) Q_G = pd.Q_qG[0] G_sG = [None] * self.nsym UG_sGc = [None] * self.nsym Q_sG = [None] * self.nsym for s in self.s_s: U_cc, sign, TR, shift_c, ft_c = self.get_symmetry_operator(s) iU_cc = np.linalg.inv(U_cc).T UG_Gc = np.dot(G_Gc - shift_c, sign * iU_cc) assert np.allclose(UG_Gc.round(), UG_Gc) UQ_G = np.ravel_multi_index(UG_Gc.round().astype(int).T, pd.gd.N_c, 'wrap') G_G = len(Q_G) * [None] for G, UQ in enumerate(UQ_G): try: G_G[G] = np.argwhere(Q_G == UQ)[0][0] except IndexError: print('This should not be possible but' + 'a G-vector was mapped outside the sphere') raise IndexError UG_sGc[s] = UG_Gc Q_sG[s] = UQ_G G_sG[s] = [G_G, sign, shift_c] self.G_Gc = G_Gc self.UG_sGc = UG_sGc self.Q_sG = Q_sG self.G_sG = G_sG def unfold_ibz_kpoint(self, ik): """Return kpoints related to irreducible kpoint.""" kd = self.kd K_k = np.unique(kd.bz2bz_ks[kd.ibz2bz_k[ik]]) K_k = K_k[K_k != -1] return K_k class PairDensity: def __init__(self, calc, ecut=50, ftol=1e-6, threshold=1, real_space_derivatives=False, world=mpi.world, txt=sys.stdout, timer=None, nblocks=1, gate_voltage=None): if ecut is not None: ecut /= Hartree if gate_voltage is not None: gate_voltage /= Hartree self.ecut = ecut self.ftol = ftol self.threshold = threshold self.real_space_derivatives = real_space_derivatives self.world = world self.gate_voltage = gate_voltage if nblocks == 1: self.blockcomm = self.world.new_communicator([world.rank]) self.kncomm = world else: assert world.size % nblocks == 0, world.size rank1 = world.rank // nblocks * nblocks rank2 = rank1 + nblocks self.blockcomm = self.world.new_communicator(range(rank1, rank2)) ranks = np.arange(world.rank % nblocks, world.size, nblocks) self.kncomm = self.world.new_communicator(ranks) if world.rank != 0: txt = devnull elif isinstance(txt, str): txt = open(txt, 'w') self.fd = txt self.timer = timer or Timer() with self.timer('Read ground state'): if isinstance(calc, str): print('Reading ground state calculation:\n %s' % calc, file=self.fd) if not calc.split('.')[-1] == 'gpw': calc = calc + '.gpw' self.reader = io.Reader(calc, comm=mpi.serial_comm) calc = GPAW(calc, txt=None, communicator=mpi.serial_comm, read_projections=False) else: self.reader = None assert calc.wfs.world.size == 1 assert calc.wfs.kd.symmetry.symmorphic self.calc = calc if gate_voltage is not None: self.add_gate_voltage(gate_voltage) self.spos_ac = calc.atoms.get_scaled_positions() self.nocc1 = None # number of completely filled bands self.nocc2 = None # number of non-empty bands self.count_occupied_bands() self.vol = abs(np.linalg.det(calc.wfs.gd.cell_cv)) self.ut_sKnvR = None # gradient of wave functions for optical limit print('Number of blocks:', nblocks, file=self.fd) def add_gate_voltage(self, gate_voltage=0): """Shifts the Fermi-level by e * Vg. By definition e = 1.""" assert isinstance(self.calc.occupations, FermiDirac) print('Shifting Fermi-level by %.2f eV' % (gate_voltage * Hartree), file=self.fd) for kpt in self.calc.wfs.kpt_u: kpt.f_n = (self.shift_occupations(kpt.eps_n, gate_voltage) * kpt.weight) def shift_occupations(self, eps_n, gate_voltage): """Shift fermilevel.""" fermi = self.calc.occupations.get_fermi_level() + gate_voltage width = self.calc.occupations.width tmp = (eps_n - fermi) / width f_n = np.zeros_like(eps_n) f_n[tmp <= 100] = 1 / (1 + np.exp(tmp[tmp <= 100])) f_n[tmp > 100] = 0.0 return f_n def count_occupied_bands(self): self.nocc1 = 9999999 self.nocc2 = 0 for kpt in self.calc.wfs.kpt_u: f_n = kpt.f_n / kpt.weight self.nocc1 = min((f_n > 1 - self.ftol).sum(), self.nocc1) self.nocc2 = max((f_n > self.ftol).sum(), self.nocc2) print('Number of completely filled bands:', self.nocc1, file=self.fd) print('Number of partially filled bands:', self.nocc2, file=self.fd) print('Total number of bands:', self.calc.wfs.bd.nbands, file=self.fd) def distribute_k_points_and_bands(self, band1, band2, kpts=None): """Distribute spins, k-points and bands. nbands: int Number of bands for each spin/k-point combination. The attribute self.mysKn1n2 will be set to a list of (s, K, n1, n2) tuples that this process handles. """ wfs = self.calc.wfs if kpts is None: kpts = np.arange(wfs.kd.nbzkpts) nbands = band2 - band1 size = self.kncomm.size rank = self.kncomm.rank ns = wfs.nspins nk = len(kpts) n = (ns * nk * nbands + size - 1) // size i1 = rank * n i2 = min(i1 + n, ns * nk * nbands) self.mysKn1n2 = [] i = 0 for s in range(ns): for K in kpts: n1 = min(max(0, i1 - i), nbands) n2 = min(max(0, i2 - i), nbands) if n1 != n2: self.mysKn1n2.append((s, K, n1 + band1, n2 + band1)) i += nbands print('BZ k-points:', self.calc.wfs.kd.description, file=self.fd) print('Distributing spins, k-points and bands (%d x %d x %d)' % (ns, nk, nbands), 'over %d process%s' % (self.kncomm.size, ['es', ''][self.kncomm.size == 1]), file=self.fd) print('Number of blocks:', self.blockcomm.size, file=self.fd) @timer('Get a k-point') def get_k_point(self, s, K, n1, n2, block=False): """Return wave functions for a specific k-point and spin. s: int Spin index (0 or 1). K: int BZ k-point index. n1, n2: int Range of bands to include. """ wfs = self.calc.wfs if block: nblocks = self.blockcomm.size rank = self.blockcomm.rank else: nblocks = 1 rank = 0 blocksize = (n2 - n1 + nblocks - 1) // nblocks na = min(n1 + rank * blocksize, n2) nb = min(na + blocksize, n2) U_cc, T, a_a, U_aii, shift_c, time_reversal = \ self.construct_symmetry_operators(K) ik = wfs.kd.bz2ibz_k[K] kpt = wfs.kpt_u[s * wfs.kd.nibzkpts + ik] assert n2 <= len(kpt.eps_n), \ 'Increase GS-nbands or decrease chi0-nbands!' eps_n = kpt.eps_n[n1:n2] f_n = kpt.f_n[n1:n2] / kpt.weight psit_nG = kpt.psit_nG ut_nR = wfs.gd.empty(nb - na, wfs.dtype) for n in range(na, nb): ut_nR[n - na] = T(wfs.pd.ifft(psit_nG[n], ik)) P_ani = [] if self.reader is None: for b, U_ii in zip(a_a, U_aii): P_ni = np.dot(kpt.P_ani[b][na:nb], U_ii) if time_reversal: P_ni = P_ni.conj() P_ani.append(P_ni) else: II_a = [] I1 = 0 for U_ii in U_aii: I2 = I1 + len(U_ii) II_a.append((I1, I2)) I1 = I2 P_ani = [] P_nI = self.reader.get('Projections', kpt.s, kpt.k) for b, U_ii in zip(a_a, U_aii): I1, I2 = II_a[b] P_ni = np.dot(P_nI[na:nb, I1:I2], U_ii) if time_reversal: P_ni = P_ni.conj() P_ani.append(P_ni) return KPoint(s, K, n1, n2, blocksize, na, nb, ut_nR, eps_n, f_n, P_ani, shift_c) def generate_pair_densities(self, pd, m1, m2, spins, intraband=True, PWSA=None, disable_optical_limit=False, unsymmetrized=False, use_more_memory=1): """Generator for returning pair densities. Returns the pair densities between the occupied and the states in range(m1, m2). pd: PWDescriptor Plane-wave descriptor for a single q-point. m1: int Index of first unoccupied band. m2: int Index of last unoccupied band. spins: list List of spin indices included. intraband: bool Include intraband transitions in optical limit. PWSA: PlanewaveSymmetryAnalyzer If supplied uses this object to determine the symmetries of the pair-densities. disable_optical_limit: bool Disable optical limit. unsymmetrized: bool Only return pair-densities from one kpoint in each group of equivalent kpoints. use_more_memory: float Group more pair densities for several occupied bands together before returning. Here 0 <= use_more_memory <= 1, where zero is the minimal amount of memory, and 1 is the maximal. """ assert 0 <= use_more_memory <= 1 q_c = pd.kd.bzk_kc[0] optical_limit = not disable_optical_limit and np.allclose(q_c, 0.0) Q_aGii = self.initialize_paw_corrections(pd) self.Q_aGii = Q_aGii # This is used in g0w0 if PWSA is None: with self.timer('Symmetry analyzer'): PWSA = PWSymmetryAnalyzer # Line too long otherwise PWSA = PWSA(self.calc.wfs.kd, pd, timer=self.timer, txt=self.fd) pb = ProgressBar(self.fd) for kn, (s, ik, n1, n2) in pb.enumerate(self.mysKn1n2): Kstar_k = PWSA.unfold_ibz_kpoint(ik) for K_k in PWSA.group_kpoints(Kstar_k): # Let the first kpoint of the group represent # the rest of the kpoints K1 = K_k[0] # In this way wavefunctions are only loaded into # memory for this particular set of kpoints kptpair = self.get_kpoint_pair(pd, s, K1, n1, n2, m1, m2) kpt1 = kptpair.get_k1() # kpt1 = k if kpt1.s not in spins: continue kpt2 = kptpair.get_k2() # kpt2 = k + q if unsymmetrized: # Number of times kpoints are mapped into themselves weight = np.sqrt(PWSA.how_many_symmetries() / len(K_k)) # Use kpt2 to compute intraband transitions # These conditions are sufficent to make sure # that it still works in parallel if kpt1.n1 == 0 and self.blockcomm.rank == 0 and \ optical_limit and intraband: assert self.nocc2 <= kpt2.nb, \ print('Error: Too few unoccupied bands') vel0_mv = self.intraband_pair_density(kpt2) f_m = kpt2.f_n[kpt2.na - kpt2.n1:kpt2.nb - kpt2.n1] with self.timer('intraband'): if vel0_mv is not None: if unsymmetrized: yield (f_m, None, None, None, None, vel0_mv / weight) else: for K2 in K_k: vel_mv = PWSA.map_v(K1, K2, vel0_mv) yield (f_m, None, None, None, None, vel_mv) # Divide the occupied bands into chunks n_n = np.arange(n2 - n1) if use_more_memory == 0: chunksize = 1 else: chunksize = np.ceil(len(n_n) * use_more_memory).astype(int) no_n = [] for i in range(len(n_n) // chunksize): i1 = i * chunksize i2 = min((i + 1) * chunksize, len(n_n)) no_n.append(n_n[i1:i2]) # n runs over occupied bands for n_n in no_n: # n_n is a list of occupied band indices # m over unoccupied bands m_m = np.arange(0, kpt2.n2 - kpt2.n1) deps_nm = kptpair.get_transition_energies(n_n, m_m) df_nm = kptpair.get_occupation_differences(n_n, m_m) # This is not quite right for # degenerate partially occupied # bands, but good enough for now: df_nm[df_nm <= 1e-20] = 0.0 # Get pair density for representative kpoint ol = optical_limit n0_nmG, n0_nmv, _ = self.get_pair_density(pd, kptpair, n_n, m_m, optical_limit=ol, intraband=False, Q_aGii=Q_aGii) n0_nmG[deps_nm >= 0.0] = 0.0 if optical_limit: n0_nmv[deps_nm >= 0.0] = 0.0 # Reshape nm -> m nG = pd.ngmax deps_m = deps_nm.reshape(-1) df_m = df_nm.reshape(-1) n0_mG = n0_nmG.reshape((-1, nG)) if optical_limit: n0_mv = n0_nmv.reshape((-1, 3)) if unsymmetrized: if optical_limit: yield (None, df_m, deps_m, n0_mG / weight, n0_mv / weight, None) else: yield (None, df_m, deps_m, n0_mG / weight, None, None) continue # Collect pair densities in a single array # and return them nm = n0_mG.shape[0] nG = n0_mG.shape[1] nk = len(K_k) n_MG = np.empty((nm * nk, nG), complex) if optical_limit: n_Mv = np.empty((nm * nk, 3), complex) deps_M = np.tile(deps_m, nk) df_M = np.tile(df_m, nk) for i, K2 in enumerate(K_k): i1 = i * nm i2 = (i + 1) * nm n_mG = PWSA.map_G(K1, K2, n0_mG) if optical_limit: n_mv = PWSA.map_v(K1, K2, n0_mv) n_mG[:, 0] = n_mv[:, 0] n_Mv[i1:i2, :] = n_mv n_MG[i1:i2, :] = n_mG if optical_limit: yield (None, df_M, deps_M, n_MG, n_Mv, None) else: yield (None, df_M, deps_M, n_MG, None, None) pb.finish() @timer('Get kpoint pair') def get_kpoint_pair(self, pd, s, K, n1, n2, m1, m2): wfs = self.calc.wfs q_c = pd.kd.bzk_kc[0] with self.timer('get k-points'): kpt1 = self.get_k_point(s, K, n1, n2) K2 = wfs.kd.find_k_plus_q(q_c, [kpt1.K])[0] kpt2 = self.get_k_point(s, K2, m1, m2, block=True) with self.timer('fft indices'): Q_G = self.get_fft_indices(kpt1.K, kpt2.K, q_c, pd, kpt1.shift_c - kpt2.shift_c) return KPointPair(kpt1, kpt2, Q_G) @timer('get_pair_density') def get_pair_density(self, pd, kptpair, n_n, m_m, optical_limit=False, intraband=False, Q_aGii=None): """Get pair density for a kpoint pair.""" if optical_limit: assert np.allclose(pd.kd.bzk_kc[0], 0.0) if Q_aGii is None: Q_aGii = self.initialize_paw_corrections(pd) kpt1 = kptpair.kpt1 kpt2 = kptpair.kpt2 Q_G = kptpair.Q_G # Fourier components of kpoint pair n_nmG = pd.empty((len(n_n), len(m_m))) if optical_limit: n_nmv = np.zeros((len(n_n), len(m_m), 3), pd.dtype) else: n_nmv = None for j, n in enumerate(n_n): Q_G = kptpair.Q_G with self.timer('conj'): ut1cc_R = kpt1.ut_nR[n].conj() with self.timer('paw'): C1_aGi = [np.dot(Q_Gii, P1_ni[n].conj()) for Q_Gii, P1_ni in zip(Q_aGii, kpt1.P_ani)] n_nmG[j] = self.calculate_pair_densities(ut1cc_R, C1_aGi, kpt2, pd, Q_G) if optical_limit: n_nmv[j] = self.optical_pair_density(n, m_m, kpt1, kpt2) if optical_limit: n_nmG[..., 0] = n_nmv[..., 0] if intraband: vel_mv = self.intraband_pair_density(kpt2) else: vel_mv = None return n_nmG, n_nmv, vel_mv @timer('get_pair_momentum') def get_pair_momentum(self, pd, kptpair, n_n, m_m, Q_avGii=None): """Calculate matrix elements of the momentum operator. Calculates:: n_{nm\mathrm{k}}\int_{\Omega_{\mathrm{cell}}}\mathrm{d}\mathbf{r} \psi_{n\mathrm{k}}^*(\mathbf{r}) e^{-i\,(\mathrm{q} + \mathrm{G})\cdot\mathbf{r}} \nabla\psi_{m\mathrm{k} + \mathrm{q}}(\mathbf{r}) pd: PlaneWaveDescriptor Plane wave descriptor of a single q_c. kptpair: KPointPair KpointPair object containing the two kpoints. n_n: list List of left-band indices (n). m_m: List of right-band indices (m). """ wfs = self.calc.wfs kpt1 = kptpair.kpt1 kpt2 = kptpair.kpt2 Q_G = kptpair.Q_G # Fourier components of kpoint pair # For the same band we kd = wfs.kd gd = wfs.gd k_c = kd.bzk_kc[kpt1.K] + kpt1.shift_c k_v = 2 * np.pi * np.dot(k_c, np.linalg.inv(gd.cell_cv).T) # Calculate k + G G_Gv = pd.get_reciprocal_vectors(add_q=True) kqG_Gv = k_v[np.newaxis] + G_Gv # Pair velocities n_nmvG = pd.zeros((len(n_n), len(m_m), 3)) # Calculate derivatives of left-wavefunction # (there will typically be fewer of these) ut_nvR = self.make_derivative(kpt1.s, kpt1.K, kpt1.n1, kpt1.n2) # PAW-corrections if Q_avGii is None: Q_avGii = self.initialize_paw_nabla_corrections(pd) # Iterate over occupied bands for j, n in enumerate(n_n): ut1cc_R = kpt1.ut_nR[n].conj() n_mG = self.calculate_pair_densities(ut1cc_R, [], kpt2, pd, Q_G) n_nmvG[j] = 1j * kqG_Gv.T[np.newaxis] * n_mG[:, np.newaxis] # Treat each cartesian component at a time for v in range(3): # Minus from integration by parts utvcc_R = -ut_nvR[n, v].conj() Cv1_aGi = [np.dot(P1_ni[n].conj(), Q_vGii[v]) for Q_vGii, P1_ni in zip(Q_avGii, kpt1.P_ani)] nv_mG = self.calculate_pair_densities(utvcc_R, Cv1_aGi, kpt2, pd, Q_G) n_nmvG[j, :, v] += nv_mG # We want the momentum operator n_nmvG *= -1j return n_nmvG @timer('Calculate pair-densities') def calculate_pair_densities(self, ut1cc_R, C1_aGi, kpt2, pd, Q_G): """Calculate FFT of pair-densities and add PAW corrections. ut1cc_R: 3-d complex ndarray Complex conjugate of the periodic part of the left hand side wave function. C1_aGi: list of ndarrays PAW corrections for all atoms. kpt2: KPoint object Right hand side k-point object. pd: PWDescriptor Plane-wave descriptor for for q=k2-k1. Q_G: 1-d int ndarray Mapping from flattened 3-d FFT grid to 0.5(G+q)^2 1: n0_Mv = np.empty((kpt2.blocksize * self.blockcomm.size, 3), dtype=complex) self.blockcomm.all_gather(n0_mv, n0_Mv) n0_mv = n0_Mv[:kpt2.n2 - kpt2.n1] return -1j * n0_mv def optical_pair_density(self, n, m_m, kpt1, kpt2): # Relative threshold for perturbation theory threshold = self.threshold eps1 = kpt1.eps_n[n] deps_m = (eps1 - kpt2.eps_n)[m_m] n0_mv = self.optical_pair_velocity(n, m_m, kpt1, kpt2) deps_m = deps_m.copy() deps_m[deps_m == 0.0] = np.inf smallness_mv = np.abs(-1e-3 * n0_mv / deps_m[:, np.newaxis]) inds_mv = (np.logical_and(np.inf > smallness_mv, smallness_mv > threshold)) n0_mv *= - 1 / deps_m[:, np.newaxis] n0_mv[inds_mv] = 0 return n0_mv @timer('Intraband') def intraband_pair_density(self, kpt, n_n=None, only_partially_occupied=True): """Calculate intraband matrix elements of nabla""" # Bands and check for block parallelization na, nb, n1 = kpt.na, kpt.nb, kpt.n1 vel_nv = np.zeros((nb - na, 3), dtype=complex) if n_n is None: n_n = np.arange(na, nb) assert np.max(n_n) < nb, print('This is too many bands') # Load kpoints kd = self.calc.wfs.kd gd = self.calc.wfs.gd k_c = kd.bzk_kc[kpt.K] + kpt.shift_c k_v = 2 * np.pi * np.dot(k_c, np.linalg.inv(gd.cell_cv).T) atomdata_a = self.calc.wfs.setups f_n = kpt.f_n # No carriers when T=0 width = self.calc.occupations.width if width == 0.0: return None # Only works with Fermi-Dirac distribution assert isinstance(self.calc.occupations, FermiDirac) dfde_n = (- 1. / width * (f_n - f_n**2.0)) # Analytical derivative partocc_n = np.abs(dfde_n) > 1e-5 # Is part. occupied? if only_partially_occupied and not partocc_n.any(): return None if only_partially_occupied: # Check for block par. consistency assert (partocc_n < nb).all(), \ print('Include more unoccupied bands ', + 'or less block parr.', file=self.fd) # Break bands into degenerate chunks degchunks_cn = [] # indexing c as chunk number for n in n_n: inds_n = np.nonzero(np.abs(kpt.eps_n[n - n1] - kpt.eps_n) < 1e-5)[0] + n1 # Has this chunk already been computed? oldchunk = any([n in chunk for chunk in degchunks_cn]) if not oldchunk and \ (partocc_n[n - n1] or not only_partially_occupied): assert all([ind in n_n for ind in inds_n]), \ print('\nYou are cutting over a degenerate band ' + 'using block parallelization.', inds_n, n_n, file=self.fd) degchunks_cn.append((inds_n)) # Calculate matrix elements by diagonalizing each block for ind_n in degchunks_cn: deg = len(ind_n) ut_nvR = self.calc.wfs.gd.zeros((deg, 3), complex) vel_nnv = np.zeros((deg, deg, 3), dtype=complex) # States are included starting from kpt.na ut_nR = kpt.ut_nR[ind_n - na] # Get derivatives for ind, ut_vR in zip(ind_n, ut_nvR): ut_vR[:] = self.make_derivative(kpt.s, kpt.K, ind, ind + 1)[0] # Treat the whole degenerate chunk for n in range(deg): ut_vR = ut_nvR[n] C_avi = [np.dot(atomdata.nabla_iiv.T, P_ni[ind_n[n] - na]) for atomdata, P_ni in zip(atomdata_a, kpt.P_ani)] nabla0_nv = -self.calc.wfs.gd.integrate(ut_vR, ut_nR).T nt_n = self.calc.wfs.gd.integrate(ut_nR[n], ut_nR) nabla0_nv += 1j * nt_n[:, np.newaxis] * k_v[np.newaxis, :] for C_vi, P_ni in zip(C_avi, kpt.P_ani): gemm(1.0, C_vi, P_ni[ind_n - na], 1.0, nabla0_nv, 'c') vel_nnv[n] = -1j * nabla0_nv for iv in range(3): vel, _ = np.linalg.eig(vel_nnv[..., iv]) vel_nv[ind_n - na, iv] = vel # Use eigenvalues return vel_nv[n_n - na] def get_fft_indices(self, K1, K2, q_c, pd, shift0_c): """Get indices for G-vectors inside cutoff sphere.""" kd = self.calc.wfs.kd N_G = pd.Q_qG[0] shift_c = (shift0_c + (q_c - kd.bzk_kc[K2] + kd.bzk_kc[K1]).round().astype(int)) if shift_c.any(): n_cG = np.unravel_index(N_G, pd.gd.N_c) n_cG = [n_G + shift for n_G, shift in zip(n_cG, shift_c)] N_G = np.ravel_multi_index(n_cG, pd.gd.N_c, 'wrap') return N_G def construct_symmetry_operators(self, K): """Construct symmetry operators for wave function and PAW projections. We want to transform a k-point in the irreducible part of the BZ to the corresponding k-point with index K. Returns U_cc, T, a_a, U_aii, shift_c and time_reversal, where: * U_cc is a rotation matrix. * T() is a function that transforms the periodic part of the wave function. * a_a is a list of symmetry related atom indices * U_aii is a list of rotation matrices for the PAW projections * shift_c is three integers: see code below. * time_reversal is a flag - if True, projections should be complex conjugated. See the get_k_point() method for how to use these tuples. """ wfs = self.calc.wfs kd = wfs.kd s = kd.sym_k[K] U_cc = kd.symmetry.op_scc[s] time_reversal = kd.time_reversal_k[K] ik = kd.bz2ibz_k[K] k_c = kd.bzk_kc[K] ik_c = kd.ibzk_kc[ik] sign = 1 - 2 * time_reversal shift_c = np.dot(U_cc, ik_c) - k_c * sign assert np.allclose(shift_c.round(), shift_c) shift_c = shift_c.round().astype(int) if (U_cc == np.eye(3)).all(): T = lambda f_R: f_R else: N_c = self.calc.wfs.gd.N_c i_cr = np.dot(U_cc.T, np.indices(N_c).reshape((3, -1))) i = np.ravel_multi_index(i_cr, N_c, 'wrap') T = lambda f_R: f_R.ravel()[i].reshape(N_c) if time_reversal: T0 = T T = lambda f_R: T0(f_R).conj() shift_c *= -1 a_a = [] U_aii = [] for a, id in enumerate(self.calc.wfs.setups.id_a): b = kd.symmetry.a_sa[s, a] S_c = np.dot(self.spos_ac[a], U_cc) - self.spos_ac[b] x = np.exp(2j * pi * np.dot(ik_c, S_c)) U_ii = wfs.setups[a].R_sii[s].T * x a_a.append(b) U_aii.append(U_ii) return U_cc, T, a_a, U_aii, shift_c, time_reversal @timer('Initialize PAW corrections') def initialize_paw_corrections(self, pd, soft=False): print('Initializing PAW Corrections', file=self.fd) wfs = self.calc.wfs q_v = pd.K_qv[0] optical_limit = np.allclose(q_v, 0) G_Gv = pd.get_reciprocal_vectors() if optical_limit: G_Gv[0] = 1 pos_av = np.dot(self.spos_ac, pd.gd.cell_cv) # Collect integrals for all species: Q_xGii = {} for id, atomdata in wfs.setups.setups.items(): if soft: ghat = PWLFC([atomdata.ghat_l], pd) ghat.set_positions(np.zeros((1, 3))) Q_LG = ghat.expand() Q_Gii = np.dot(atomdata.Delta_iiL, Q_LG).T else: Q_Gii = two_phi_planewave_integrals(G_Gv, atomdata) ni = atomdata.ni Q_Gii.shape = (-1, ni, ni) Q_xGii[id] = Q_Gii Q_aGii = [] for a, atomdata in enumerate(wfs.setups): id = wfs.setups.id_a[a] Q_Gii = Q_xGii[id] x_G = np.exp(-1j * np.dot(G_Gv, pos_av[a])) Q_aGii.append(x_G[:, np.newaxis, np.newaxis] * Q_Gii) if optical_limit: Q_aGii[a][0] = atomdata.dO_ii return Q_aGii @timer('Initialize PAW corrections') def initialize_paw_nabla_corrections(self, pd, soft=False): print('Initializing nabla PAW Corrections', file=self.fd) wfs = self.calc.wfs G_Gv = pd.get_reciprocal_vectors() pos_av = np.dot(self.spos_ac, pd.gd.cell_cv) # Collect integrals for all species: Q_xvGii = {} for id, atomdata in wfs.setups.setups.items(): if soft: raise NotImplementedError else: Q_vGii = two_phi_nabla_planewave_integrals(G_Gv, atomdata) ni = atomdata.ni Q_vGii.shape = (3, -1, ni, ni) Q_xvGii[id] = Q_vGii Q_avGii = [] for a, atomdata in enumerate(wfs.setups): id = wfs.setups.id_a[a] Q_vGii = Q_xvGii[id] x_G = np.exp(-1j * np.dot(G_Gv, pos_av[a])) Q_avGii.append(x_G[np.newaxis, :, np.newaxis, np.newaxis] * Q_vGii) return Q_avGii def calculate_derivatives(self, kpt): ut_sKnvR = [{}, {}] ut_nvR = self.make_derivative(kpt.s, kpt.K, kpt.n1, kpt.n2) ut_sKnvR[kpt.s][kpt.K] = ut_nvR return ut_sKnvR @timer('Derivatives') def make_derivative(self, s, K, n1, n2): wfs = self.calc.wfs if self.real_space_derivatives: grad_v = [Gradient(wfs.gd, v, 1.0, 4, complex).apply for v in range(3)] U_cc, T, a_a, U_aii, shift_c, time_reversal = \ self.construct_symmetry_operators(K) A_cv = wfs.gd.cell_cv M_vv = np.dot(np.dot(A_cv.T, U_cc.T), np.linalg.inv(A_cv).T) ik = wfs.kd.bz2ibz_k[K] kpt = wfs.kpt_u[s * wfs.kd.nibzkpts + ik] psit_nG = kpt.psit_nG iG_Gv = 1j * wfs.pd.get_reciprocal_vectors(q=ik, add_q=False) ut_nvR = wfs.gd.zeros((n2 - n1, 3), complex) for n in range(n1, n2): for v in range(3): if self.real_space_derivatives: ut_R = T(wfs.pd.ifft(psit_nG[n], ik)) grad_v[v](ut_R, ut_nvR[n - n1, v], np.ones((3, 2), complex)) else: ut_R = T(wfs.pd.ifft(iG_Gv[:, v] * psit_nG[n], ik)) for v2 in range(3): ut_nvR[n - n1, v2] += ut_R * M_vv[v, v2] return ut_nvR gpaw-0.11.0.13004/gpaw/response/base.py0000664000175000017500000005112412553643470017537 0ustar jensjjensj00000000000000from __future__ import print_function import sys from time import time, ctime import numpy as np from math import sqrt, pi from datetime import timedelta from ase.units import Hartree, Bohr from ase.utils import devnull from gpaw import GPAW, extra_parameters from gpaw.utilities import unpack from gpaw.utilities.blas import gemmdot, gemv from gpaw.mpi import world, rank, size, serial_comm from gpaw.lfc import LocalizedFunctionsCollection as LFC from gpaw.grid_descriptor import GridDescriptor from gpaw.utilities.memory import maxrss from gpaw.fd_operators import Gradient from gpaw.response.cell import get_primitive_cell, set_Gvectors from gpaw.response.math_func import delta_function, \ two_phi_planewave_integrals from gpaw.response.parallel import set_communicator, \ parallel_partition, SliceAlongFrequency, SliceAlongOrbitals from gpaw.response.kernel import calculate_Kxc, calculate_Kc, calculate_Kc_q from gpaw.kpt_descriptor import KPointDescriptor from gpaw.wavefunctions.pw import PWLFC import gpaw.wavefunctions.pw as pw class BASECHI: """This class is to store the basic common stuff for chi and bse.""" def __init__(self, calc=None, nbands=None, w=None, q=None, eshift=None, ecut=10., density_cut=None, G_plus_q=False, eta=0.2, rpad=None, ftol=1e-5, txt=None, optical_limit=False): if rpad is None: rpad = np.ones(3, int) self.txtname = txt self.output_init() if isinstance(calc, str): # Always use serial_communicator when a filename is given. self.calc = GPAW(calc, communicator=serial_comm, txt=None) else: # To be optimized so that the communicator is loaded automatically # according to kcommsize. # # so temporarily it is used like this : # kcommsize = int (should <= world.size) # r0 = rank % kcommsize # ranks = np.arange(r0, r0+size, kcommsize) # calc = GPAW(filename.gpw, communicator=ranks, txt=None) self.calc = calc if self.calc is not None: self.pwmode = isinstance(self.calc.wfs, pw.PWWaveFunctions) else: self.pwmode = False if self.pwmode: assert self.calc.wfs.world.size == 1 self.nbands = nbands self.q_c = q # chi.py modifies the input array w by dividing by Hartree. # This will change the user-supplied arrays in-place unless # we create a copy. So now we create a copy. *Grumble* # # To make matters worse, w is allowed to be None (why not take # care of that *before*?? This should really be cleaned up. if isinstance(w, np.ndarray): w = w.copy() self.w_w = w self.eta = eta self.ftol = ftol if isinstance(ecut, int) or isinstance(ecut, float): self.ecut = np.ones(3) * ecut else: assert len(ecut) == 3 self.ecut = np.array(ecut, dtype=float) self.density_cut = density_cut self.G_plus_q = G_plus_q self.rpad = rpad self.optical_limit = optical_limit #if self.optical_limit: self.qopt = 1e-5 self.eshift = eshift def initialize(self): self.eta /= Hartree self.ecut /= Hartree calc = self.calc self.nspins = self.calc.wfs.nspins # kpoint init self.kd = kd = calc.wfs.kd self.nikpt = kd.nibzkpts self.ftol /= kd.nbzkpts # cell init self.acell_cv = calc.wfs.gd.cell_cv self.acell_cv, self.bcell_cv, self.vol, self.BZvol = \ get_primitive_cell(self.acell_cv,rpad=self.rpad) # grid init gd = calc.wfs.gd.new_descriptor(comm=serial_comm) self.pbc = gd.pbc_c self.gd = gd self.nG0 = np.prod(gd.N_c) # Number of grid points and volume including zero padding self.nGrpad = gd.N_c * self.rpad self.nG0rpad = np.prod(self.nGrpad) self.d_c = [Gradient(gd, i, n=4, dtype=complex).apply for i in range(3)] # obtain eigenvalues, occupations nibzkpt = kd.nibzkpts kweight_k = kd.weight_k self.eFermi = self.calc.occupations.get_fermi_level() try: self.e_skn self.printtxt('Use eigenvalues from user.') except: self.printtxt('Use eigenvalues from the calculator.') self.e_skn = {} self.f_skn = {} for ispin in range(self.nspins): self.e_skn[ispin] = np.array([calc.get_eigenvalues(kpt=k, spin=ispin) for k in range(nibzkpt)]) / Hartree self.f_skn[ispin] = np.array([calc.get_occupation_numbers(kpt=k, spin=ispin) / kweight_k[k] for k in range(nibzkpt)]) / kd.nbzkpts #self.printtxt('Eigenvalues(k=0) are:') #print >> self.txt, self.e_skn[0][0] * Hartree self.enoshift_skn = {} for ispin in range(self.nspins): self.enoshift_skn[ispin] = self.e_skn[ispin].copy() if self.eshift is not None: self.add_discontinuity(self.eshift) self.printtxt('Shift unoccupied bands by %f eV' % (self.eshift)) # k + q init if self.q_c is not None: self.qq_v = np.dot(self.q_c, self.bcell_cv) # summation over c if self.optical_limit: kq_k = np.arange(kd.nbzkpts) self.expqr_g = 1. else: r_vg = gd.get_grid_point_coordinates() # (3, nG) qr_g = gemmdot(self.qq_v, r_vg, beta=0.0) self.expqr_g = np.exp(-1j * qr_g) del r_vg, qr_g kq_k = kd.find_k_plus_q(self.q_c) self.kq_k = kq_k # Plane wave init if self.G_plus_q: self.npw, self.Gvec_Gc, self.Gindex_G = set_Gvectors(self.acell_cv, self.bcell_cv, self.gd.N_c, self.ecut, q=self.q_c) else: self.npw, self.Gvec_Gc, self.Gindex_G = set_Gvectors(self.acell_cv, self.bcell_cv, self.gd.N_c, self.ecut) # band init if self.nbands is None: self.nbands = calc.wfs.bd.nbands self.nvalence = calc.wfs.nvalence # Projectors init setups = calc.wfs.setups self.spos_ac = calc.atoms.get_scaled_positions() if self.pwmode: self.pt = PWLFC([setup.pt_j for setup in setups], self.calc.wfs.pd) self.pt.set_positions(self.spos_ac) else: self.pt = LFC(gd, [setup.pt_j for setup in setups], KPointDescriptor(self.kd.bzk_kc), dtype=complex, forces=True) self.pt.set_positions(self.spos_ac) # Printing calculation information self.print_stuff() return def output_init(self): if self.txtname is None: if rank == 0: self.txt = sys.stdout else: sys.stdout = devnull self.txt = devnull elif self.txtname == devnull: self.txt = devnull else: assert isinstance(self.txtname, str) from ase.parallel import paropen self.txt = paropen(self.txtname,'w') def printtxt(self, text): print(text, file=self.txt) def print_stuff(self): printtxt = self.printtxt printtxt('') printtxt('Parameters used:') printtxt('') printtxt('Unit cell (a.u.):') printtxt(self.acell_cv) printtxt('Volume of cell (a.u.**3) : %f' % self.vol) printtxt('Reciprocal cell (1/a.u.)') printtxt(self.bcell_cv) printtxt('BZ volume (1/a.u.**3) : %f' % self.BZvol) printtxt('Number of G-vectors / Grid : %d %s' % (self.nG0, tuple(self.gd.N_c))) printtxt('') printtxt('Coulomb interaction cutoff : %s' % self.vcut) printtxt('') printtxt('Number of bands : %d' % self.nbands) printtxt('Number of kpoints : %d' % self.kd.nbzkpts) if self.ecut[0] == self.ecut[1] and self.ecut[0] == self.ecut[2]: printtxt('Planewave ecut (eV) : %4.1f' % (self.ecut[0] * Hartree)) else: printtxt('Planewave ecut (eV) : (%f, %f, %f)' % tuple(self.ecut * Hartree)) printtxt('Number of planewave used : %d' % self.npw) printtxt('Broadening (eta) : %f' % (self.eta * Hartree)) printtxt('') if self.q_c is not None: if self.optical_limit: printtxt('Optical limit calculation ! (q=1e-5)') else: printtxt('q in reduced coordinate : (%f %f %f)' % tuple(self.q_c)) printtxt('q in cartesian coordinate (1/A): (%f %f %f)' % tuple(self.qq_v / Bohr)) printtxt('|q| (1/A) : %f' % np.linalg.norm(self.qq_v / Bohr)) def timing(self, i, t0, n_local, txt): if i == 0: dt = time() - t0 self.totaltime = dt * n_local self.printtxt(' Finished %s 0 in %s, estimate %s left.' % (txt, timedelta(seconds=round(dt)), timedelta(seconds=round(self.totaltime)))) if rank == 0 and n_local // 5 > 0: if i > 0 and i % (n_local // 5) == 0: dt = time() - t0 self.printtxt(' Finished %s %d in %s, estimate %s left.' % (txt, i, timedelta(seconds=round(dt)), timedelta(seconds=round(self.totaltime - dt)))) def get_phi_aGp(self, q_c=None, parallel=True, alldir=False): if q_c is None: q_c = self.q_c qq_v = self.qq_v optical_limit = self.optical_limit else: optical_limit = False if np.abs(q_c).sum() < 1e-8: q_c = np.array([0.0001, 0, 0]) optical_limit = True qq_v = np.dot(q_c, self.bcell_cv) setups = self.calc.wfs.setups spos_ac = self.calc.atoms.get_scaled_positions() kk_Gv = gemmdot(q_c + self.Gvec_Gc, self.bcell_cv.copy(), beta=0.0) phi_aGp = {} phiG0_avp = {} if parallel: from gpaw.response.parallel import parallel_partition npw, npw_local, Gstart, Gend = parallel_partition( self.npw, self.comm.rank, self.comm.size, reshape=False) else: Gstart = 0 Gend = self.npw for a, id in enumerate(setups.id_a): phi_aGp[a] = two_phi_planewave_integrals(kk_Gv, setups[a], Gstart, Gend) for iG in range(Gstart, Gend): phi_aGp[a][iG] *= np.exp(-1j * 2. * pi * np.dot(q_c + self.Gvec_Gc[iG], spos_ac[a]) ) if parallel: self.comm.sum(phi_aGp[a]) # For optical limit, G == 0 part should change if optical_limit: for a, id in enumerate(setups.id_a): nabla_iiv = setups[a].nabla_iiv phi_aGp[a][0] = -1j * (np.dot(nabla_iiv, qq_v)).ravel() phiG0_avp[a] = np.zeros((3, len(phi_aGp[a][0])), complex) for dir in range(3): # 3 dimension q2_c = np.diag((1,1,1))[dir] * self.qopt qq2_v = np.dot(q2_c, self.bcell_cv) # summation over c phiG0_avp[a][dir] = -1j * (np.dot(nabla_iiv, qq2_v)).ravel() if alldir: return phi_aGp, phiG0_avp else: return phi_aGp def get_wavefunction(self, ibzk, n, check_focc=True, spin=0): if (self.calc.wfs.world.size == 1 or self.calc.wfs.gd.comm.size != 1 or self.calc.input_parameters['mode'] == 'lcao'): if not check_focc: return else: psit_G = self.calc.wfs.get_wave_function_array(n, ibzk, spin) if self.calc.wfs.world.size == 1: return np.complex128(psit_G) if self.calc.wfs.world.rank != 0: psit_G = self.calc.wfs.gd.empty(dtype=self.calc.wfs.dtype, global_array=True) self.calc.wfs.world.broadcast(psit_G, 0) return np.complex128(psit_G) else: # support ground state calculation with kpoint and band parallelization # but domain decomposition must = 1 kpt_rank, u = self.calc.wfs.kd.get_rank_and_index(0, ibzk) bzkpt_rank = self.kcomm.rank band_rank, myn = self.calc.wfs.bd.who_has(n) assert self.calc.wfs.gd.comm.size == 1 world_rank = (kpt_rank * self.calc.wfs.band_comm.size + band_rank) # in the following, kpt_rank is assigned to world_rank klist = np.array([world_rank, u, bzkpt_rank, myn]) klist_kcomm = np.zeros((self.kcomm.size, 4), dtype=int) self.kcomm.all_gather(klist, klist_kcomm) check_focc_global = np.zeros(self.kcomm.size, dtype=bool) self.kcomm.all_gather(np.array([check_focc]), check_focc_global) psit_G = self.calc.wfs.gd.empty(dtype=self.calc.wfs.dtype) for i in range(self.kcomm.size): if check_focc_global[i]: kpt_rank, u, bzkpt_rank, nlocal = klist_kcomm[i] if kpt_rank == bzkpt_rank: if rank == kpt_rank: psit_G = self.calc.wfs.kpt_u[u].psit_nG[nlocal] else: if rank == kpt_rank: world.send(self.calc.wfs.kpt_u[u].psit_nG[nlocal], bzkpt_rank, 1300+bzkpt_rank) if rank == bzkpt_rank: psit_G = self.calc.wfs.gd.empty(dtype=self.calc.wfs.dtype) world.receive(psit_G, kpt_rank, 1300+bzkpt_rank) self.wScomm.broadcast(psit_G, 0) return psit_G def add_discontinuity(self, shift): for ispin in range(self.nspins): for k in range(self.kd.nibzkpts): for i in range(self.e_skn[0].shape[1]): if self.e_skn[ispin][k,i] > self.eFermi: self.e_skn[ispin][k,i] += shift / Hartree def density_matrix(self, n, m, k, kq=None, spin1=0, spin2=0, phi_aGp=None, Gspace=True): gd = self.gd kd = self.kd optical_limit = False if kq is None: kq = self.kq_k[k] expqr_g = self.expqr_g q_v = self.qq_v optical_limit = self.optical_limit q_c = self.q_c else: q_c = kd.bzk_kc[kq] - kd.bzk_kc[k] q_c[np.where(q_c>0.501)] -= 1 q_c[np.where(q_c<-0.499)] += 1 if (np.abs(q_c) < self.ftol).all(): optical_limit = True q_c = self.q_c q_v = np.dot(q_c, self.bcell_cv) r_vg = gd.get_grid_point_coordinates() # (3, nG) qr_g = gemmdot(q_v, r_vg, beta=0.0) expqr_g = np.exp(-1j * qr_g) if optical_limit: expqr_g = 1 ibzkpt1 = kd.bz2ibz_k[k] ibzkpt2 = kd.bz2ibz_k[kq] psitold_g = self.get_wavefunction(ibzkpt1, n, True, spin=spin1) psit1_g = kd.transform_wave_function(psitold_g, k) psitold_g = self.get_wavefunction(ibzkpt2, m, True, spin=spin2) psit2_g = kd.transform_wave_function(psitold_g, kq) if Gspace is False: return psit1_g.conj() * psit2_g * expqr_g else: tmp_g = psit1_g.conj()* psit2_g * expqr_g # zero padding is included through the FFT rho_g = np.fft.fftn(tmp_g, s=self.nGrpad) * self.vol / self.nG0rpad # Here, planewave cutoff is applied rho_G = rho_g.ravel()[self.Gindex_G] if optical_limit: dpsit_g = gd.empty(dtype=complex) tmp = np.zeros((3), dtype=complex) phase_cd = np.exp(2j * pi * gd.sdisp_cd * kd.bzk_kc[kq, :, np.newaxis]) for ix in range(3): self.d_c[ix](psit2_g, dpsit_g, phase_cd) tmp[ix] = gd.integrate(psit1_g.conj() * dpsit_g) rho_G[0] = -1j * np.dot(q_v, tmp) calc = self.calc pt = self.pt if not self.pwmode: if calc.wfs.world.size > 1 or kd.nbzkpts == 1: P1_ai = pt.dict() pt.integrate(psit1_g, P1_ai, k) P2_ai = pt.dict() pt.integrate(psit2_g, P2_ai, kq) else: P1_ai = self.get_P_ai(k, n, spin1) P2_ai = self.get_P_ai(kq, m, spin2) else: # first calculate P_ai at ibzkpt, then rotate to k u = self.kd.get_rank_and_index(spin1, ibzkpt1)[1] Ptmp_ai = pt.dict() kpt = calc.wfs.kpt_u[u] pt.integrate(kpt.psit_nG[n], Ptmp_ai, ibzkpt1) P1_ai = self.get_P_ai(k, n, spin1, Ptmp_ai) u = self.kd.get_rank_and_index(spin2, ibzkpt2)[1] Ptmp_ai = pt.dict() kpt = calc.wfs.kpt_u[u] pt.integrate(kpt.psit_nG[m], Ptmp_ai, ibzkpt2) P2_ai = self.get_P_ai(kq, m, spin2, Ptmp_ai) if phi_aGp is None: try: if not self.mode == 'RPA': if optical_limit: iq = kd.where_is_q(np.zeros(3), self.bzq_qc) else: iq = kd.where_is_q(q_c, self.bzq_qc) assert np.abs(self.bzq_qc[iq] - q_c).sum() < 1e-8 phi_aGp = self.load_phi_aGp(self.reader, iq) #phi_qaGp[iq] except AttributeError: phi_aGp = self.phi_aGp for a, id in enumerate(self.calc.wfs.setups.id_a): P_p = np.outer(P1_ai[a].conj(), P2_ai[a]).ravel() phi_Gp = np.ascontiguousarray(phi_aGp[a], complex) gemv(1.0, phi_Gp, P_p, 1.0, rho_G) if optical_limit: if n==m: rho_G[0] = 1. elif np.abs(self.e_skn[spin2][ibzkpt2, m] - self.e_skn[spin1][ibzkpt1, n]) < 1e-5: rho_G[0] = 0. else: rho_G[0] /= (self.enoshift_skn[spin2][ibzkpt2, m] - self.enoshift_skn[spin1][ibzkpt1, n]) return rho_G def get_P_ai(self, k, n, spin=0, Ptmp_ai=None): calc = self.calc kd = self.calc.wfs.kd spos_ac = self.spos_ac ibzkpt = kd.bz2ibz_k[k] u = ibzkpt + kd.nibzkpts * spin kpt = calc.wfs.kpt_u[u] s = kd.sym_k[k] time_reversal = kd.time_reversal_k[k] P_ai = {} for a, id in enumerate(calc.wfs.setups.id_a): b = kd.symmetry.a_sa[s, a] S_c = (np.dot(spos_ac[a], kd.symmetry.op_scc[s]) - kd.symmetry.ft_sc[s] - spos_ac[b]) #print abs(S_c.round() - S_c).max() #print 'S_c', abs(S_c).max() assert abs(S_c.round() - S_c).max() < 1e-8 ############## k_c = kd.ibzk_kc[kpt.k] x = np.exp(2j * pi * np.dot(k_c, S_c)) if Ptmp_ai is None: P_i = np.dot(calc.wfs.setups[a].R_sii[s], kpt.P_ani[b][n]) * x else: P_i = np.dot(calc.wfs.setups[a].R_sii[s], Ptmp_ai[b]) * x if time_reversal: P_i = P_i.conj() P_ai[a] = P_i return P_ai gpaw-0.11.0.13004/gpaw/response/fxc.py0000664000175000017500000000336112553643470017405 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np def Bootstrap(chi0_wGG, Nw, Kc_GG, printtxt, print_bootstrap, world): Nw_local = chi0_wGG.shape[0] npw = chi0_wGG.shape[1] # arxiv 1107.0199 fxc_GG = np.zeros((npw, npw), dtype=complex) tmp_GG = np.eye(npw, npw) dminv_wGG = np.zeros((Nw_local, npw, npw), dtype=complex) dflocal_w = np.zeros(Nw_local, dtype=complex) df_w = np.zeros(Nw, dtype=complex) for iscf in range(120): dminvold_wGG = dminv_wGG.copy() Kxc_GG = Kc_GG + fxc_GG for iw in range(Nw_local): chi_GG = np.dot(chi0_wGG[iw], np.linalg.inv(tmp_GG - np.dot(Kxc_GG, chi0_wGG[iw]))) dminv_wGG[iw] = tmp_GG + np.dot(Kc_GG, chi_GG) if world.rank == 0: alpha = dminv_wGG[0,0,0] / (Kc_GG[0,0] * chi0_wGG[0,0,0]) fxc_GG = alpha * Kc_GG world.broadcast(fxc_GG, 0) error = np.abs(dminvold_wGG - dminv_wGG).sum() if world.sum(error) < 0.1: printtxt('Self consistent fxc finished in %d iterations ! ' %(iscf)) break if iscf > 100: printtxt('Too many fxc scf steps !') if print_bootstrap: for iw in range(Nw_local): dflocal_w[iw] = np.linalg.inv(dminv_wGG[iw])[0,0] world.all_gather(dflocal_w, df_w) if world.rank == 0: f = open('df_scf%d' %(iscf), 'w') for iw in range(Nw): print(np.real(df_w[iw]), np.imag(df_w[iw]), file=f) f.close() world.barrier() for iw in range(Nw_local): dflocal_w[iw] = np.linalg.inv(dminv_wGG[iw])[0,0] world.all_gather(dflocal_w, df_w) return df_w gpaw-0.11.0.13004/gpaw/response/parallel.py0000664000175000017500000002114012553643470020414 0ustar jensjjensj00000000000000# The parallel code is from Carsten Rostgaard # import numpy as np from gpaw.mpi import serial_comm from gpaw.mpi import rank, size, world from gpaw.io import open def set_communicator(world, rank, size, kcommsize=None): """Communicator inilialized.""" # wcomm is always set to world wcomm = world if kcommsize is None or kcommsize == size or size == 1: # By default, only use parallization in kpoints # then kcomm is set to world communicator # and wS is not parallelized kcomm = world wScomm = serial_comm else: # If use wS parallization for storage of spectral function # then new kpoint and wS communicator are generated assert kcommsize != size r0 = (rank // kcommsize) * kcommsize ranks = np.arange(r0, r0 + kcommsize) kcomm = world.new_communicator(ranks) # wS comm generated r0 = rank % kcommsize ranks = np.arange(r0, r0+size, kcommsize) wScomm = world.new_communicator(ranks) return kcomm, wScomm, wcomm def parallel_partition(N, commrank, commsize, reshape=True, positive=False): if reshape is True: if N % commsize != 0: N -= N % commsize if positive: N += commsize assert N % commsize == 0 N_local = N // commsize N_residual = N - N_local * commsize if commrank < N_residual: N_local += 1 N_start = commrank * N_local N_end = (commrank + 1) * N_local else: offset = N_residual * (N_local + 1) N_start = offset + (commrank - N_residual) * N_local N_end = offset + (commrank + 1 - N_residual) * N_local return N, N_local, N_start, N_end def parallel_partition_list(N, commrank, commsize): Nlist = [] for i in range(N): if commrank == i % commsize: Nlist.append(i) N_local = len(Nlist) return N, N_local, Nlist def collect_orbitals(a_xo, coords, comm, root=0): """Collect array distributed over orbitals to root-CPU. Input matrix has last axis distributed amongst CPUs, return is None on slaves, and the collected array on root. The distribution can be uneven amongst CPUs. The list coords gives the number of values for each CPU. """ a_xo = np.ascontiguousarray(a_xo) if comm.size == 1: return a_xo # All slaves send their piece to ``root``: # There can be several sends before the corresponding receives # are posted, so use syncronous send here if comm.rank != root: comm.ssend(a_xo, root, 112) return None # On root, put the subdomains from the slaves into the big array # for the whole domain on root: xshape = a_xo.shape[:-1] Norb2 = sum(coords) # total number of orbital indices a_xO = np.empty(xshape + (Norb2,), a_xo.dtype) o = 0 for rank, norb in enumerate(coords): if rank != root: tmp_xo = np.empty(xshape + (norb,), a_xo.dtype) comm.receive(tmp_xo, rank, 112) a_xO[..., o:o + norb] = tmp_xo else: a_xO[..., o:o + norb] = a_xo o += norb return a_xO def collect_energies(a_ex, comm, root=0): """Collect array distributed over energies to root-CPU. Input matrix has first axis distributed evenly amongst CPUs, return is None on slaves, and the collected array on root. As the distribution is even amongst CPUs, gather can be used here. """ a_ex = np.ascontiguousarray(a_ex) if comm.size == 1: return a_ex nenergies, xshape = a_ex.shape[0], a_ex.shape[1:] if comm.rank == root: a_Ex = np.empty((comm.size, nenergies) + xshape, a_ex.dtype) comm.gather(a_ex, root, a_Ex) return a_Ex.reshape((comm.size * nenergies,) + xshape) else: comm.gather(a_ex, root) return None def SliceAlongFrequency(a_eO, coords, comm): """Slice along frequency axis. Input array has subset of energies, but full orbital matrix. Output has full energy, but subset of flattened orbital matrix. coords is a list of the number of orbital indices per cpu. """ # flatten orbital axis a_eO = np.ascontiguousarray(a_eO).reshape(len(a_eO), -1) if comm.size == 1: return a_eO o = 0 for rank, norb in enumerate(coords): a_eo = a_eO[:, o:o + norb].copy() tmp = collect_energies(a_eo, comm, root=rank) if rank == comm.rank: a_Eo = tmp o += norb return a_Eo def SliceAlongOrbitals(a_Eo, coords, comm): """Slice along orbital axis. Input has full energy, but subset of flattened orbital matrix. Output array has subset of energies, but full orbital matrix. coords is a list of the number of orbital indices per cpu. """ Norb = np.sqrt(sum(coords)).astype(int) nenergies = len(a_Eo) // comm.size # energy points per processor. a_Eo = np.ascontiguousarray(a_Eo) if comm.size == 1: return a_Eo.reshape(nenergies, Norb, Norb) for rank in range(comm.size): a_eo = a_Eo[rank * nenergies:(rank + 1) * nenergies, :].copy() tmp = collect_orbitals(a_eo, coords, comm, root=rank) if rank == comm.rank: a_eO = tmp.reshape(nenergies, Norb, Norb) return a_eO def GatherOrbitals(a_Eo, coords, comm): """Slice along orbital axis. Input has subset of flattened orbital matrix. Output array has full orbital matrix. coords is a list of the number of orbital indices per cpu. """ Norb = np.sqrt(sum(coords)).astype(int) if len(np.shape(a_Eo)) == 1: nenergies = 1 else: nenergies = len(a_Eo) a_Eo = np.ascontiguousarray(a_Eo) if comm.size == 1: if nenergies == 1: return a_Eo.reshape(nenergies, Norb, Norb)[0] else: return a_Eo.reshape(nenergies, Norb, Norb) for rank in range(comm.size): tmp = collect_orbitals(a_Eo, coords, comm, root=rank) if rank == comm.rank: if nenergies==1: a_EO = tmp.reshape(Norb, Norb) else: a_EO = tmp.reshape(nenergies, Norb, Norb) return a_EO def par_write(filename, name, comm, chi0_wGG): ## support only world communicator at the moment assert comm.size == size assert comm.rank == rank Nw_local, npw, npw1 = chi0_wGG.shape assert npw == npw1 Nw = Nw_local * size w = open(filename, 'w', comm) w.dimension('Nw', Nw) w.dimension('npw', npw) w.add(name, ('Nw', 'npw', 'npw'), dtype=complex) if rank == 0: tmp = np.zeros_like(chi0_wGG[0]) for iw in range(Nw): irank = iw // Nw_local if irank == 0: if rank == 0: w.fill(chi0_wGG[iw]) else: if rank == irank: world.send(chi0_wGG[iw-rank*Nw_local], 0, irank+100) if rank == 0: world.receive(tmp, irank, irank+100) w.fill(tmp) if rank == 0: w.close() world.barrier() def par_read(filename, name, Nw=None): r = open(filename, 'r') if Nw is None: Nw = r.dimension('Nw') else: assert Nw <= r.dimension('Nw') npw = r.dimension('npw') Nw_local = Nw // size chi0_wGG = np.zeros((Nw_local, npw, npw), dtype=complex) for iw in range(Nw_local): chi0_wGG[iw] = r.get(name, iw+rank*Nw_local) r.close() return chi0_wGG def gatherv(m, N=None): if world.size == 1: return m ndim = m.ndim if ndim == 2: n, N = m.shape assert n < N M = np.zeros((N, N), dtype=complex) elif ndim == 1: n = m.shape[0] M = np.zeros(N, dtype=complex) else: print('Not Implemented') XX n_index = np.zeros(size, dtype=int) world.all_gather(np.array([n]), n_index) root = 0 if rank != root: world.ssend(m, root, 112+rank) else: for irank, n in enumerate(n_index): if irank == root: if ndim == 2: M[:n_index[0] :] = m else: M[:n_index[0]] = m else: n_start = n_index[0:irank].sum() n_end = n_index[0:irank+1].sum() if ndim == 2: tmp_nN = np.zeros((n, N), dtype=complex) world.receive(tmp_nN, irank, 112+irank) M[n_start:n_end, :] = tmp_nN else: tmp_n = np.zeros(n, dtype=complex) world.receive(tmp_n, irank, 112+irank) M[n_start:n_end] = tmp_n world.broadcast(M, root) return M gpaw-0.11.0.13004/gpaw/response/__init__.py0000664000175000017500000000000012553643470020347 0ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/hgh.py0000664000175000017500000004622712553643470015545 0ustar jensjjensj00000000000000import hashlib import numpy as np from ase.data import atomic_numbers from gpaw.utilities import pack2 from gpaw.atom.radialgd import AERadialGridDescriptor from gpaw.atom.configurations import configurations from gpaw.pseudopotential import PseudoPotential setups = {} # Filled out during parsing below sc_setups = {} # Semicore # Tabulated values of Gamma(m + 1/2) half_integer_gamma = [np.sqrt(np.pi)] for m in range(20): half_integer_gamma.append(half_integer_gamma[m] * (m + 0.5)) class HGHSetupData: """Setup-compatible class implementing HGH pseudopotential. To the PAW code this will appear as a legit PAW setup, but is in fact considerably simpler. In particular, all-electron and pseudo partial waves are all zero, and compensation charges do not depend on environment. A HGH setup has the following form:: ---- \ V = Vlocal + ) | p > h < p | / i ij j ---- ij Vlocal contains a short-range term which is Gaussian-shaped and implemented as vbar of a PAW setup, along with a long-range term which goes like 1/r and is implemented in terms of a compensation charge. The non-local part contains KB projector functions which are essentially similar to those in PAW, while h_ij are constants. h_ij are provided by setting the K_p variable of the normal setup. Most other properties of a PAW setup do not exist for HGH setups, for which reason they are generally set to zero: * All-electron partial waves: always zero * Pseudo partial waves: always zero * Projectors: HGH projectors * Zero potential (vbar): Gaussian times polynomial * Compensation charges: One Gaussian-shaped spherically symmetric charge * All-electron core density: Delta function corresponding to core electron charge * Pseudo core density: always zero * Pseudo valence density: always zero * PS/AE Kinetic energy density: always zero * The mysterious constants K_p of a setup correspond to h_ij. Note that since the pseudo partial waves are set to zero, initialization of atomic orbitals requires loading a custom basis set. Absolute energies become numerically large since no atomic reference is subtracted. """ def __init__(self, hghdata): if isinstance(hghdata, str): symbol = hghdata if symbol.endswith('.sc'): hghdata = sc_setups[symbol[:-3]] else: hghdata = setups[symbol] self.hghdata = hghdata chemsymbol = hghdata.symbol if '.' in chemsymbol: chemsymbol, sc = chemsymbol.split('.') assert sc == 'sc' self.symbol = chemsymbol self.type = hghdata.symbol self.name = 'LDA' self.initialize_setup_data() def initialize_setup_data(self): hghdata = self.hghdata beta = 0.1 N = 450 rgd = AERadialGridDescriptor(beta / N, 1.0 / N, N, default_spline_points=100) #rgd = EquidistantRadialGridDescriptor(0.001, 10000) self.rgd = rgd self.Z = hghdata.Z self.Nc = hghdata.Z - hghdata.Nv self.Nv = hghdata.Nv self.rcgauss = np.sqrt(2.0) * hghdata.rloc threshold = 1e-8 if len(hghdata.c_n) > 0: vloc_g = create_local_shortrange_potential(rgd.r_g, hghdata.rloc, hghdata.c_n) gcutvbar, rcutvbar = self.find_cutoff(rgd.r_g, rgd.dr_g, vloc_g, threshold) self.vbar_g = np.sqrt(4.0 * np.pi) * vloc_g[:gcutvbar] else: rcutvbar = 0.5 gcutvbar = rgd.ceil(rcutvbar) self.vbar_g = np.zeros(gcutvbar) nj = sum([v.nn for v in hghdata.v_l]) if nj == 0: nj = 1 # Code assumes nj > 0 elsewhere, we fill out with zeroes if not hghdata.v_l: # No projectors. But the remaining code assumes that everything # has projectors! We'll just add the zero function then hghdata.v_l = [VNonLocal(0, 0.01, [[0.]])] n_j = [] l_j = [] # j ordering is significant, must be nl rather than ln for n, l in self.hghdata.nl_iter(): n_j.append(n + 1) # Note: actual n must be positive! l_j.append(l) assert nj == len(n_j) self.nj = nj self.l_j = l_j self.l_orb_j = l_j self.n_j = n_j self.rcut_j = [] self.pt_jg = [] for n, l in zip(n_j, l_j): # Note: even pseudopotentials without projectors will get one # projector, but the coefficients h_ij should be zero so it # doesn't matter pt_g = create_hgh_projector(rgd.r_g, l, n, hghdata.v_l[l].r0) norm = np.sqrt(np.dot(rgd.dr_g, pt_g**2 * rgd.r_g**2)) assert np.abs(1 - norm) < 1e-5, str(1 - norm) gcut, rcut = self.find_cutoff(rgd.r_g, rgd.dr_g, pt_g, threshold) if rcut < 0.5: rcut = 0.5 gcut = rgd.ceil(rcut) pt_g = pt_g[:gcut].copy() rcut = max(rcut, 0.5) self.rcut_j.append(rcut) self.pt_jg.append(pt_g) # This is the correct magnitude of the otherwise normalized # compensation charge self.Delta0 = -self.Nv / np.sqrt(4.0 * np.pi) f_ln = self.hghdata.get_occupation_numbers() f_j = [0] * nj for j, (n, l) in enumerate(self.hghdata.nl_iter()): try: f_j[j] = f_ln[l][n] except IndexError: pass self.f_ln = f_ln self.f_j = f_j def find_cutoff(self, r_g, dr_g, f_g, sqrtailnorm=1e-5): g = len(r_g) acc_sqrnorm = 0.0 while acc_sqrnorm <= sqrtailnorm: g -= 1 acc_sqrnorm += (r_g[g] * f_g[g])**2.0 * dr_g[g] if r_g[g] < 0.5: # XXX return g, r_g[g] return g, r_g[g] def expand_hamiltonian_matrix(self): """Construct K_p from individual h_nn for each l.""" ni = sum([2 * l + 1 for l in self.l_j]) H_ii = np.zeros((ni, ni)) # The H_ii used in gpaw is much larger and more general than the one # required for HGH pseudopotentials. This means a lot of the elements # must be assigned the same value. Not a performance issue though, # since these are small matrices M1start = 0 for n1, l1 in self.hghdata.nl_iter(): M1end = M1start + 2 * l1 + 1 M2start = 0 v = self.hghdata.v_l[l1] for n2, l2 in self.hghdata.nl_iter(): M2end = M2start + 2 * l2 + 1 if l1 == l2: h_nn = v.expand_hamiltonian_diagonal() H_mm = np.identity(M2end - M2start) * h_nn[n1, n2] H_ii[M1start:M1end, M2start:M2end] += H_mm M2start = M2end M1start = M1end K_p = pack2(H_ii) return K_p def __str__(self): return "HGHSetupData('%s')" % self.type def __repr__(self): return self.__str__() def print_info(self, text, _setup): self.hghdata.print_info(text) def plot(self): """Plot localized functions of HGH setup.""" import pylab as pl rgd = self.rgd pl.subplot(211) # vbar, compensation charge gcutvbar = len(self.vbar_g) pl.plot(rgd.r_g[:gcutvbar], self.vbar_g, 'r', label='vloc', linewidth=3) rcc, gcc = self.get_compensation_charge_functions() gcc = gcc[0] pl.plot(rcc, gcc * self.Delta0, 'b--', label='Comp charge [arb. unit]', linewidth=3) pl.legend(loc='best') pl.subplot(212) # projectors for j, (n, l, pt_g) in enumerate(zip(self.n_j, self.l_j, self.pt_jg)): label = 'n=%d, l=%d' % (n, l) pl.ylabel('$p_n^l(r)$') ng = len(pt_g) r_g = rgd.r_g[:ng] pl.plot(r_g, pt_g, label=label) pl.legend() def get_projectors(self): # XXX equal-range projectors still required for some reason maxlen = max([len(pt_g) for pt_g in self.pt_jg]) pt_j = [] for l, pt1_g in zip(self.l_j, self.pt_jg): pt2_g = self.rgd.zeros()[:maxlen] pt2_g[:len(pt1_g)] = pt1_g pt_j.append(self.rgd.spline(pt2_g, self.rgd.r_g[maxlen - 1], l)) return pt_j def create_basis_functions(self): from gpaw.pseudopotential import generate_basis_functions return generate_basis_functions(self) def get_compensation_charge_functions(self): alpha = self.rcgauss**-2 rcutgauss = self.rcgauss * 5.0 # smaller values break charge conservation r = np.linspace(0.0, rcutgauss, 100) g = alpha**1.5 * np.exp(-alpha * r**2) * 4.0 / np.sqrt(np.pi) g[-1] = 0.0 return r, [0], [g] def get_local_potential(self): n = len(self.vbar_g) return self.rgd.spline(self.vbar_g, self.rgd.r_g[n - 1]) def build(self, xcfunc, lmax, basis, filter=None): if basis is None: basis = self.create_basis_functions() setup = PseudoPotential(self, basis) setup.fingerprint = hashlib.md5(str(self.hghdata).encode()).hexdigest() return setup def create_local_shortrange_potential(r_g, rloc, c_n): rr_g = r_g / rloc # "Relative r" rr2_g = rr_g**2 rr4_g = rr2_g**2 rr6_g = rr4_g * rr2_g gaussianpart = np.exp(-.5 * rr2_g) polypart = np.zeros(r_g.shape) for c, rrn_g in zip(c_n, [1, rr2_g, rr4_g, rr6_g]): polypart += c * rrn_g vloc_g = gaussianpart * polypart return vloc_g def create_hgh_projector(r_g, l, n, r0): poly_g = r_g**(l + 2 * (n - 1)) gauss_g = np.exp(-.5 * r_g**2 / r0**2) A = r0**(l + (4 * n - 1) / 2.0) assert (4 * n - 1) % 2 == 1 B = half_integer_gamma[l + (4 * n - 1) // 2]**.5 pt_g = 2.**.5 / A / B * poly_g * gauss_g return pt_g # Coefficients determining off-diagonal elements of h_nn for l = 0...2 # given the diagonal elements hcoefs_l = [ [-.5 * (3. / 5.)**.5, .5 * (5. / 21.)**.5, -.5 * (100. / 63.)**.5], [-.5 * (5. / 7.)**.5, 1. / 6. * (35. / 11.)**.5, -1. / 6. * 14. / 11.**.5], [-.5 * (7. / 9.)**.5, .5 * (63. / 143)**.5, -.5 * 18. / 143.**.5] ] class VNonLocal: """Wrapper class for one nonlocal term of an HGH potential.""" def __init__(self, l, r0, h_n): self.l = l self.r0 = r0 h_n = np.array(h_n) nn = len(h_n) self.nn = nn self.h_n = h_n def expand_hamiltonian_diagonal(self): """Construct full atomic Hamiltonian from diagonal elements.""" nn = self.nn h_n = self.h_n h_nn = np.zeros((nn, nn)) for n, h in enumerate(h_n): h_nn[n, n] = h if self.l > 2: #print 'Warning: no diagonal elements for l=%d' % l # Some elements have projectors corresponding to l=3, but # the HGH article only specifies how to calculate the # diagonal elements of the atomic hamiltonian for l = 0, 1, 2 ! return coefs = hcoefs_l[self.l] if nn > 2: h_nn[0, 2] = h_nn[2, 0] = coefs[1] * h_n[2] h_nn[1, 2] = h_nn[2, 1] = coefs[2] * h_n[2] if nn > 1: h_nn[0, 1] = h_nn[1, 0] = coefs[0] * h_n[1] return h_nn def copy(self): return VNonLocal(self.l, self.r0, self.h_n.copy()) def serialize(self): # no spin-orbit part return ' '.join([' ', '%-10s' % self.r0] + ['%10f' % h for h in self.h_n]) class HGHParameterSet: """Wrapper class for HGH-specific data corresponding to one element.""" def __init__(self, symbol, Z, Nv, rloc, c_n, v_l): self.symbol = symbol # Identifier, e.g. 'Na', 'Na.sc', ... self.Z = Z # Actual atomic number self.Nv = Nv # Valence electron count self.rloc = rloc # Characteristic radius of local part self.c_n = np.array(c_n) # Polynomial coefficients for local part self.v_l = list(v_l) # Non-local parts Z, nlfe_j = configurations[self.symbol.split('.')[0]] self.configuration = nlfe_j def __str__(self): strings = ['HGH setup for %s\n' % self.symbol, ' Valence Z=%d, rloc=%.05f\n' % (self.Nv, self.rloc)] if len(self.c_n) > 0: coef_string = ', '.join(['%.05f' % c for c in self.c_n]) else: coef_string = 'zeros' strings.append(' Local part coeffs: %s\n' % coef_string) strings.append(' Projectors:\n') if not self.v_l: strings.append(' None\n') for v in self.v_l: strings.append(' l=%d, rc=%.05f\n' % (v.l, v.r0)) strings.append(' Diagonal coefficients of nonlocal parts:') if not self.v_l: strings.append('\n None\n') for v in self.v_l: strings.append('\n') strings.append(' l=%d: ' % v.l + ', '.join(['%8.05f' % h for h in v.h_n])) return ''.join(strings) def copy(self): other = HGHParameterSet(self.symbol, self.Z, self.Nv, self.rloc, self.c_n, self.v_l) return other def print_info(self, txt): txt(str(self)) txt() def nl_iter(self): for n in range(4): for l, v in enumerate(self.v_l): if n < v.nn: yield n, l def get_occupation_numbers(self): nlfe_j = list(self.configuration) nlfe_j.reverse() f_ln = [[], [], []] # [[s], [p], [d]] # f states will be ignored as the atomic Hamiltonians # of those are, carelessly, not defined in the article. lmax = len(self.v_l) - 1 Nv = 0 # Right. We need to find the occupation numbers of each state and # put them into a nice list of lists f_ln. # # We loop over states starting with the least bound one # (i.e. reversed nlfe_j), adding the occupation numbers of each state # as appropriate. Once we have the right number of electrons, we # end the loop. # # Some states in the standard configuration might # be f-type; these should be skipped (unless the HGH setup actually # has a valence f-state; however as noted above, some of the # parameters are undefined in that case so are ignored anyway). More # generally if for some state l > lmax, # we can skip that state. for n, l, f, e in nlfe_j: if l > lmax: continue Nv += f f_n = f_ln[l] assert f_n == [] or self.symbol.endswith('.sc') f_n.append(f) if Nv >= self.Nv: break assert Nv == self.Nv return f_ln def zeropad(self): """Return a new HGHParameterSet with all arrays zero padded so they have the same (max) length for all such HGH setups. Makes plotting multiple HGH setups easier because they have compatible arrays.""" c_n = np.zeros(4) for n, c in enumerate(self.c_n): c_n[n] = c v_l = [] for l, v in enumerate(self.v_l): h_n = np.zeros(3) h_n[:len(v.h_n)] = list(v.h_n) v2 = VNonLocal(l, v.r0, h_n) v_l.append(v2) for l in range(len(self.v_l), 3): v_l.append(VNonLocal(l, 0.5, np.zeros(3))) copy = HGHParameterSet(self.symbol, self.Z, self.Nv, self.rloc, c_n, v_l) return copy def serialize(self): string1 = '%-5s %-12s %10s ' % (self.symbol, self.Z, self.rloc) string2 = ' '.join(['%.10s' % c for c in self.c_n]) nonlocal_strings = [v.serialize() for v in self.v_l] return '\n'.join([string1 + string2] + nonlocal_strings) def parse_local_part(string): """Create HGHParameterSet object with local part initialized.""" tokens = iter(string.split()) symbol = next(tokens) actual_chemical_symbol = symbol.split('.')[0] Z = atomic_numbers[actual_chemical_symbol] Nv = int(next(tokens)) rloc = float(next(tokens)) c_n = [float(token) for token in tokens] return symbol, Z, Nv, rloc, c_n class HGHBogusNumbersError(ValueError): """Error which is raised when the HGH parameters contain f-type or higher projectors. The HGH article only defines atomic Hamiltonian matrices up to l=2, so these are meaningless.""" pass def parse_hgh_setup(lines): """Initialize HGHParameterSet object from text representation.""" lines = iter(lines) symbol, Z, Nv, rloc, c_n = parse_local_part(next(lines)) def pair_up_nonlocal_lines(lines): yield next(lines), '' while True: yield next(lines), next(lines) v_l = [] for l, (non_local, spinorbit) in enumerate(pair_up_nonlocal_lines(lines)): # we discard the spinorbit 'k_n' data so far nltokens = non_local.split() r0 = float(nltokens[0]) h_n = [float(token) for token in nltokens[1:]] #if h_n[-1] == 0.0: # Only spin-orbit contributes. Discard. # h_n.pop() # Actually the above causes trouble. Probably it messes up state # ordering or something else that shouldn't have any effect. vnl = VNonLocal(l, r0, h_n) v_l.append(vnl) if l > 2: raise HGHBogusNumbersError hgh = HGHParameterSet(symbol, Z, Nv, rloc, c_n, v_l) return hgh def str2hgh(string): return parse_hgh_setup(string.splitlines()) def hgh2str(hgh): return hgh.serialize() def parse_setups(lines): """Read HGH data from file.""" setups = {} entry_lines = [i for i in range(len(lines)) if lines[i][0].isalpha()] lines_by_element = [lines[entry_lines[i]:entry_lines[i + 1]] for i in range(len(entry_lines) - 1)] lines_by_element.append(lines[entry_lines[-1]:]) for elines in lines_by_element: try: hgh = parse_hgh_setup(elines) except HGHBogusNumbersError: continue assert hgh.symbol not in setups setups[hgh.symbol] = hgh return setups def plot(symbol, extension=None): import pylab as pl try: s = HGHSetupData(symbol) except IndexError: print('Nooooo') return s.plot() if extension is not None: pl.savefig('hgh.%s.%s' % (symbol, extension)) def plot_many(*symbols): import pylab as pl if not symbols: symbols = setups.keys() + [key + '.sc' for key in sc_setups.keys()] for symbol in symbols: pl.figure(1) plot(symbol, extension='png') pl.clf() def parse_default_setups(): from gpaw.hgh_parameters import parameters lines = parameters.splitlines() setups0 = parse_setups(lines) for key, value in setups0.items(): if key.endswith('.sc'): sym, sc = key.split('.') sc_setups[sym] = value else: setups[key] = value parse_default_setups() gpaw-0.11.0.13004/gpaw/solvation/0000775000175000017500000000000012553644063016427 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/solvation/poisson.py0000664000175000017500000002645012553643471020504 0ustar jensjjensj00000000000000from gpaw.poisson import PoissonSolver from gpaw.transformers import Transformer from gpaw.fd_operators import Laplace, Gradient from gpaw.wfd_operators import WeightedFDOperator from gpaw.utilities.gauss import Gaussian from gpaw.utilities import erf import warnings import numpy as np class SolvationPoissonSolver(PoissonSolver): """Base class for Poisson solvers with spatially varying dielectric. The Poisson equation div(epsilon(r) grad phi(r)) = -4 pi rho(r) is solved. """ def __init__(self, nn=3, relax='J', eps=2e-10, maxiter=1000, remove_moment=None, use_charge_center=True): if remove_moment is not None: raise NotImplementedError( 'Removing arbitrary multipole moments ' 'is not implemented for SolvationPoissonSolver!' ) PoissonSolver.__init__(self, nn, relax, eps, maxiter, remove_moment, use_charge_center=use_charge_center) def set_dielectric(self, dielectric): """Set the dielectric. Arguments: dielectric -- A Dielectric instance. """ self.dielectric = dielectric def load_gauss(self, center=None): """Load compensating charge distribution for charged systems. See Appendix B of A. Held and M. Walter, J. Chem. Phys. 141, 174108 (2014). """ # XXX Check if update is needed (dielectric changed)? epsr, dx_epsr, dy_epsr, dz_epsr = self.dielectric.eps_gradeps gauss = Gaussian(self.gd, center=center) rho_g = gauss.get_gauss(0) phi_g = gauss.get_gauss_pot(0) x, y, z = gauss.xyz fac = 2. * np.sqrt(gauss.a) * np.exp(-gauss.a * gauss.r2) fac /= np.sqrt(np.pi) * gauss.r2 fac -= erf(np.sqrt(gauss.a) * gauss.r) / (gauss.r2 * gauss.r) fac *= 2.0 * 1.7724538509055159 dx_phi_g = fac * x dy_phi_g = fac * y dz_phi_g = fac * z sp = dx_phi_g * dx_epsr + dy_phi_g * dy_epsr + dz_phi_g * dz_epsr rho = epsr * rho_g - 1. / (4. * np.pi) * sp invnorm = np.sqrt(4. * np.pi) / self.gd.integrate(rho) self.phi_gauss = phi_g * invnorm self.rho_gauss = rho * invnorm class WeightedFDPoissonSolver(SolvationPoissonSolver): """Weighted finite difference Poisson solver with dielectric. Following V. M. Sanchez, M. Sued and D. A. Scherlis, J. Chem. Phys. 131, 174108 (2009). """ def solve(self, phi, rho, charge=None, eps=None, maxcharge=1e-6, zero_initial_phi=False): if self.gd.pbc_c.all(): actual_charge = self.gd.integrate(rho) if abs(actual_charge) > maxcharge: raise NotImplementedError( 'charged periodic systems are not implemented' ) self.restrict_op_weights() ret = PoissonSolver.solve(self, phi, rho, charge, eps, maxcharge, zero_initial_phi) return ret def restrict_op_weights(self): """Restric operator weights to coarse grids.""" weights = [self.dielectric.eps_gradeps] + self.op_coarse_weights for i, res in enumerate(self.restrictors): for j in range(4): res.apply(weights[i][j], weights[i + 1][j]) self.step = 0.66666666 / self.operators[0].get_diagonal_element() def set_grid_descriptor(self, gd): self.gd = gd self.gds = [gd] self.dv = gd.dv gd = self.gd self.B = None self.interpolators = [] self.restrictors = [] self.operators = [] level = 0 self.presmooths = [2] self.postsmooths = [1] self.weights = [2. / 3.] while level < 8: try: gd2 = gd.coarsen() except ValueError: break self.gds.append(gd2) self.interpolators.append(Transformer(gd2, gd)) self.restrictors.append(Transformer(gd, gd2)) self.presmooths.append(4) self.postsmooths.append(4) self.weights.append(1.0) level += 1 gd = gd2 self.levels = level def get_description(self): if len(self.operators) == 0: return 'uninitialized WeightedFDPoissonSolver' else: description = SolvationPoissonSolver.get_description(self) return description.replace( 'solver with', 'weighted FD solver with dielectric and' ) def initialize(self, load_gauss=False): self.presmooths[self.levels] = 8 self.postsmooths[self.levels] = 8 self.phis = [None] + [gd.zeros() for gd in self.gds[1:]] self.residuals = [gd.zeros() for gd in self.gds] self.rhos = [gd.zeros() for gd in self.gds] self.op_coarse_weights = [ [g.empty() for g in (gd, ) * 4] for gd in self.gds[1:] ] scale = -0.25 / np.pi for i, gd in enumerate(self.gds): if i == 0: nn = self.nn weights = self.dielectric.eps_gradeps else: nn = 1 weights = self.op_coarse_weights[i - 1] operators = [Laplace(gd, scale, nn)] + \ [Gradient(gd, j, scale, nn) for j in (0, 1, 2)] self.operators.append(WeightedFDOperator(weights, operators)) if load_gauss: self.load_gauss() class PolarizationPoissonSolver(SolvationPoissonSolver): """Poisson solver with dielectric. Calculates the polarization charges first using only the vacuum poisson equation, then solves the vacuum equation with polarization charges. Warning: Not intended for production use, as it is not exact enough, since the electric field is not exact enough! """ def __init__(self, nn=3, relax='J', eps=2e-10, maxiter=1000, remove_moment=None, use_charge_center=True): polarization_warning = UserWarning( ( 'PolarizationPoissonSolver is not accurate enough' ' and therefore not recommended for production code!' ) ) warnings.warn(polarization_warning) SolvationPoissonSolver.__init__( self, nn, relax, eps, maxiter, remove_moment, use_charge_center=use_charge_center ) self.phi_tilde = None def get_description(self): if len(self.operators) == 0: return 'uninitialized PolarizationPoissonSolver' else: description = SolvationPoissonSolver.get_description(self) return description.replace( 'solver with', 'polarization solver with dielectric and' ) def solve(self, phi, rho, charge=None, eps=None, maxcharge=1e-6, zero_initial_phi=False): if self.phi_tilde is None: self.phi_tilde = self.gd.zeros() phi_tilde = self.phi_tilde niter_tilde = PoissonSolver.solve( self, phi_tilde, rho, None, self.eps, maxcharge, False ) epsr, dx_epsr, dy_epsr, dz_epsr = self.dielectric.eps_gradeps dx_phi_tilde = self.gd.empty() dy_phi_tilde = self.gd.empty() dz_phi_tilde = self.gd.empty() Gradient(self.gd, 0, 1.0, self.nn).apply(phi_tilde, dx_phi_tilde) Gradient(self.gd, 1, 1.0, self.nn).apply(phi_tilde, dy_phi_tilde) Gradient(self.gd, 2, 1.0, self.nn).apply(phi_tilde, dz_phi_tilde) scalar_product = ( dx_epsr * dx_phi_tilde + dy_epsr * dy_phi_tilde + dz_epsr * dz_phi_tilde ) rho_and_pol = ( rho / epsr + scalar_product / (4. * np.pi * epsr ** 2) ) niter = PoissonSolver.solve( self, phi, rho_and_pol, None, eps, maxcharge, zero_initial_phi ) return niter_tilde + niter def load_gauss(self, center=None): return PoissonSolver.load_gauss(self, center=center) class ADM12PoissonSolver(SolvationPoissonSolver): """Poisson solver with dielectric. Following O. Andreussi, I. Dabo, and N. Marzari, J. Chem. Phys. 136, 064102 (2012). Warning: Not intended for production use, as it is not tested thouroughly! XXX TODO : * Correction for charged systems??? * Check: Can the polarization charge introduce a monopole? * Convergence problems depending on eta. Apparently this method works best with FFT as in the original Paper. * Optimize numerics. """ def __init__(self, nn=3, relax='J', eps=2e-10, maxiter=1000, remove_moment=None, eta=.6, use_charge_center=True): """Constructor for ADM12PoissonSolver. Additional arguments not present in SolvationPoissonSolver: eta -- linear mixing parameter """ adm12_warning = UserWarning( ( 'ADM12PoissonSolver is not tested thoroughly' ' and therefore not recommended for production code!' ) ) warnings.warn(adm12_warning) self.eta = eta SolvationPoissonSolver.__init__( self, nn, relax, eps, maxiter, remove_moment, use_charge_center=use_charge_center ) def set_grid_descriptor(self, gd): SolvationPoissonSolver.set_grid_descriptor(self, gd) self.gradx = Gradient(gd, 0, 1.0, self.nn) self.grady = Gradient(gd, 1, 1.0, self.nn) self.gradz = Gradient(gd, 2, 1.0, self.nn) def get_description(self): if len(self.operators) == 0: return 'uninitialized ADM12PoissonSolver' else: description = SolvationPoissonSolver.get_description(self) return description.replace( 'solver with', 'ADM12 solver with dielectric and' ) def initialize(self, load_gauss=False): self.rho_iter = self.gd.zeros() self.d_phi = self.gd.empty() return SolvationPoissonSolver.initialize(self, load_gauss) def solve(self, phi, rho, charge=None, eps=None, maxcharge=1e-6, zero_initial_phi=False): if self.gd.pbc_c.all(): actual_charge = self.gd.integrate(rho) if abs(actual_charge) > maxcharge: raise NotImplementedError( 'charged periodic systems are not implemented' ) return PoissonSolver.solve( self, phi, rho, charge, eps, maxcharge, zero_initial_phi ) def solve_neutral(self, phi, rho, eps=2e-10): self.rho = rho return SolvationPoissonSolver.solve_neutral(self, phi, rho, eps) def iterate2(self, step, level=0): if level == 0: epsr, dx_epsr, dy_epsr, dz_epsr = self.dielectric.eps_gradeps self.gradx.apply(self.phis[0], self.d_phi) sp = dx_epsr * self.d_phi self.grady.apply(self.phis[0], self.d_phi) sp += dy_epsr * self.d_phi self.gradz.apply(self.phis[0], self.d_phi) sp += dz_epsr * self.d_phi self.rho_iter = self.eta / (4. * np.pi) * sp + \ (1. - self.eta) * self.rho_iter self.rhos[0][:] = (self.rho_iter + self.rho) / epsr return SolvationPoissonSolver.iterate2(self, step, level) gpaw-0.11.0.13004/gpaw/solvation/hamiltonian.py0000664000175000017500000001702412553643471021312 0ustar jensjjensj00000000000000from gpaw.hamiltonian import RealSpaceHamiltonian from gpaw.solvation.poisson import WeightedFDPoissonSolver from gpaw.fd_operators import Gradient import numpy as np class SolvationRealSpaceHamiltonian(RealSpaceHamiltonian): """Realspace Hamiltonian with continuum solvent model. See also Section III of A. Held and M. Walter, J. Chem. Phys. 141, 174108 (2014). """ def __init__( self, # solvation related arguments: cavity, dielectric, interactions, # RealSpaceHamiltonian arguments: gd, finegd, nspins, setups, timer, xc, world, kptband_comm, vext=None, collinear=True, psolver=None, stencil=3 ): """Constructor of SolvationRealSpaceHamiltonian class. Additional arguments not present in RealSpaceHamiltonian: cavity -- A Cavity instance. dielectric -- A Dielectric instance. interactions -- A list of Interaction instances. """ self.cavity = cavity self.dielectric = dielectric self.interactions = interactions cavity.set_grid_descriptor(finegd) dielectric.set_grid_descriptor(finegd) for ia in interactions: ia.set_grid_descriptor(finegd) if psolver is None: psolver = WeightedFDPoissonSolver() psolver.set_dielectric(self.dielectric) self.gradient = None RealSpaceHamiltonian.__init__( self, gd, finegd, nspins, setups, timer, xc, world, kptband_comm, vext, collinear, psolver, stencil ) for ia in interactions: setattr(self, 'E_' + ia.subscript, None) self.new_atoms = None self.vt_ia_g = None def estimate_memory(self, mem): RealSpaceHamiltonian.estimate_memory(self, mem) solvation = mem.subnode('Solvation') for name, obj in [ ('Cavity', self.cavity), ('Dielectric', self.dielectric), ] + [('Interaction: ' + ia.subscript, ia) for ia in self.interactions]: obj.estimate_memory(solvation.subnode(name)) def update_atoms(self, atoms): self.new_atoms = atoms.copy() def initialize(self): self.gradient = [ Gradient(self.finegd, i, 1.0, self.poisson.nn) for i in (0, 1, 2) ] self.vt_ia_g = self.finegd.zeros() self.cavity.allocate() self.dielectric.allocate() for ia in self.interactions: ia.allocate() RealSpaceHamiltonian.initialize(self) def update(self, density): self.timer.start('Hamiltonian') if self.vt_sg is None: self.timer.start('Initialize Hamiltonian') self.initialize() self.timer.stop('Initialize Hamiltonian') cavity_changed = self.cavity.update(self.new_atoms, density) if cavity_changed: self.cavity.update_vol_surf() self.dielectric.update(self.cavity) Epot, Ebar, Eext, Exc = self.update_pseudo_potential(density) ia_changed = [ ia.update( self.new_atoms, density, self.cavity if cavity_changed else None ) for ia in self.interactions ] if np.any(ia_changed): self.vt_ia_g.fill(.0) for ia in self.interactions: if ia.depends_on_el_density: self.vt_ia_g += ia.delta_E_delta_n_g if self.cavity.depends_on_el_density: self.vt_ia_g += (ia.delta_E_delta_g_g * self.cavity.del_g_del_n_g) if len(self.interactions) > 0: for vt_g in self.vt_sg[:self.nspins]: vt_g += self.vt_ia_g Eias = [ia.E for ia in self.interactions] Ekin = self.calculate_kinetic_energy(density) W_aL = self.calculate_atomic_hamiltonians(density) Ekin, Epot, Ebar, Eext, Exc = self.update_corrections( density, Ekin, Epot, Ebar, Eext, Exc, W_aL ) energies = np.array([Ekin, Epot, Ebar, Eext, Exc] + Eias) self.timer.start('Communicate energies') self.gd.comm.sum(energies) # Make sure that all CPUs have the same energies self.world.broadcast(energies, 0) self.cavity.communicate_vol_surf(self.world) self.timer.stop('Communicate energies') (self.Ekin0, self.Epot, self.Ebar, self.Eext, self.Exc) = energies[:5] for E, ia in zip(energies[5:], self.interactions): setattr(self, 'E_' + ia.subscript, E) # self.Exc += self.Enlxc # self.Ekin0 += self.Enlkin self.new_atoms = None self.timer.stop('Hamiltonian') def update_pseudo_potential(self, density): ret = RealSpaceHamiltonian.update_pseudo_potential(self, density) if not self.cavity.depends_on_el_density: return ret del_g_del_n_g = self.cavity.del_g_del_n_g # XXX optimize numerics del_eps_del_g_g = self.dielectric.del_eps_del_g_g Veps = -1. / (8. * np.pi) * del_eps_del_g_g * del_g_del_n_g Veps *= self.grad_squared(self.vHt_g) for vt_g in self.vt_sg[:self.nspins]: vt_g += Veps return ret def calculate_forces(self, dens, F_av): # XXX reorganize self.el_force_correction(dens, F_av) for ia in self.interactions: if self.cavity.depends_on_atomic_positions: for a, F_v in enumerate(F_av): del_g_del_r_vg = self.cavity.get_del_r_vg(a, dens) for v in (0, 1, 2): F_v[v] -= self.finegd.integrate( ia.delta_E_delta_g_g * del_g_del_r_vg[v], global_integral=False ) if ia.depends_on_atomic_positions: for a, F_v in enumerate(F_av): del_E_del_r_vg = ia.get_del_r_vg(a, dens) for v in (0, 1, 2): F_v[v] -= self.finegd.integrate( del_E_del_r_vg[v], global_integral=False ) return RealSpaceHamiltonian.calculate_forces( self, dens, F_av ) def el_force_correction(self, dens, F_av): if not self.cavity.depends_on_atomic_positions: return del_eps_del_g_g = self.dielectric.del_eps_del_g_g fixed = 1. / (8. * np.pi) * del_eps_del_g_g * \ self.grad_squared(self.vHt_g) # XXX grad_vHt_g inexact in bmgs for a, F_v in enumerate(F_av): del_g_del_r_vg = self.cavity.get_del_r_vg(a, dens) for v in (0, 1, 2): F_v[v] += self.finegd.integrate( fixed * del_g_del_r_vg[v], global_integral=False ) def get_energy(self, occupations): self.Ekin = self.Ekin0 + occupations.e_band self.S = occupations.e_entropy self.Eel = ( self.Ekin + self.Epot + self.Eext + self.Ebar + self.Exc - self.S ) Etot = self.Eel for ia in self.interactions: Etot += getattr(self, 'E_' + ia.subscript) self.Etot = Etot return self.Etot def grad_squared(self, x): # XXX ugly gs = np.empty_like(x) tmp = np.empty_like(x) self.gradient[0].apply(x, gs) np.square(gs, gs) self.gradient[1].apply(x, tmp) np.square(tmp, tmp) gs += tmp self.gradient[2].apply(x, tmp) np.square(tmp, tmp) gs += tmp return gs gpaw-0.11.0.13004/gpaw/solvation/dielectric.py0000664000175000017500000000754412553643471021124 0ustar jensjjensj00000000000000from gpaw.fd_operators import Gradient from gpaw.solvation.gridmem import NeedsGD import numpy as np class Dielectric(NeedsGD): """Class representing a spatially varying permittivity. Attributes: eps_gradeps -- List [eps_g, dxeps_g, dyeps_g, dzeps_g] with eps_g: permittivity on the fine grid dieps_g: gradient of eps_g. del_eps_del_g_g -- Partial derivative with respect to the cavity. (A point-wise dependence on the cavity is assumed). """ def __init__(self, epsinf): """Constructor for the Dielectric class. Arguments: epsinf -- Static dielectric constant at infinite distance from the solute. """ NeedsGD.__init__(self) self.epsinf = float(epsinf) self.eps_gradeps = None # eps_g, dxeps_g, dyeps_g, dzeps_g self.del_eps_del_g_g = None def estimate_memory(self, mem): nbytes = self.gd.bytecount() mem.subnode('Permittivity', nbytes) mem.subnode('Permittivity Gradient', 3 * nbytes) mem.subnode('Permittivity Derivative', nbytes) def allocate(self): NeedsGD.allocate(self) self.eps_gradeps = [] eps_g = self.gd.empty() eps_g.fill(1.0) self.eps_gradeps.append(eps_g) self.eps_gradeps.extend([gd.zeros() for gd in (self.gd, ) * 3]) self.del_eps_del_g_g = self.gd.empty() def update(self, cavity): """Calculate eps_gradeps and del_eps_del_g_g from the cavity.""" raise NotImplementedError def print_parameters(self, text): """Print parameters using text function.""" text('epsilon_inf: %s' % (self.epsinf, )) class FDGradientDielectric(Dielectric): """Dielectric with finite difference gradient.""" def __init__(self, epsinf, nn=3): """Constructor for the FDGradientDielectric class. Additional arguments not present in the base Dielectric class: nn -- Stencil size for finite difference gradient. """ Dielectric.__init__(self, epsinf) self.nn = nn self.eps_hack_g = None self.gradient = None def estimate_memory(self, mem): Dielectric.estimate_memory(self, mem) mem.subnode('Boundary Correction', self.gd.bytecount()) def allocate(self): Dielectric.allocate(self) self.eps_hack_g = self.gd.empty() self.gradient = [ Gradient(self.gd, i, 1.0, self.nn) for i in (0, 1, 2) ] def update_gradient(self): """Update the gradient. Usage note: Call this method at the end of the update method of a subclass. """ # zero on boundary, since bmgs supports only zero or periodic BC np.subtract(self.eps_gradeps[0], self.epsinf, out=self.eps_hack_g) for i in (0, 1, 2): self.gradient[i].apply(self.eps_hack_g, self.eps_gradeps[i + 1]) class LinearDielectric(FDGradientDielectric): """Dielectric depending (affine) linearly on the cavity. See also A. Held and M. Walter, J. Chem. Phys. 141, 174108 (2014). """ def allocate(self): FDGradientDielectric.allocate(self) self.del_eps_del_g_g = self.epsinf - 1. # frees array def update(self, cavity): np.multiply(cavity.g_g, self.epsinf - 1., self.eps_gradeps[0]) self.eps_gradeps[0] += 1. self.update_gradient() class CMDielectric(FDGradientDielectric): """Clausius-Mossotti like dielectric. Untested, use at own risk! """ def update(self, cavity): ei = self.epsinf t = 1. - cavity.g_g self.eps_gradeps[0][:] = (3. * (ei + 2.)) / ((ei - 1.) * t + 3.) - 2. self.del_eps_del_g_g[:] = ( (3. * (ei - 1.) * (ei + 2.)) / ((ei - 1.) * t + 3.) ** 2 ) self.update_gradient() gpaw-0.11.0.13004/gpaw/solvation/cavity.py0000664000175000017500000007455512553643471020322 0ustar jensjjensj00000000000000from ase.units import kB, Hartree, Bohr from gpaw.solvation.gridmem import NeedsGD from gpaw.fd_operators import Gradient import numpy as np def get_pbc_positions(atoms, r_max): """Return dict mapping atom index to positions in Bohr. With periodic boundary conditions, it also includes neighbouring cells up to a distance of r_max (in Bohr). """ # code snippet taken from ase/calculators/vdwcorrection.py pbc_c = atoms.get_pbc() cell_cv = atoms.get_cell() / Bohr Rcell_c = np.sqrt(np.sum(cell_cv ** 2, axis=1)) ncells_c = np.ceil(np.where(pbc_c, 1. + r_max / Rcell_c, 1)).astype(int) pos_aav = {} # loop over all atoms in the cell (and neighbour cells for PBC) for index1, atom in enumerate(atoms): pos = atom.position / Bohr pos_aav[index1] = np.empty((np.prod(ncells_c * 2 - 1), 3)) # loops over neighbour cells index2 = 0 for ix in range(-ncells_c[0] + 1, ncells_c[0]): for iy in range(-ncells_c[1] + 1, ncells_c[1]): for iz in range(-ncells_c[2] + 1, ncells_c[2]): i_c = np.array([ix, iy, iz]) pos_aav[index1][index2, :] = pos + np.dot(i_c, cell_cv) index2 += 1 return pos_aav def divide_silently(x, y): """Divide numpy arrays x / y ignoring all floating point errors. Use with caution! """ old_err = np.seterr(all='ignore') result = x / y np.seterr(**old_err) return result class Cavity(NeedsGD): """Base class for representing a cavity in the solvent. Attributes: g_g -- The cavity on the fine grid. It varies from zero at the solute location to one in the bulk solvent. del_g_del_n_g -- The partial derivative of the cavity with respect to the electron density on the fine grid. V -- global Volume in Bohr ** 3 or None A -- global Area in Bohr ** 2 or None """ def __init__(self, surface_calculator=None, volume_calculator=None): """Constructor for the Cavity class. Arguments: surface_calculator -- A SurfaceCalculator instance or None volume_calculator -- A VolumeCalculator instance or None """ NeedsGD.__init__(self) self.g_g = None self.del_g_del_n_g = None self.surface_calculator = surface_calculator self.volume_calculator = volume_calculator self.V = None # global Volume self.A = None # global Surface def estimate_memory(self, mem): ngrids = 1 + self.depends_on_el_density mem.subnode('Distribution Function', ngrids * self.gd.bytecount()) if self.surface_calculator is not None: self.surface_calculator.estimate_memory( mem.subnode('Surface Calculator') ) if self.volume_calculator is not None: self.volume_calculator.estimate_memory( mem.subnode('Volume Calculator') ) def update(self, atoms, density): """Update the cavity. atoms are None, iff they have not changed. Return whether the cavity has changed. """ raise NotImplementedError() def update_vol_surf(self): """Update volume and surface.""" if self.surface_calculator is not None: self.surface_calculator.update(self) if self.volume_calculator is not None: self.volume_calculator.update(self) def communicate_vol_surf(self, world): """Communicate global volume and surface.""" if self.surface_calculator is not None: A = np.array([self.surface_calculator.A]) self.gd.comm.sum(A) world.broadcast(A, 0) self.A = A[0] else: self.A = None if self.volume_calculator is not None: V = np.array([self.volume_calculator.V]) self.gd.comm.sum(V) world.broadcast(V, 0) self.V = V[0] else: self.V = None def allocate(self): NeedsGD.allocate(self) self.g_g = self.gd.empty() if self.depends_on_el_density: self.del_g_del_n_g = self.gd.empty() if self.surface_calculator is not None: self.surface_calculator.allocate() if self.volume_calculator is not None: self.volume_calculator.allocate() def set_grid_descriptor(self, gd): NeedsGD.set_grid_descriptor(self, gd) if self.surface_calculator is not None: self.surface_calculator.set_grid_descriptor(gd) if self.volume_calculator is not None: self.volume_calculator.set_grid_descriptor(gd) def get_del_r_vg(self, atom_index, density): """Return spatial derivatives with respect to atomic position.""" raise NotImplementedError() @property def depends_on_el_density(self): """Return whether the cavity depends on the electron density.""" raise NotImplementedError() @property def depends_on_atomic_positions(self): """Return whether the cavity depends explicitly on atomic positions.""" raise NotImplementedError() def print_parameters(self, text): """Print parameters using text function.""" typ = self.surface_calculator and self.surface_calculator.__class__ text('surface calculator: %s' % (typ, )) if self.surface_calculator is not None: self.surface_calculator.print_parameters(text) text() typ = self.volume_calculator and self.volume_calculator.__class__ text('volume calculator: %s' % (typ, )) if self.volume_calculator is not None: self.volume_calculator.print_parameters(text) class EffectivePotentialCavity(Cavity): """Cavity built from effective potential and Boltzmann distribution. See also A. Held and M. Walter, J. Chem. Phys. 141, 174108 (2014). """ def __init__( self, effective_potential, temperature, surface_calculator=None, volume_calculator=None ): """Constructor for the EffectivePotentialCavity class. Additional arguments not present in base Cavity class: effective_potential -- A Potential instance. temperature -- Temperature for the Boltzmann distribution in Kelvin. """ Cavity.__init__(self, surface_calculator, volume_calculator) self.effective_potential = effective_potential self.temperature = float(temperature) self.minus_beta = -1. / (kB * temperature / Hartree) def estimate_memory(self, mem): Cavity.estimate_memory(self, mem) self.effective_potential.estimate_memory( mem.subnode('Effective Potential') ) def set_grid_descriptor(self, gd): Cavity.set_grid_descriptor(self, gd) self.effective_potential.set_grid_descriptor(gd) def allocate(self): Cavity.allocate(self) self.effective_potential.allocate() def update(self, atoms, density): if not self.effective_potential.update(atoms, density): return False u_g = self.effective_potential.u_g np.exp(u_g * self.minus_beta, out=self.g_g) if self.depends_on_el_density: self.del_g_del_n_g.fill(self.minus_beta) self.del_g_del_n_g *= self.g_g self.del_g_del_n_g *= self.effective_potential.del_u_del_n_g return True def get_del_r_vg(self, atom_index, density): u = self.effective_potential del_u_del_r_vg = u.get_del_r_vg(atom_index, density) # asserts lim_(||r - r_atom|| -> 0) dg/du * du/dr_atom = 0 del_u_del_r_vg[np.isnan(del_u_del_r_vg)] = .0 return self.minus_beta * self.g_g * del_u_del_r_vg @property def depends_on_el_density(self): return self.effective_potential.depends_on_el_density @property def depends_on_atomic_positions(self): return self.effective_potential.depends_on_atomic_positions def print_parameters(self, text): text('effective potential: %s' % (self.effective_potential.__class__)) self.effective_potential.print_parameters(text) text() Cavity.print_parameters(self, text) # --- BEGIN GradientSurface API --- def get_inner_function(self): return np.minimum(self.effective_potential.u_g, 1e20) def get_inner_function_boundary_value(self): if hasattr(self.effective_potential, 'grad_u_vg'): raise NotImplementedError else: return .0 def get_grad_inner(self): if hasattr(self.effective_potential, 'grad_u_vg'): return self.effective_potential.grad_u_vg else: raise NotImplementedError def get_del_outer_del_inner(self): return self.minus_beta * self.g_g # --- END GradientSurface API --- class Potential(NeedsGD): """Base class for describing an effective potential. Attributes: u_g -- The potential on the fine grid in Hartree. del_u_del_n_g -- Partial derivative with respect to the electron density. """ def __init__(self): NeedsGD.__init__(self) self.u_g = None self.del_u_del_n_g = None @property def depends_on_el_density(self): """Return whether the cavity depends on the electron density.""" raise NotImplementedError() @property def depends_on_atomic_positions(self): """returns whether the cavity depends explicitly on atomic positions""" raise NotImplementedError() def estimate_memory(self, mem): ngrids = 1 + self.depends_on_el_density mem.subnode('Potential', ngrids * self.gd.bytecount()) def allocate(self): NeedsGD.allocate(self) self.u_g = self.gd.empty() if self.depends_on_el_density: self.del_u_del_n_g = self.gd.empty() def update(self, atoms, density): """Update the potential. atoms are None, iff they have not changed. Return whether the potential has changed. """ raise NotImplementedError() def get_del_r_vg(self, atom_index, density): """Return spatial derivatives with respect to atomic position.""" raise NotImplementedError() def print_parameters(self, text): pass class Power12Potential(Potential): """Inverse power law potential. An 1 / r ** 12 repulsive potential taking the value u0 at the atomic radius. See also A. Held and M. Walter, J. Chem. Phys. 141, 174108 (2014). """ depends_on_el_density = False depends_on_atomic_positions = True def __init__(self, atomic_radii, u0, pbc_cutoff=1e-6): """Constructor for the Power12Potential class. Arguments: atomic_radii -- Callable mapping an ase.Atoms object to an iterable of atomic radii in Angstroms. u0 -- Strength of the potential at the atomic radius in eV. pbc_cutoff -- Cutoff in eV for including neighbor cells in a calculation with periodic boundary conditions. """ Potential.__init__(self) self.atomic_radii = atomic_radii self.u0 = float(u0) self.pbc_cutoff = float(pbc_cutoff) self.r12_a = None self.r_vg = None self.pos_aav = None self.del_u_del_r_vg = None self.atomic_radii_output = None self.symbols = None self.grad_u_vg = None def estimate_memory(self, mem): Potential.estimate_memory(self, mem) nbytes = self.gd.bytecount() mem.subnode('Coordinates', 3 * nbytes) mem.subnode('Atomic Position Derivative', 3 * nbytes) mem.subnode('Gradient', 3 * nbytes) def allocate(self): Potential.allocate(self) self.r_vg = self.gd.get_grid_point_coordinates() self.del_u_del_r_vg = self.gd.empty(3) self.grad_u_vg = self.gd.empty(3) def update(self, atoms, density): if atoms is None: return False self.atomic_radii_output = np.array(self.atomic_radii(atoms)) self.symbols = atoms.get_chemical_symbols() self.r12_a = (self.atomic_radii_output / Bohr) ** 12 r_cutoff = (self.r12_a.max() * self.u0 / self.pbc_cutoff) ** (1. / 12.) self.pos_aav = get_pbc_positions(atoms, r_cutoff) self.u_g.fill(.0) self.grad_u_vg.fill(.0) na = np.newaxis for index, pos_av in self.pos_aav.items(): r12 = self.r12_a[index] for pos_v in pos_av: origin_vg = pos_v[:, na, na, na] r_diff_vg = self.r_vg - origin_vg r_diff2_g = (r_diff_vg ** 2).sum(0) r12_g = r_diff2_g ** 6 r14_g = r12_g * r_diff2_g self.u_g += divide_silently(r12, r12_g) self.grad_u_vg += divide_silently(r12 * r_diff_vg, r14_g) self.u_g *= self.u0 / Hartree # np.exp(-np.inf) = .0 self.u_g[np.isnan(self.u_g)] = np.inf self.grad_u_vg *= -12. * self.u0 / Hartree # mask points where the limit of all later # calculations is zero anyways self.grad_u_vg[...] = np.nan_to_num(self.grad_u_vg) # avoid overflow in norm calculation: self.grad_u_vg[self.grad_u_vg < -1e20] = -1e20 self.grad_u_vg[self.grad_u_vg > 1e20] = 1e20 return True def get_del_r_vg(self, atom_index, density): u0 = self.u0 / Hartree r12 = self.r12_a[atom_index] na = np.newaxis self.del_u_del_r_vg.fill(.0) for pos_v in self.pos_aav[atom_index]: origin_vg = pos_v[:, na, na, na] diff_vg = self.r_vg - origin_vg r14_g = np.sum(diff_vg ** 2, axis=0) ** 7 self.del_u_del_r_vg += divide_silently(diff_vg, r14_g) self.del_u_del_r_vg *= (12. * u0 * r12) return self.del_u_del_r_vg def print_parameters(self, text): if self.symbols is None: text('atomic_radii: not initialized (dry run)') else: text('atomic_radii:') for a, (s, r) in enumerate( zip(self.symbols, self.atomic_radii_output) ): text('%3d %-2s %10.5f' % (a, s, r)) text('u0: %s' % (self.u0, )) text('pbc_cutoff: %s' % (self.pbc_cutoff, )) Potential.print_parameters(self, text) class SmoothStepCavity(Cavity): """Base class for cavities based on a smooth step function and a density. Attributes: del_g_del_rho_g -- Partial derivative with respect to the density. """ def __init__( self, density, surface_calculator=None, volume_calculator=None ): """Constructor for the SmoothStepCavity class. Additional arguments not present in the base Cavity class: density -- A Density instance """ Cavity.__init__(self, surface_calculator, volume_calculator) self.del_g_del_rho_g = None self.density = density @property def depends_on_el_density(self): return self.density.depends_on_el_density @property def depends_on_atomic_positions(self): return self.density.depends_on_atomic_positions def set_grid_descriptor(self, gd): Cavity.set_grid_descriptor(self, gd) self.density.set_grid_descriptor(gd) def estimate_memory(self, mem): Cavity.estimate_memory(self, mem) mem.subnode('Cavity Derivative', self.gd.bytecount()) self.density.estimate_memory(mem.subnode('Density')) def allocate(self): Cavity.allocate(self) self.del_g_del_rho_g = self.gd.empty() self.density.allocate() def update(self, atoms, density): if not self.density.update(atoms, density): return False self.update_smooth_step(self.density.rho_g) if self.depends_on_el_density: np.multiply( self.del_g_del_rho_g, self.density.del_rho_del_n_g, self.del_g_del_n_g ) return True def update_smooth_step(self, rho_g): """Calculate self.g_g and self.del_g_del_rho_g.""" raise NotImplementedError() def get_del_r_vg(self, atom_index, density): return self.del_g_del_rho_g * self.density.get_del_r_vg( atom_index, density ) def print_parameters(self, text): text('density: %s' % (self.density.__class__)) self.density.print_parameters(text) text() Cavity.print_parameters(self, text) # --- BEGIN GradientSurface API --- def get_inner_function(self): return self.density.rho_g def get_inner_function_boundary_value(self): return .0 def get_grad_inner(self): raise NotImplementedError def get_del_outer_del_inner(self): return self.del_g_del_rho_g # --- END GradientSurface API --- class Density(NeedsGD): """Class representing a density for the use with a SmoothStepCavity. Attributes: rho_g -- The density on the fine grid in 1 / Bohr ** 3. del_rho_del_n_g -- Partial derivative with respect to the electron density. """ def __init__(self): NeedsGD.__init__(self) self.rho_g = None self.del_rho_del_n_g = None def estimate_memory(self, mem): nbytes = self.gd.bytecount() mem.subnode('Density', nbytes) if self.depends_on_el_density: mem.subnode('Density Derivative', nbytes) def allocate(self): NeedsGD.allocate(self) self.rho_g = self.gd.empty() if self.depends_on_el_density: self.del_rho_del_n_g = self.gd.empty() def update(self, atoms, density): raise NotImplementedError() @property def depends_on_el_density(self): raise NotImplementedError() @property def depends_on_atomic_positions(self): raise NotImplementedError() def print_parameters(self, text): pass class ElDensity(Density): """Wrapper class for using the electron density in a SmoothStepCavity. (Hopefully small) negative values of the electron density are set to zero. """ depends_on_el_density = True depends_on_atomic_positions = False def allocate(self): Density.allocate(self) self.del_rho_del_n_g = 1. # free array def update(self, atoms, density): self.rho_g[:] = density.nt_g self.rho_g[self.rho_g < .0] = .0 return True class SSS09Density(Density): """Fake density from atomic radii for the use in a SmoothStepCavity. Following V. M. Sanchez, M. Sued and D. A. Scherlis, J. Chem. Phys. 131, 174108 (2009). """ depends_on_el_density = False depends_on_atomic_positions = True def __init__(self, atomic_radii, pbc_cutoff=1e-3): """Constructor for the SSS09Density class. Arguments: atomic_radii -- Callable mapping an ase.Atoms object to an iterable of atomic radii in Angstroms. pbc_cutoff -- Cutoff in eV for including neighbor cells in a calculation with periodic boundary conditions. """ Density.__init__(self) self.atomic_radii = atomic_radii self.atomic_radii_output = None self.symbols = None self.pbc_cutoff = float(pbc_cutoff) self.pos_aav = None self.r_vg = None self.del_rho_del_r_vg = None def estimate_memory(self, mem): Density.estimate_memory(self, mem) nbytes = self.gd.bytecount() mem.subnode('Coordinates', 3 * nbytes) mem.subnode('Atomic Position Derivative', 3 * nbytes) def allocate(self): Density.allocate(self) self.r_vg = self.gd.get_grid_point_coordinates() self.del_rho_del_r_vg = self.gd.empty(3) def update(self, atoms, density): if atoms is None: return False self.atomic_radii_output = np.array(self.atomic_radii(atoms)) self.symbols = atoms.get_chemical_symbols() r_a = self.atomic_radii_output / Bohr r_cutoff = r_a.max() - np.log(self.pbc_cutoff) self.pos_aav = get_pbc_positions(atoms, r_cutoff) self.rho_g.fill(.0) na = np.newaxis for index, pos_av in self.pos_aav.items(): for pos_v in pos_av: origin_vg = pos_v[:, na, na, na] r_diff_vg = self.r_vg - origin_vg norm_r_diff_g = (r_diff_vg ** 2).sum(0) ** .5 self.rho_g += np.exp(r_a[index] - norm_r_diff_g) return True def get_del_r_vg(self, atom_index, density): r_a = self.atomic_radii_output[atom_index] / Bohr na = np.newaxis self.del_rho_del_r_vg.fill(.0) for pos_v in self.pos_aav[atom_index]: origin_vg = pos_v[:, na, na, na] r_diff_vg = self.r_vg - origin_vg norm_r_diff_g = np.sum(r_diff_vg ** 2, axis=0) ** .5 exponential = np.exp(r_a - norm_r_diff_g) self.del_rho_del_r_vg += divide_silently( exponential * r_diff_vg, norm_r_diff_g ) return self.del_rho_del_r_vg def print_parameters(self, text): if self.symbols is None: text('atomic_radii: not initialized (dry run)') else: text('atomic_radii:') for a, (s, r) in enumerate( zip(self.symbols, self.atomic_radii_output) ): text('%3d %-2s %10.5f' % (a, s, r)) text('pbc_cutoff: %s' % (self.pbc_cutoff, )) Density.print_parameters(self, text) class ADM12SmoothStepCavity(SmoothStepCavity): """Cavity from smooth step function. Following O. Andreussi, I. Dabo, and N. Marzari, J. Chem. Phys. 136, 064102 (2012). """ def __init__( self, rhomin, rhomax, epsinf, density, surface_calculator=None, volume_calculator=None ): """Constructor for the ADM12SmoothStepCavity class. Additional arguments not present in the SmoothStepCavity class: rhomin -- Lower density isovalue in 1 / Angstrom ** 3. rhomax -- Upper density isovalue in 1 / Angstrom ** 3. epsinf -- Static dielectric constant of the solvent. """ SmoothStepCavity.__init__( self, density, surface_calculator, volume_calculator ) self.rhomin = float(rhomin) self.rhomax = float(rhomax) self.epsinf = float(epsinf) def update_smooth_step(self, rho_g): eps = self.epsinf inside = rho_g > self.rhomax * Bohr ** 3 outside = rho_g < self.rhomin * Bohr ** 3 transition = np.logical_not( np.logical_or(inside, outside) ) self.g_g[inside] = .0 self.g_g[outside] = 1. self.del_g_del_rho_g.fill(.0) t, dt = self._get_t_dt(np.log(rho_g[transition])) if eps == 1.0: # lim_{eps -> 1} (eps - eps ** t) / (eps - 1) = 1 - t self.g_g[transition] = t self.del_g_del_rho_g[transition] = dt / rho_g[transition] else: eps_to_t = eps ** t self.g_g[transition] = (eps_to_t - 1.) / (eps - 1.) self.del_g_del_rho_g[transition] = ( eps_to_t * np.log(eps) * dt ) / ( rho_g[transition] * (eps - 1.) ) def _get_t_dt(self, x): lnmax = np.log(self.rhomax * Bohr ** 3) lnmin = np.log(self.rhomin * Bohr ** 3) twopi = 2. * np.pi arg = twopi * (lnmax - x) / (lnmax - lnmin) t = (arg - np.sin(arg)) / twopi dt = -2. * np.sin(arg / 2.) ** 2 / (lnmax - lnmin) return (t, dt) def print_parameters(self, text): text('rhomin: %s' % (self.rhomin, )) text('rhomax: %s' % (self.rhomax, )) text('epsinf: %s' % (self.epsinf, )) SmoothStepCavity.print_parameters(self, text) class FG02SmoothStepCavity(SmoothStepCavity): """Cavity from smooth step function. Following J. Fattebert and F. Gygi, J. Comput. Chem. 23, 662 (2002). """ def __init__( self, rho0, beta, density, surface_calculator=None, volume_calculator=None ): """Constructor for the FG02SmoothStepCavity class. Additional arguments not present in the SmoothStepCavity class: rho0 -- Density isovalue in 1 / Angstrom ** 3. beta -- Parameter controlling the steepness of the transition. """ SmoothStepCavity.__init__( self, density, surface_calculator, volume_calculator ) self.rho0 = float(rho0) self.beta = float(beta) def update_smooth_step(self, rho_g): rho0 = self.rho0 / (1. / Bohr ** 3) rho_scaled_g = rho_g / rho0 exponent = 2. * self.beta np.divide(1., rho_scaled_g ** exponent + 1., self.g_g) np.multiply( (-exponent / rho0) * rho_scaled_g ** (exponent - 1.), self.g_g ** 2, self.del_g_del_rho_g ) def print_parameters(self, text): text('rho0: %s' % (self.rho0, )) text('beta: %s' % (self.beta, )) SmoothStepCavity.print_parameters(self, text) class SurfaceCalculator(NeedsGD): """Base class for surface calculators. Attributes: A -- Local area in Bohr ** 2. delta_A_delta_g_g -- Functional derivative with respect to the cavity on the fine grid. """ def __init__(self): NeedsGD.__init__(self) self.A = None self.delta_A_delta_g_g = None def estimate_memory(self, mem): mem.subnode('Functional Derivative', self.gd.bytecount()) def allocate(self): NeedsGD.allocate(self) self.delta_A_delta_g_g = self.gd.empty() def print_parameters(self, text): pass def update(self, cavity): """Calculate A and delta_A_delta_g_g.""" raise NotImplementedError() class GradientSurface(SurfaceCalculator): """Class for getting the surface area from the gradient of the cavity. See also W. Im, D. Beglov and B. Roux, Comput. Phys. Commun. 111, 59 (1998) and A. Held and M. Walter, J. Chem. Phys. 141, 174108 (2014). """ def __init__(self, nn=3): SurfaceCalculator.__init__(self) self.nn = nn self.gradient = None self.gradient_in = None self.gradient_out = None self.norm_grad_out = None self.div_tmp = None def estimate_memory(self, mem): SurfaceCalculator.estimate_memory(self, mem) nbytes = self.gd.bytecount() mem.subnode('Gradient', 5 * nbytes) mem.subnode('Divergence', nbytes) def allocate(self): SurfaceCalculator.allocate(self) self.gradient = [ Gradient(self.gd, i, 1.0, self.nn) for i in (0, 1, 2) ] self.gradient_in = self.gd.empty() self.gradient_out = self.gd.empty(3) self.norm_grad_out = self.gd.empty() self.div_tmp = self.gd.empty() def update(self, cavity): inner = cavity.get_inner_function() del_outer_del_inner = cavity.get_del_outer_del_inner() sign = np.sign(del_outer_del_inner.max() + del_outer_del_inner.min()) try: self.gradient_out[...] = cavity.get_grad_inner() self.norm_grad_out = (self.gradient_out ** 2).sum(0) ** .5 except NotImplementedError: self.calc_grad(inner, cavity.get_inner_function_boundary_value()) self.A = sign * self.gd.integrate( del_outer_del_inner * self.norm_grad_out, global_integral=False ) mask = self.norm_grad_out > 1e-12 # avoid division by zero or overflow imask = np.logical_not(mask) masked_norm_grad = self.norm_grad_out[mask] for i in (0, 1, 2): self.gradient_out[i][mask] /= masked_norm_grad # set limit for later calculations: self.gradient_out[i][imask] = .0 self.calc_div(self.gradient_out, self.delta_A_delta_g_g) if sign == 1: self.delta_A_delta_g_g *= -1. def calc_grad(self, x, boundary): if boundary != .0: np.subtract(x, boundary, self.gradient_in) gradient_in = self.gradient_in else: gradient_in = x self.norm_grad_out.fill(.0) for i in (0, 1, 2): self.gradient[i].apply(gradient_in, self.gradient_out[i]) self.norm_grad_out += self.gradient_out[i] ** 2 self.norm_grad_out **= .5 def calc_div(self, vec, out): self.gradient[0].apply(vec[0], out) self.gradient[1].apply(vec[1], self.div_tmp) out += self.div_tmp self.gradient[2].apply(vec[2], self.div_tmp) out += self.div_tmp class VolumeCalculator(NeedsGD): """Base class for volume calculators. Attributes: V -- Local volume in Bohr ** 3. delta_V_delta_g_g -- Functional derivative with respect to the cavity on the fine grid. """ def __init__(self): NeedsGD.__init__(self) self.V = None self.delta_V_delta_g_g = None def estimate_memory(self, mem): mem.subnode('Functional Derivative', self.gd.bytecount()) def allocate(self): NeedsGD.allocate(self) self.delta_V_delta_g_g = self.gd.empty() def print_parameters(self, text): pass def update(self, cavity): """Calculate V and delta_V_delta_g_g""" raise NotImplementedError() class KB51Volume(VolumeCalculator): """KB51 Volume Calculator. V = Integral(1 - g) + kappa_T * k_B * T Following J. G. Kirkwood and F. P. Buff, J. Chem. Phys. 19, 6, 774 (1951). """ def __init__(self, compressibility=.0, temperature=.0): """Constructor for KB51Volume class. Arguments: compressibility -- Isothermal compressibility of the solvent in Angstrom ** 3 / eV. temperature -- Temperature in Kelvin. """ VolumeCalculator.__init__(self) self.compressibility = float(compressibility) self.temperature = float(temperature) def print_parameters(self, text): text('compressibility: %s' % (self.compressibility, )) text('temperature: %s' % (self.temperature, )) VolumeCalculator.print_parameters(self, text) def allocate(self): VolumeCalculator.allocate(self) self.delta_V_delta_g_g = -1. # frees array def update(self, cavity): self.V = self.gd.integrate(1. - cavity.g_g, global_integral=False) V_compress = self.compressibility * kB * self.temperature / Bohr ** 3 self.V += V_compress / self.gd.comm.size gpaw-0.11.0.13004/gpaw/solvation/calculator.py0000664000175000017500000001114612553643471021137 0ustar jensjjensj00000000000000from gpaw import GPAW from gpaw.solvation.hamiltonian import SolvationRealSpaceHamiltonian from ase.units import Hartree, Bohr class NIReciprocalSpaceHamiltonian: def __init__(self, *args, **kwargs): raise NotImplementedError( 'SolvationGPAW does not support ' 'calculations in reciprocal space yet.' ) class SolvationGPAW(GPAW): """Subclass of gpaw.GPAW calculator with continuum solvent model. See also Section III of A. Held and M. Walter, J. Chem. Phys. 141, 174108 (2014). """ reciprocal_space_hamiltonian_class = NIReciprocalSpaceHamiltonian def __init__(self, cavity, dielectric, interactions=None, **gpaw_kwargs): """Constructor for SolvationGPAW class. Additional arguments not present in GPAW class: cavity -- A Cavity instance. dielectric -- A Dielectric instance. interactions -- A list of Interaction instances. """ if interactions is None: interactions = [] def real_space_hamiltonian_factory(*args, **kwargs): return SolvationRealSpaceHamiltonian( cavity, dielectric, interactions, *args, **kwargs ) self.real_space_hamiltonian_class = real_space_hamiltonian_factory GPAW.__init__(self, **gpaw_kwargs) def initialize_positions(self, atoms=None): spos_ac = GPAW.initialize_positions(self, atoms) self.hamiltonian.update_atoms(self.atoms) return spos_ac def get_electrostatic_energy(self, atoms=None, force_consistent=False): """Return electrostatic part of the total energy. The electrostatic part consists of everything except the short-range interactions defined in the interactions list. See the get_potential_energy method for the meaning of the force_consistent option. """ self.calculate(atoms, converge=True) if force_consistent: # Free energy: return Hartree * self.hamiltonian.Eel else: # Energy extrapolated to zero width: return Hartree * self._extrapolate_energy_to_zero_width( self.hamiltonian.Eel ) def get_solvation_interaction_energy(self, subscript, atoms=None): """Return a specific part of the solvation interaction energy. The subscript parameter defines which part is to be returned. It has to match the value of a subscript attribute of one of the interactions in the interactions list. """ self.calculate(atoms, converge=True) return Hartree * getattr(self.hamiltonian, 'E_' + subscript) def get_cavity_volume(self, atoms=None): """Return the cavity volume in Angstrom ** 3. In case no volume calculator has been set for the cavity, None is returned. """ self.calculate(atoms, converge=True) V = self.hamiltonian.cavity.V return V and V * Bohr ** 3 def get_cavity_surface(self, atoms=None): """Return the cavity surface area in Angstrom ** 2. In case no surface calculator has been set for the cavity, None is returned. """ self.calculate(atoms, converge=True) A = self.hamiltonian.cavity.A return A and A * Bohr ** 2 def print_parameters(self): GPAW.print_parameters(self) t = self.text t() def ul(s, l): t(s) t(l * len(s)) ul('Solvation Parameters:', '=') ul('Cavity:', '-') t('type: %s' % (self.hamiltonian.cavity.__class__, )) self.hamiltonian.cavity.print_parameters(t) t() ul('Dielectric:', '-') t('type: %s' % (self.hamiltonian.dielectric.__class__, )) self.hamiltonian.dielectric.print_parameters(t) t() for ia in self.hamiltonian.interactions: ul('Interaction:', '-') t('type: %s' % (ia.__class__, )) t('subscript: %s' % (ia.subscript, )) ia.print_parameters(t) t() def print_all_information(self): t = self.text t() t('Solvation Energy Contributions:') for ia in self.hamiltonian.interactions: E = Hartree * getattr(self.hamiltonian, 'E_' + ia.subscript) t('%-14s: %+11.6f' % (ia.subscript, E)) Eel = Hartree * getattr(self.hamiltonian, 'Eel') t('%-14s: %+11.6f' % ('el', Eel)) GPAW.print_all_information(self) def write(self, *args, **kwargs): raise NotImplementedError( 'IO is not implemented yet for SolvationGPAW!' ) gpaw-0.11.0.13004/gpaw/solvation/interactions.py0000664000175000017500000001242612553643471021512 0ustar jensjjensj00000000000000from gpaw.solvation.gridmem import NeedsGD from ase.units import Bohr, Hartree import numpy as np class Interaction(NeedsGD): """Base class for non-electrostatic solvent solute interactions. See also Section III of A. Held and M. Walter, J. Chem. Phys. 141, 174108 (2014). Attributes: subscript -- Short label used to reference the interaction. E -- Local interaction energy in Hartree delta_E_delta_n_g -- Functional derivative of the interaction energy with respect to the electron density. delta_E_delta_n_g -- Functional derivative of the interaction energy with respect to the cavity. """ subscript = 'unnamed' def __init__(self): NeedsGD.__init__(self) self.E = None self.delta_E_delta_n_g = None self.delta_E_delta_g_g = None def update(self, atoms, density, cavity): """Update the Kohn-Sham potential and the energy. atoms and/or cavity are None iff they have not changed since the last call Return whether the interaction has changed. """ raise NotImplementedError def estimate_memory(self, mem): ngrids = 1 + self.depends_on_el_density mem.subnode('Functional Derivatives', ngrids * self.gd.bytecount()) def allocate(self): NeedsGD.allocate(self) self.delta_E_delta_g_g = self.gd.empty() if self.depends_on_el_density: self.delta_E_delta_n_g = self.gd.empty() @property def depends_on_atomic_positions(self): """Return whether the ia depends explicitly on atomic positions.""" raise NotImplementedError @property def depends_on_el_density(self): """Return whether the ia depends explicitly on the electron density.""" raise NotImplementedError def get_del_r_vg(self, atomic_index, density): """Return spatial derivatives with respect to atomic position.""" raise NotImplementedError def print_parameters(self, text): """Print parameters using text function.""" pass class SurfaceInteraction(Interaction): """An interaction with energy proportional to the cavity surface area.""" subscript = 'surf' depends_on_el_density = False depends_on_atomic_positions = False def __init__(self, surface_tension): """Constructor for SurfaceInteraction class. Arguments: surface_tension -- Proportionality factor to calculate energy from surface area in eV / Angstrom ** 2. """ Interaction.__init__(self) self.surface_tension = float(surface_tension) def update(self, atoms, density, cavity): if cavity is None: return False acalc = cavity.surface_calculator st = self.surface_tension * Bohr ** 2 / Hartree self.E = st * acalc.A np.multiply(st, acalc.delta_A_delta_g_g, self.delta_E_delta_g_g) return True def print_parameters(self, text): Interaction.print_parameters(self, text) text('surface_tension: %s' % (self.surface_tension, )) class VolumeInteraction(Interaction): """An interaction with energy proportional to the cavity volume""" subscript = 'vol' depends_on_el_density = False depends_on_atomic_positions = False def __init__(self, pressure): """Constructor for VolumeInteraction class. Arguments: pressure -- Proportionality factor to calculate energy from volume in eV / Angstrom ** 3. """ Interaction.__init__(self) self.pressure = float(pressure) def update(self, atoms, density, cavity): if cavity is None: return False vcalc = cavity.volume_calculator pressure = self.pressure * Bohr ** 3 / Hartree self.E = pressure * vcalc.V np.multiply(pressure, vcalc.delta_V_delta_g_g, self.delta_E_delta_g_g) return True def print_parameters(self, text): Interaction.print_parameters(self, text) text('pressure: %s' % (self.pressure, )) class LeakedDensityInteraction(Interaction): """Interaction proportional to charge leaking outside cavity. The charge outside the cavity is calculated as """ subscript = 'leak' depends_on_el_density = True depends_on_atomic_positions = False def __init__(self, voltage): """Constructor for LeakedDensityInteraction class. Arguments: voltage -- Proportionality factor to calculate energy from integrated electron density in Volts. A positive value of the voltage leads to a positive interaction energy. """ Interaction.__init__(self) self.voltage = float(voltage) def update(self, atoms, density, cavity): E0 = self.voltage / Hartree if cavity is not None: np.multiply(E0, cavity.g_g, self.delta_E_delta_n_g) np.multiply(E0, density.nt_g, self.delta_E_delta_g_g) self.E = self.gd.integrate( density.nt_g * self.delta_E_delta_n_g, global_integral=False ) return True def print_parameters(self, text): Interaction.print_parameters(self, text) text('voltage: %s' % (self.voltage, )) gpaw-0.11.0.13004/gpaw/solvation/__init__.py0000664000175000017500000000106712553643471020546 0ustar jensjjensj00000000000000"""The gpaw.solvation package. This packages extends GPAW to be used with different continuum solvent models. """ from gpaw.solvation.calculator import SolvationGPAW from gpaw.solvation.cavity import ( EffectivePotentialCavity, Power12Potential, ElDensity, SSS09Density, ADM12SmoothStepCavity, FG02SmoothStepCavity, GradientSurface, KB51Volume) from gpaw.solvation.dielectric import LinearDielectric, CMDielectric from gpaw.solvation.interactions import ( SurfaceInteraction, VolumeInteraction, LeakedDensityInteraction) gpaw-0.11.0.13004/gpaw/solvation/gridmem.py0000664000175000017500000000045212553643471020430 0ustar jensjjensj00000000000000class NeedsGD: """Common base class for classes using a grid descriptor.""" def __init__(self): self.gd = None def set_grid_descriptor(self, gd): self.gd = gd def allocate(self): pass def estimate_memory(self, mem): raise NotImplementedError gpaw-0.11.0.13004/gpaw/spline.py0000664000175000017500000000471312553643470016263 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. import numpy as np from gpaw import debug from gpaw.utilities import is_contiguous import _gpaw class Spline: def __init__(self, l, rmax, f_g): """Spline(l, rcut, list) -> Spline object The integer l gives the angular momentum quantum number and the list contains the spline values from r=0 to r=rcut. The array f_g gives the radial part of the function on the grid. The radial function is multiplied by a real solid spherical harmonics (r^l * Y_lm). """ assert 0.0 < rmax f_g = np.array(f_g, float) # Copy so we don't change the values of the input array f_g[-1] = 0.0 self.spline = _gpaw.Spline(l, rmax, f_g) def get_cutoff(self): """Return the radial cutoff.""" return self.spline.get_cutoff() def get_angular_momentum_number(self): """Return the angular momentum quantum number.""" return self.spline.get_angular_momentum_number() def get_value_and_derivative(self, r): """Return the value and derivative.""" return self.spline.get_value_and_derivative(r) def __call__(self, r): assert r >= 0.0 return self.spline(r) def map(self, r_x): return np.vectorize(self, [float])(r_x) def get_functions(self, gd, start_c, end_c, spos_c): h_cv = gd.h_cv # start_c is the new origin so we translate gd.beg_c to start_c origin_c = np.array([0,0,0]) pos_v = np.dot(spos_c, gd.cell_cv) - np.dot(start_c, h_cv) A_gm, G_b = _gpaw.spline_to_grid(self.spline, origin_c, end_c-start_c, pos_v, h_cv, end_c-start_c, origin_c) if debug: assert G_b.ndim == 1 and G_b.shape[0] % 2 == 0 assert is_contiguous(G_b, np.intc) assert A_gm.shape[:-1] == np.sum(G_b[1::2]-G_b[::2]) indices_gm, ng, nm = self.spline.get_indices_from_zranges(start_c, end_c, G_b) shape = (nm,) + tuple(end_c-start_c) work_mB = np.zeros(shape, dtype=A_gm.dtype) np.put(work_mB, indices_gm, A_gm) return work_mB ## class rspline: ## def __init__(self, r_g, f_g, l=0): ## self.rcut = r_g[-1] ## self.l = l ## ... ## def __call__(self, r): ## return self.spline(r)*r**l gpaw-0.11.0.13004/gpaw/version.py0000664000175000017500000000047612553643470016460 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. version_base = '0.11.0' ase_required_version = '3.9.1' try: from gpaw.svnversion import svnversion except (AttributeError, ImportError): version = version_base else: version = version_base + '.' + svnversion gpaw-0.11.0.13004/gpaw/hgh_parameters.py0000664000175000017500000007777712553643470020006 0ustar jensjjensj00000000000000parameters = """\ H 1 .200000 -4.180237 .725075 He 2 .200000 -9.112023 1.698368 Li 1 .787553 -1.892612 .286060 .666375 1.858811 1.079306 -.005895 .000019 Li.sc 3 .400000 -14.034868 9.553476 -1.766488 .084370 Be 2 .739009 -2.592951 .354839 .528797 3.061666 .658153 .092462 .000129 Be.sc 4 .325000 -24.015041 17.204014 -3.326390 .165419 B 3 .433930 -5.578642 .804251 .373843 6.233928 .360393 .000000 .000878 C 4 .348830 -8.513771 1.228432 .304553 9.522842 .232677 .000000 .004104 N 5 .289179 -12.234820 1.766407 .256605 13.552243 .270134 .000000 .003131 O 6 .247621 -16.580318 2.395701 .221786 18.266917 .256829 .000000 .004476 F 7 .218525 -21.307361 3.072869 .195567 23.584942 .174268 .000000 .015106 Ne 8 .190000 -27.692852 4.005906 .179488 28.506098 -1.076245 .214913 -.000090 .010336 Na 1 .885509 -1.238867 .661104 1.847271 .582004 .857119 .471133 .002623 Na.sc 9 .246318 -7.545593 1.125997 .141251 36.556987 .139668 -10.392083 .038386 Mg 2 .651812 -2.864297 .556478 2.970957 1.329941 .677569 1.049881 .005152 Mg.sc 10 .210950 -19.419008 2.871331 .141547 40.316626 .105469 -10.891113 .096277 Al 3 .450000 -8.491351 .460104 5.088340 2.679700 .536744 2.193438 .000000 .006154 .003947 Si 4 .440000 -7.336103 .422738 5.906928 3.258196 .484278 2.727013 .000000 .000373 .014437 P 5 .430000 -6.654220 .389803 6.842136 3.856693 .440796 3.282606 .000000 .002544 .017895 S 6 .420000 -6.554492 .361757 7.905303 4.471698 .405285 3.866579 .000000 .005372 .022062 Cl 7 .410000 -6.864754 .338208 9.062240 5.065682 .376137 4.465876 .000000 .010020 .025784 Ar 8 .400000 -7.100000 .317381 10.249487 5.602516 .351619 4.978801 .000000 .016395 .029171 K 1 .950000 .955364 .914612 .287551 -.300224 1.086411 .315462 .068194 -.004343 .010261 .720606 -1.529514 .000354 K.sc 9 .400000 -4.989348 -.756048 .294826 11.238705 7.067779 .322359 5.256702 .938947 .015795 .048923 Ca 2 .800000 .669737 1.645014 1.523491 .295996 .946474 .585479 .126329 -.003362 .012779 .526550 -3.032321 .000814 Ca.sc 10 .390000 -4.928146 -1.232854 .281909 12.352340 7.657455 .310345 5.722423 .923591 .021701 .056661 .904330 .016806 .000371 Sc 3 .750000 .597079 1.835768 1.734309 1.418483 .847994 .784127 .246733 -.008463 .020913 .454653 -3.859241 .001430 Sc.sc 11 .385000 7.425036 -.489852 .359707 6.119585 -2.563453 .243234 6.376618 -6.016415 .083053 .093017 .252945 -8.020892 .004812 Ti 4 .720000 .528411 1.866613 1.440233 3.658172 .791146 .967916 .260687 -.009333 .025291 .408712 -4.826456 .002010 Ti.sc 12 .380000 7.548789 -.588377 .334235 6.925740 -3.142005 .242416 5.079086 -6.284281 .122395 .057447 .242947 -9.125896 .005822 V 5 .690000 .514704 2.208670 1.896763 3.076377 .743504 1.115751 .286649 -.010973 .030816 .374890 -5.841633 .002717 V.sc 13 .375000 4.941291 -.096443 .326651 7.659390 -3.892229 .246407 4.256230 -5.941212 .156408 .008030 .240792 -8.828518 .006548 Cr 6 .660000 .498578 2.400756 2.072337 2.952179 .719768 1.145557 .278236 -.013176 .035625 .354341 -6.615878 .003514 Cr.sc 14 .370000 5.113362 -.646819 .306011 8.617835 -4.137695 .241090 3.161588 -5.032906 .169781 .000411 .219577 -11.157868 .009007 Mn 7 .640000 .481246 2.799031 2.486101 2.565630 .669304 1.368776 .316763 -.013685 .042938 .327763 -7.995418 .004536 Mn.sc 15 .365000 6.748683 -.576569 .280753 9.379532 -5.575280 .254536 .371176 -4.229057 .164188 -.039396 .221422 -12.115385 .009590 Fe 8 .610000 .454482 3.016640 2.583038 3.257635 .638903 1.499642 .326874 -.014909 .049793 .308732 -9.145354 .005722 Fe.sc 16 .360000 5.392507 -.030066 .269268 10.193723 -6.834982 .247686 .145613 -5.234954 .201450 -.075829 .223021 -12.026941 .010322 Co 9 .580000 .440457 3.334978 2.873150 3.091028 .610048 1.634005 .356083 -.017521 .058766 .291661 -10.358800 .007137 Co.sc 17 .355000 3.418391 .482078 .259140 11.195226 -7.845825 .251425 -.551464 -4.639237 .207915 -.108249 .221665 -12.075354 .011475 Ni 10 .560000 .425399 3.619651 3.088965 3.058598 .584081 1.742220 .386341 -.020384 .068770 .278113 -11.608428 .008708 Ni.sc 18 .350000 3.610311 .449638 .245105 12.161131 -9.078929 .234741 -.820624 -6.029071 .269572 -.143442 .214950 -13.395062 .013538 Cu 1 .580000 .843283 .975787 -.822070 -.133237 1.089543 .024580 -.249001 .010792 -.006734 1.291602 -.065292 -.000730 Cu.sc 11 .530000 .423734 3.888050 3.276584 2.290091 .572177 1.751272 .374943 -.024067 .076481 .266143 -12.676957 .010489 Zn 2 .570000 .640712 2.088557 -.218270 -.941317 .967605 .163546 -.227086 .012139 -.004876 1.330352 .010486 .000225 Zn.sc 12 .510000 .400866 4.278710 3.627342 2.849567 .539618 2.023884 .431742 -.025759 .090915 .252151 -14.338368 .012767 Ga 3 .560000 .610791 2.369325 -.249015 -.551796 .704596 .746305 -.513132 .029607 -.000873 .982580 .075437 .001486 Ga.sc 13 .490000 .384713 4.831779 4.238168 2.833238 .586130 1.940527 -.299738 .026949 .031400 .240803 -15.795675 .015503 Ge 4 .540000 .493743 3.826891 1.100231 -1.344218 .601064 1.362518 -.627370 .043981 .009802 .788369 .191205 .002918 As 5 .520000 .456400 4.560761 1.692389 -1.373804 .550562 1.812247 -.646727 .052466 .020562 .685283 .312373 .004273 Se 6 .510000 .432531 5.145131 2.052009 -1.369203 .472473 2.858806 -.590671 .062196 .064907 .613420 .434829 .005784 Br 7 .500000 .428207 5.398837 1.820292 -1.323974 .455323 3.108823 -.632202 .074007 .068787 .557847 .555903 .007144 Kr 8 .500000 .410759 5.911194 1.967372 -1.458069 .430256 3.524357 -.691198 .087011 .086008 .517120 .629228 .009267 Rb 1 1.096207 .847333 -.748120 .955699 .887460 .903088 -.006750 1.156681 .461734 .336113 -.043443 .057876 .664323 -1.362938 .003708 Rb.sc 9 .490000 4.504151 -.741018 .282301 9.536329 9.486634 .301886 2.209592 5.475249 -.867379 1.237532 .514895 .449376 .008685 Sr 2 1.010000 .684749 -.062125 .837564 1.200395 .926675 -.315858 1.174178 .439983 .018267 .004022 .022207 .743175 -1.386990 .002846 Sr.sc 10 .480000 5.571455 -1.079963 .275441 9.995135 9.336679 .302243 3.169126 4.049231 -.576265 .990062 .502045 .438728 .008991 Y 3 .900000 -.343891 .782457 1.520655 1.484368 -.189013 .949864 .780950 .368739 -.043336 .079989 .653851 -1.256930 -.075368 .009198 -.011657 Y.sc 11 .475000 13.217914 1.353178 .414360 2.522621 -4.363769 .406442 -.569552 -3.020044 .251526 -.077005 .513304 -1.571003 .627616 .012450 -.007507 Zr 4 .750000 -.782611 .649998 1.739877 2.388208 1.205349 .874408 1.018294 .528223 -.057486 .104495 .630668 -1.173911 .212179 .009380 -.011973 Zr.sc 12 .470000 15.782342 .433648 .396540 2.571767 -4.714509 .388558 -.794123 -3.172114 .301247 -.098654 .520496 -1.548402 .826127 .013187 -.010136 Nb 5 .724000 4.021058 .699708 1.532651 1.428264 .846672 .609675 .596788 -.080816 .125243 .516072 -2.696830 -1.694967 .025653 -.031541 Nb.sc 13 .460000 13.505394 .752434 .393708 3.222025 -4.599342 .403626 -.822037 -2.247366 .246821 -.086659 .513644 -1.489848 .823817 .014064 -.012055 Mo 6 .699000 7.995868 .678126 1.289607 .998113 .800771 .301412 .741615 -.104124 .153906 .453384 -2.809708 -6.820946 .068972 -.075591 Mo.sc 14 .430000 16.237452 1.496536 .376255 3.362426 -5.289276 .361734 -.379571 -4.067713 .378681 -.124561 .525828 -1.543211 1.074388 .014460 -.014769 Tc 7 .673000 13.315381 .677612 .819218 .348460 .784275 .028673 .658363 -.080760 .140668 .519890 -5.984224 .721822 .026025 -.041776 Tc.sc 15 .430000 14.910011 1.046381 .369721 3.917408 -5.268399 .357772 -.270000 -3.737771 .340791 -.065948 .510487 -1.586709 1.132307 .015790 -.016485 Ru 8 .647214 8.687723 .625656 1.637866 1.329335 .746425 .639012 .650376 -.095454 .164257 .440358 -4.883365 -3.063746 .046652 -.061808 Ru.sc 16 .430000 13.582571 .596227 .364084 4.480632 -5.268679 .364053 -.320372 -3.059714 .337322 -.103467 .495850 -1.597870 1.165495 .017773 -.019725 Rh 9 .621429 5.397962 .598079 2.242111 2.151597 .709586 1.155278 .704846 -.114357 .193923 .369207 -1.053058 -10.923960 .135036 -.127750 Rh.sc 17 .420000 15.225012 .415911 .350052 4.715292 -5.805525 .350253 -.504694 -3.373040 .389629 -.122856 .496950 -1.685594 1.387707 .018875 -.022837 Pd 10 .596000 5.209665 .582204 2.411076 2.318920 .688787 1.227253 .758021 -.136909 .220805 .442835 -4.377131 .413271 .033797 -.047798 Pd.sc 18 .410000 15.720259 .140765 .342151 5.177686 -5.852819 .343111 -.372561 -3.258728 .406984 -.110764 .494916 -1.608273 1.446609 .020374 -.026732 Ag 1 .650000 -2.376061 1.012705 .897931 -.748323 .029787 1.235842 .130081 -.277495 .019692 -.006821 1.016159 -.038842 .009455 Ag.sc 11 .570000 1.017053 .498900 2.990284 3.912395 2.205847 .630009 1.813968 1.304450 -.201869 .319708 .387660 -3.420076 -1.019949 .045193 -.051565 Cd 2 .625000 -1.796838 .828465 1.485292 -.424753 -.407986 .972873 .469208 -.448111 .037714 -.002009 1.240949 .065412 .003109 Cd.sc 12 .550000 2.382713 .491505 3.207932 4.140963 1.584234 .598565 1.940150 1.515892 -.241409 .376830 .377874 -4.190072 -.770156 .049329 -.058835 In 3 .610000 2.865777 .770602 1.256194 -.397255 -.278329 .858132 .494459 -.380789 .066367 -.005563 1.088691 .129208 .004448 In.sc 13 .530000 2.395404 .474081 3.554411 4.754135 1.565040 .559819 2.223664 2.035278 -.306488 .479435 .360488 -4.566414 -.773785 .058765 -.073414 Sn 4 .605000 4.610912 .663544 1.648791 -.141974 -.576546 .745865 .769355 -.445070 .103931 .005057 .944459 .225115 .007066 Sb 5 .590000 6.680228 .597684 1.951477 .037537 -.786631 .672122 .970313 -.466731 .139222 .023513 .856557 .300103 .009432 Te 6 .575000 9.387085 .556456 2.046890 -.029333 -.881119 .615262 1.033478 -.481172 .172997 .050641 .805101 .317411 .010809 I 7 .560000 14.661825 .552830 1.338054 -.834851 -.467438 .562251 .674496 -.577787 .213967 .093313 .794325 .224345 .010180 Xe 8 .560000 12.734280 .507371 2.236451 -.403551 -1.132507 .541024 1.130043 -.752764 .236603 .108473 .729821 .280131 .013362 Cs 1 1.200000 1.224737 .611527 .239830 -.294024 1.280478 .244893 .227279 -.107627 .138132 1.107522 -.542163 .003259 Cs.sc 9 .540000 35.234438 -3.318070 .456821 -.282378 -2.780956 .362467 -2.696733 -2.290940 .000000 -2.748528 1.815069 1.204825 .761462 .183754 .010841 .333507 -17.948259 .004760 Ba 2 1.200000 1.016187 .922593 .763495 -.333465 1.249880 .447168 .151081 -.041017 .088800 .937158 -.718934 .005321 Ba.sc 10 .540000 24.478653 -2.500850 .514776 1.046729 -.977217 .375190 -.202439 .680331 .000000 -.415083 .599763 .927065 .665403 .378419 .017660 .304920 -18.795208 .006151 La.sc 11 .535000 19.909308 -1.474830 .551775 1.293272 -1.121819 .476308 1.172527 -.828810 .029857 .524623 -.030901 .142077 .626672 .328377 .020900 .299310 -18.269439 .007193 Ce.sc 12 .535000 18.847470 -.765636 .521790 1.321616 -1.700444 .470324 .972641 -1.451337 .000000 .463710 .090257 .012566 .703593 .074241 .013265 .306717 -17.214790 .007568 Pr.sc 13 .532083 18.424739 -.657669 .526850 1.012621 -1.717982 .458897 1.117060 -1.852109 .000000 .314280 .350982 -.165254 .747610 .017571 .010905 .300773 -17.897119 .008547 Nd.sc 14 .529167 17.815030 -.594798 .503000 1.529110 -2.153732 .467013 .721553 -1.647499 .000000 -.214396 1.100446 -.832670 .325290 -.543240 .611413 .294743 -18.520228 .009598 Pm.sc 15 .526250 18.251723 -.492107 .489879 1.308978 -2.507751 .472260 .160512 -1.565305 .000000 -.339955 1.359017 -1.145883 .473709 -.429952 .064044 .291527 -19.305057 .010619 Sm.sc 16 .523333 17.206792 -.532803 .479677 1.723635 -2.659367 .490598 -.082403 -1.111009 .000000 -.240300 1.200867 -1.054041 .470840 -.410630 .063352 .284040 -19.984292 .011924 Eu.sc 17 .520417 17.373516 -.648468 .469043 1.763638 -2.916932 .445907 .518046 -2.135186 .000000 .252258 .584324 -.480586 .490038 -.426120 .051028 .278401 -20.946528 .013267 Gd.sc 18 .517500 17.512556 -.719534 .462014 1.551856 -3.068703 .456953 -.058347 -1.697711 .000000 .535540 .022024 -.054301 .482368 -.562601 .053128 .273390 -21.923490 .014666 Tb.sc 19 .514583 17.603616 -.828080 .448694 1.718481 -3.435239 .424220 .562400 -2.781827 .000000 -.008725 1.144007 -.860425 .482809 -.625802 .051754 .268260 -22.911697 .016197 Dy.sc 20 .511667 16.994331 -.955298 .440590 1.940320 -3.559798 .434642 .014315 -2.046238 .000000 -.124371 1.327404 -1.092142 .467229 -.668924 .058286 .261670 -23.922358 .017938 Ho.sc 21 .508750 16.781570 -1.173514 .432212 2.052797 -3.674534 .420138 .253295 -2.355289 .000000 .895947 -.275149 .205729 .447131 -.742863 .069483 .254992 -25.197211 .019830 Er.sc 22 .505833 17.105293 -1.430953 .419948 2.144503 -3.984203 .414455 .054087 -2.294477 .000000 1.255135 -.891960 .749717 .418385 -.999006 .091862 .249126 -26.696809 .021783 Tm.sc 23 .502917 17.247293 -1.627697 .413373 1.947196 -4.121556 .409923 -.094493 -2.224087 .000000 2.045370 -2.347237 1.902736 .392870 -1.353308 .119299 .243917 -28.104159 .023833 Yb.sc 24 .500000 17.357144 -1.773916 .402309 2.120771 -4.802990 .414358 -.923212 -1.678540 .000000 -.349470 2.074295 -1.814297 .444025 -.889967 .070076 .238298 -29.932854 .025718 Lu.sc 25 .497000 17.037053 -1.661610 .391206 2.184678 -5.432346 .393896 -.719819 -2.723799 .000000 .152450 1.395416 -1.238744 .436518 -1.173245 .072130 .232629 -31.852262 .028006 Hf.sc 12 .560000 5.134801 .529191 .422810 2.564442 -6.013732 1.109760 .472681 -1.025275 -1.872548 .000000 .607504 -.331637 -.121021 .426388 1.459363 -5.282764 .222119 -.121283 Ta 5 .744000 3.623116 .581801 2.005338 3.027036 .770646 .518567 1.185378 -.485635 .695148 .534370 -2.202200 -1.666675 .086716 -.094635 Ta.sc 13 .550000 4.546236 .779422 .421853 2.708136 -5.790959 .947663 .461345 -.724853 -2.215211 .000000 .649992 -.336371 -.101322 .410994 1.348495 -5.386947 .205344 -.102353 W 6 .719000 4.058450 .582463 2.161166 2.741500 .742307 .600973 1.299943 -.509800 .751739 .534959 -2.517063 -.789137 .075772 -.086193 W.sc 14 .540000 4.800251 .901544 .418570 2.692204 -6.022637 1.218316 .449555 -.702084 -2.451680 .000000 .715480 -.385339 -.077093 .399602 1.177436 -5.553621 .205860 -.100046 Re 7 .693000 8.180816 .509816 2.269379 3.528529 .745839 .496693 .925829 -.370589 .616765 .500954 -3.689630 -1.894601 .111557 -.131595 Re.sc 15 .530000 5.592660 .943957 .403252 2.760720 -6.396415 .868732 .440951 -.900546 -2.511211 .000000 .788715 -.489984 -.017012 .390395 .875251 -5.672543 .209737 -.102862 Os 8 .667000 9.440459 .510307 2.402367 3.046706 .717553 .499523 1.053284 -.430746 .701752 .487586 -4.142035 -1.666100 .116941 -.139761 Os.sc 16 .520000 5.613073 .921955 .410578 2.785758 -6.692130 2.247034 .422395 -.590006 -3.018323 .000000 .870817 -.412886 -.139506 .380252 .880133 -5.732892 .216440 -.103221 Ir 9 .641000 10.720016 .509960 2.445999 2.811037 .684971 .461792 1.304726 -.565347 .859620 .471745 -4.545484 -1.635428 .127199 -.151950 Ir.sc 17 .510000 4.904509 1.313786 .404469 3.243278 -7.315509 2.956978 .411426 -.380574 -3.504403 .000000 .930121 -.379865 -.262716 .376428 .754315 -5.875580 .219517 -.112145 Pt 10 .616000 11.027417 .520132 2.447430 2.640360 .658976 .408453 1.647716 -.763296 1.065883 .451243 -4.552295 -2.102396 .146912 -.169306 Pt.sc 18 .500000 5.445832 1.156382 .409942 2.994366 -7.448772 4.243095 .398652 -.225181 -3.776974 .000000 1.017060 -.348213 -.331919 .367964 .632067 -5.755431 .226472 -.114346 Au 1 .650000 -1.963712 -1.698123 .919308 1.539599 -.468779 -.792039 1.140351 .471229 -.497538 -.209758 .039349 .132970 -.153427 Au.sc 11 .590000 11.604428 .521180 2.538614 2.701113 .630613 .394853 2.057831 -.960055 1.296571 .440706 -4.719070 -1.650429 .148484 -.169493 Hg 2 .640000 -3.296329 .812108 1.765041 -.466127 -.799941 1.053714 .474056 -.531816 .092330 -.001118 1.100000 .120638 .020931 Hg.sc 12 .570000 2.134572 .521802 3.293920 4.661001 .621648 2.100960 1.689988 .000000 .084989 .072771 .653348 .401894 -1.669886 -2.473265 .155759 -.122282 Tl 3 .630000 -1.235846 .754005 1.875766 -.303680 -.781337 .903742 .759668 -.586721 .168641 .004459 1.063512 .247614 .022941 Tl.sc 13 .550000 7.301886 .502423 3.326560 4.341390 .572016 1.272807 2.992206 .000000 .012233 .031664 1.019164 .393185 -3.200652 -3.008296 .186849 -.170651 Pb 4 .617500 .753143 .705259 1.979927 -.164960 -.806060 .846641 .864420 -.540969 .207711 .012948 .971939 .374967 .029256 Bi 5 .605000 6.679437 .678858 1.377634 -.513697 -.471028 .798673 .655578 -.402932 .305314 -.023134 .934683 .378476 .029217 Po 6 .592500 10.411731 .647950 1.144203 -.735851 -.339386 .748947 .594562 -.353595 .396354 -.031462 .880468 .433232 .033886 At 7 .580000 13.520411 .627827 .945557 -.965903 -.190429 .709823 .527078 -.318821 .480774 -.034954 .838365 .468948 .037544 Rn 8 .570000 14.629185 .615182 .981832 -1.038963 -.120456 .676697 .612279 -.344122 .549896 -.023760 .788337 .557746 .045488 """ gpaw-0.11.0.13004/gpaw/lcao/0000775000175000017500000000000012553644063015327 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/lcao/tools.py0000664000175000017500000005375512553643472017063 0ustar jensjjensj00000000000000from time import localtime import pickle import numpy as np from gpaw.utilities import pack from gpaw.utilities.tools import tri2full from gpaw.utilities.blas import rk, gemm from gpaw.basis_data import Basis from gpaw.setup import types2atomtypes from gpaw.coulomb import CoulombNEW as Coulomb from gpaw.mpi import world, rank, MASTER, serial_comm from gpaw import GPAW from ase.units import Hartree from ase.calculators.singlepoint import SinglePointCalculator def get_bf_centers(atoms, basis=None): calc = atoms.get_calculator() if calc is None or isinstance(calc, SinglePointCalculator): symbols = atoms.get_chemical_symbols() basis_a = types2atomtypes(symbols, basis, 'dzp') nao_a = [Basis(symbol, type).nao for symbol, type in zip(symbols, basis_a)] else: if not calc.initialized: calc.initialize(atoms) nao_a = [calc.wfs.setups[a].nao for a in range(len(atoms))] pos_ic = [] for pos, nao in zip(atoms.get_positions(), nao_a): pos_ic.extend(pos[None].repeat(nao, 0)) return np.array(pos_ic) def get_bfi(calc, a_list): """basis function indices from a list of atom indices. a_list: atom indices Use: get_bfi(calc, [0, 4]) gives the functions indices corresponding to atom 0 and 4""" bfs_list = [] for a in a_list: M = calc.wfs.basis_functions.M_a[a] bfs_list += range(M, M + calc.wfs.setups[a].nao) return bfs_list def get_bfi2(symbols, basis, a_list): """Same as get_bfi, but does not require an LCAO calc""" basis = types2atomtypes(symbols, basis, default='dzp') bfs_list = [] i = 0 for a, symbol in enumerate(symbols): nao = Basis(symbol, basis[a]).nao if a in a_list: bfs_list += range(i, i + nao) i += nao return bfs_list def get_mulliken(calc, a_list): """Mulliken charges from a list of atom indices (a_list).""" Q_a = {} for a in a_list: Q_a[a] = 0.0 for kpt in calc.wfs.kpt_u: S_MM = calc.wfs.S_qMM[kpt.q] nao = S_MM.shape[0] rho_MM = np.empty((nao, nao), calc.wfs.dtype) calc.wfs.calculate_density_matrix(kpt.f_n, kpt.C_nM, rho_MM) Q_M = np.dot(rho_MM, S_MM).diagonal() for a in a_list: M1 = calc.wfs.basis_functions.M_a[a] M2 = M1 + calc.wfs.setups[a].nao Q_a[a] += np.sum(Q_M[M1:M2]) return Q_a def get_realspace_hs(h_skmm, s_kmm, bzk_kc, weight_k, R_c=(0, 0, 0), direction='x', symmetry={'enabled': False}): from gpaw.symmetry import Symmetry from ase.dft.kpoints import get_monkhorst_pack_size_and_offset, \ monkhorst_pack if symmetry['point_group'] is True: raise NotImplementedError('Point group symmetry not implemented') nspins, nk, nbf = h_skmm.shape[:3] dir = 'xyz'.index(direction) transverse_dirs = np.delete([0, 1, 2], [dir]) dtype = float if len(bzk_kc) > 1 or np.any(bzk_kc[0] != [0, 0, 0]): dtype = complex kpts_grid = get_monkhorst_pack_size_and_offset(bzk_kc)[0] # kpts in the transport direction nkpts_p = kpts_grid[dir] bzk_p_kc = monkhorst_pack((nkpts_p,1,1))[:, 0] weight_p_k = 1. / nkpts_p # kpts in the transverse directions bzk_t_kc = monkhorst_pack(tuple(kpts_grid[transverse_dirs]) + (1, )) if not 'time_reversal' in symmetry: symmetry['time_reversal'] = True if symmetry['time_reversal'] is True: #XXX a somewhat ugly hack: # By default GPAW reduces inversion sym in the z direction. The steps # below assure reduction in the transverse dirs. # For now this part seems to do the job, but it may be written # in a smarter way in the future. symmetry = Symmetry([1], np.eye(3)) symmetry.prune_symmetries_atoms(np.zeros((1, 3))) ibzk_kc, ibzweight_k = symmetry.reduce(bzk_kc)[:2] ibzk_t_kc, weights_t_k = symmetry.reduce(bzk_t_kc)[:2] ibzk_t_kc = ibzk_t_kc[:, :2] nkpts_t = len(ibzk_t_kc) else: ibzk_kc = bzk_kc.copy() ibzk_t_kc = bzk_t_kc nkpts_t = len(bzk_t_kc) weights_t_k = [1. / nkpts_t for k in range(nkpts_t)] h_skii = np.zeros((nspins, nkpts_t, nbf, nbf), dtype) if s_kmm is not None: s_kii = np.zeros((nkpts_t, nbf, nbf), dtype) tol = 7 for j, k_t in enumerate(ibzk_t_kc): for k_p in bzk_p_kc: k = np.zeros((3,)) k[dir] = k_p k[transverse_dirs] = k_t kpoint_list = [list(np.round(k_kc, tol)) for k_kc in ibzk_kc] if list(np.round(k, tol)) not in kpoint_list: k = -k # inversion index = kpoint_list.index(list(np.round(k,tol))) h = h_skmm[:, index].conjugate() if s_kmm is not None: s = s_kmm[index].conjugate() k=-k else: # kpoint in the ibz index = kpoint_list.index(list(np.round(k, tol))) h = h_skmm[:, index] if s_kmm is not None: s = s_kmm[index] c_k = np.exp(2.j * np.pi * np.dot(k, R_c)) * weight_p_k h_skii[:, j] += c_k * h if s_kmm is not None: s_kii[j] += c_k * s if s_kmm is None: return ibzk_t_kc, weights_t_k, h_skii else: return ibzk_t_kc, weights_t_k, h_skii, s_kii def remove_pbc(atoms, h, s=None, d=0, centers_ic=None, cutoff=None): if h.ndim > 2: raise KeyError('You have to run remove_pbc for each ' 'spin/kpoint seperately.') L = atoms.cell[d, d] nao = len(h) dtype = h.dtype if centers_ic is None: centers_ic = get_bf_centers(atoms) # requires an attached LCAO calc ni = len(centers_ic) if nao != ni: assert nao == 2 * ni centers_ic = np.vstack((centers_ic, centers_ic)) centers_ic[ni:, d] += L if cutoff is None: cutoff = L - 1e-3 elif cutoff is None: cutoff = 0.5 * L - 1e-3 pos_i = centers_ic[:, d] for i in range(nao): dpos_i = abs(pos_i - pos_i[i]) mask_i = (dpos_i < cutoff).astype(dtype) h[i, :] *= mask_i h[:, i] *= mask_i if s is not None: s[i, :] *= mask_i s[:, i] *= mask_i def dump_hamiltonian(filename, atoms, direction=None, Ef=None): h_skmm, s_kmm = get_hamiltonian(atoms) if direction is not None: d = 'xyz'.index(direction) for s in range(atoms.calc.nspins): for k in range(atoms.calc.nkpts): if s==0: remove_pbc(atoms, h_skmm[s, k], s_kmm[k], d) else: remove_pbc(atoms, h_skmm[s, k], None, d) if atoms.calc.master: fd = open(filename, 'wb') pickle.dump((h_skmm, s_kmm), fd, 2) atoms_data = {'cell':atoms.cell, 'positions':atoms.positions, 'numbers':atoms.numbers, 'pbc':atoms.pbc} pickle.dump(atoms_data, fd, 2) calc_data ={'weight_k':atoms.calc.weight_k, 'ibzk_kc':atoms.calc.ibzk_kc} pickle.dump(calc_data, fd, 2) fd.close() world.barrier() def dump_hamiltonian_parallel(filename, atoms, direction=None, Ef=None): """ Dump the lcao representation of H and S to file(s) beginning with filename. If direction is x, y or z, the periodic boundary conditions will be removed in the specified direction. If the Fermi temperature is different from zero, the energy zero-point is taken as the Fermi level. Note: H and S are parallized over spin and k-points and is for now dumped into a number of pickle files. This may be changed into a dump to a single file in the future. """ if direction is not None: d = 'xyz'.index(direction) calc = atoms.calc wfs = calc.wfs nao = wfs.setups.nao nq = len(wfs.kpt_u) // wfs.nspins H_qMM = np.empty((wfs.nspins, nq, nao, nao), wfs.dtype) calc_data = {'k_q':{}, 'skpt_qc':np.empty((nq, 3)), 'weight_q':np.empty(nq)} S_qMM = wfs.S_qMM for kpt in wfs.kpt_u: calc_data['skpt_qc'][kpt.q] = calc.wfs.kd.ibzk_kc[kpt.k] calc_data['weight_q'][kpt.q] = calc.wfs.kd.weight_k[kpt.k] calc_data['k_q'][kpt.q] = kpt.k ## print ('Calc. H matrix on proc. %i: ' ## '(rk, rd, q, k) = (%i, %i, %i, %i)') % ( ## wfs.world.rank, wfs.kd.comm.rank, ## wfs.gd.domain.comm.rank, kpt.q, kpt.k) H_MM = wfs.eigensolver.calculate_hamiltonian_matrix(calc.hamiltonian, wfs, kpt) H_qMM[kpt.s, kpt.q] = H_MM tri2full(H_qMM[kpt.s, kpt.q]) if kpt.s==0: tri2full(S_qMM[kpt.q]) if direction is not None: remove_pbc(atoms, H_qMM[kpt.s, kpt.q], S_qMM[kpt.q], d) else: if direction is not None: remove_pbc(atoms, H_qMM[kpt.s, kpt.q], None, d) if calc.occupations.width > 0: if Ef is None: Ef = calc.occupations.get_fermi_level() else: Ef = Ef / Hartree H_qMM[kpt.s, kpt.q] -= S_qMM[kpt.q] * Ef if wfs.gd.comm.rank == 0: fd = file(filename+'%i.pckl' % wfs.kd.comm.rank, 'wb') H_qMM *= Hartree pickle.dump((H_qMM, S_qMM),fd , 2) pickle.dump(calc_data, fd, 2) fd.close() def get_lcao_hamiltonian(calc): """Return H_skMM, S_kMM on master, (None, None) on slaves. H is in eV.""" if calc.wfs.S_qMM is None: calc.wfs.set_positions(calc.get_atoms().get_scaled_positions() % 1) dtype = calc.wfs.dtype NM = calc.wfs.eigensolver.nao Nk = calc.wfs.kd.nibzkpts Ns = calc.wfs.nspins S_kMM = np.zeros((Nk, NM, NM), dtype) H_skMM = np.zeros((Ns, Nk, NM, NM), dtype) for kpt in calc.wfs.kpt_u: H_MM = calc.wfs.eigensolver.calculate_hamiltonian_matrix( calc.hamiltonian, calc.wfs, kpt) if kpt.s == 0: S_kMM[kpt.k] = calc.wfs.S_qMM[kpt.q] tri2full(S_kMM[kpt.k]) H_skMM[kpt.s, kpt.k] = H_MM * Hartree tri2full(H_skMM[kpt.s, kpt.k]) calc.wfs.kd.comm.sum(S_kMM, MASTER) calc.wfs.kd.comm.sum(H_skMM, MASTER) if rank == MASTER: return H_skMM, S_kMM else: return None, None def get_lead_lcao_hamiltonian(calc, direction='x'): H_skMM, S_kMM = get_lcao_hamiltonian(calc) if rank == MASTER: return lead_kspace2realspace(H_skMM, S_kMM, bzk_kc=calc.wfs.kd.bzk_kc, weight_k=calc.wfs.kd.weight_k, direction=direction, symmetry=calc.input_parameters['symmetry']) else: return None, None, None, None def lead_kspace2realspace(h_skmm, s_kmm, bzk_kc, weight_k, direction='x', symmetry={'point_group': False}): """Convert a k-dependent Hamiltonian to tight-binding onsite and coupling. For each transverse k-point: Convert k-dependent (in transport direction) Hamiltonian representing a lead to a real space tight-binding Hamiltonian of double size representing two principal layers and the coupling between. """ dir = 'xyz'.index(direction) if symmetry['point_group'] is True: raise NotImplementedError R_c = [0, 0, 0] ibz_t_kc, weight_t_k, h_skii, s_kii = get_realspace_hs( h_skmm, s_kmm, bzk_kc, weight_k, R_c, direction, symmetry) R_c[dir] = 1 h_skij, s_kij = get_realspace_hs( h_skmm, s_kmm, bzk_kc, weight_k, R_c, direction, symmetry)[-2:] nspins, nk, nbf = h_skii.shape[:-1] h_skmm = np.zeros((nspins, nk, 2 * nbf, 2 * nbf), h_skii.dtype) s_kmm = np.zeros((nk, 2 * nbf, 2 * nbf), h_skii.dtype) h_skmm[:, :, :nbf, :nbf] = h_skmm[:, :, nbf:, nbf:] = h_skii h_skmm[:, :, :nbf, nbf:] = h_skij h_skmm[:, :, nbf:, :nbf] = h_skij.swapaxes(2, 3).conj() s_kmm[:, :nbf, :nbf] = s_kmm[:, nbf:, nbf:] = s_kii s_kmm[:, :nbf, nbf:] = s_kij s_kmm[:, nbf:, :nbf] = s_kij.swapaxes(1,2).conj() return ibz_t_kc, weight_t_k, h_skmm, s_kmm def zeta_pol(basis): """Get number of zeta func. and polarization func. indices in Basis.""" zeta = [] pol = [] for bf in basis.bf_j: if 'polarization' in bf.type: pol.append(2 * bf.l + 1) else: zeta.append(2 * bf.l + 1) zeta = sum(zeta) pol = sum(pol) assert zeta + pol == basis.nao return zeta, pol def basis_subset(symbol, largebasis, smallbasis): """Title. Determine which basis function indices from ``largebasis`` are also present in smallbasis. """ blarge = Basis(symbol, largebasis) zeta_large, pol_large = zeta_pol(blarge) bsmall = Basis(symbol, smallbasis) zeta_small, pol_small = zeta_pol(bsmall) assert zeta_small <= zeta_large assert pol_small <= pol_large insmall = np.zeros(blarge.nao, bool) insmall[:zeta_small] = True insmall[zeta_large:zeta_large + pol_small] = True return insmall def basis_subset2(symbols, largebasis='dzp', smallbasis='sz'): """Same as basis_subset, but for an entire list of atoms.""" largebasis = types2atomtypes(symbols, largebasis, default='dzp') smallbasis = types2atomtypes(symbols, smallbasis, default='sz') mask = [] for symbol, large, small in zip(symbols, largebasis, smallbasis): mask.extend(basis_subset(symbol, large, small)) return np.asarray(mask, bool) def collect_orbitals(a_xo, coords, root=0): """Collect array distributed over orbitals to root-CPU. Input matrix has last axis distributed amongst CPUs, return is None on slaves, and the collected array on root. The distribution can be uneven amongst CPUs. The list coords gives the number of values for each CPU. """ a_xo = np.ascontiguousarray(a_xo) if world.size == 1: return a_xo # All slaves send their piece to ``root``: # There can be several sends before the corresponding receives # are posted, so use syncronous send here if world.rank != root: world.ssend(a_xo, root, 112) return None # On root, put the subdomains from the slaves into the big array # for the whole domain on root: xshape = a_xo.shape[:-1] Norb2 = sum(coords) # total number of orbital indices a_xO = np.empty(xshape + (Norb2,), a_xo.dtype) o = 0 for rank, norb in enumerate(coords): if rank != root: tmp_xo = np.empty(xshape + (norb,), a_xo.dtype) world.receive(tmp_xo, rank, 112) a_xO[..., o:o + norb] = tmp_xo else: a_xO[..., o:o + norb] = a_xo o += norb return a_xO def makeU(gpwfile='grid.gpw', orbitalfile='w_wG__P_awi.pckl', rotationfile='eps_q__U_pq.pckl', tolerance=1e-5, writeoptimizedpairs=False, dppname='D_pp.pckl', S_w=None): # S_w: None or diagonal of overlap matrix. In the latter case # the optimized and truncated pair orbitals are obtained from # normalized (to 1) orbitals. # # Tolerance is used for truncation of optimized pairorbitals #calc = GPAW(gpwfile, txt=None) from gpaw import GPAW from gpaw.mpi import world, MASTER calc = GPAW(gpwfile, txt='pairorb.txt') # XXX gd = calc.wfs.gd setups = calc.wfs.setups myatoms = calc.density.D_asp.keys() del calc # Load orbitals on master and distribute to slaves if world.rank == MASTER: wglobal_wG, P_awi = pickle.load(open(orbitalfile, 'rb')) Nw = len(wglobal_wG) print('Estimated total (serial) mem usage: %0.3f GB' % ( np.prod(gd.N_c) * Nw**2 * 8 / 1024.**3)) else: wglobal_wG = None Nw = 0 Nw = gd.comm.sum(Nw) #distribute Nw to all nodes w_wG = gd.empty(n=Nw) gd.distribute(wglobal_wG, w_wG) del wglobal_wG # Make pairorbitals f_pG = gd.zeros(n=Nw**2) Np = len(f_pG) for p, (w1, w2) in enumerate(np.ndindex(Nw, Nw)): np.multiply(w_wG[w1], w_wG[w2], f_pG[p]) del w_wG assert f_pG.flags.contiguous # Make pairorbital overlap (lower triangle only) D_pp = np.zeros((Nw**2, Nw**2)) rk(gd.dv, f_pG, 0., D_pp) # Add atomic corrections to pairorbital overlap for a in myatoms: if setups[a].type != 'ghost': P_pp = np.array([pack(np.outer(P_awi[a][w1], P_awi[a][w2])) for w1, w2 in np.ndindex(Nw, Nw)]) I4_pp = setups[a].four_phi_integrals() A = np.zeros((len(I4_pp), len(P_pp))) gemm(1.0, P_pp, I4_pp, 0.0, A, 't') gemm(1.0, A, P_pp, 1.0, D_pp) #D_pp += np.dot(P_pp, np.dot(I4_pp, P_pp.T)) # Summ all contributions to master gd.comm.sum(D_pp, MASTER) if world.rank == MASTER: if S_w is not None: print('renormalizing pairorb overlap matrix (D_pp)') S2 = np.sqrt(S_w) for pa, (wa1, wa2) in enumerate(np.ndindex(Nw, Nw)): for pb, (wb1, wb2) in enumerate(np.ndindex(Nw, Nw)): D_pp[pa, pb] /= S2[wa1] * S2[wa2] * S2[wb1] * S2[wb2] D_pp.dump(dppname) # XXX if the diagonalization below (on MASTER only) # fails, then one can always restart the stuff # below using only the stored D_pp matrix # Determine eigenvalues and vectors on master only eps_q, U_pq = np.linalg.eigh(D_pp, UPLO='L') del D_pp indices = np.argsort(-eps_q.real) eps_q = np.ascontiguousarray(eps_q.real[indices]) U_pq = np.ascontiguousarray(U_pq[:, indices]) # Truncate indices = eps_q > tolerance U_pq = np.ascontiguousarray(U_pq[:, indices]) eps_q = np.ascontiguousarray(eps_q[indices]) # Dump to file pickle.dump((eps_q, U_pq), open(rotationfile, 'wb'), 2) if writeoptimizedpairs is not False: assert world.size == 1 # works in parallel if U and eps are broadcast Uisq_qp = (U_pq / np.sqrt(eps_q)).T.copy() g_qG = gd.zeros(n=len(eps_q)) gemm(1.0, f_pG, Uisq_qp, 0.0, g_qG) g_qG = gd.collect(g_qG) if world.rank == MASTER: P_app = dict([(a, np.array([pack(np.outer(P_wi[w1], P_wi[w2]), tolerance=1e3) for w1, w2 in np.ndindex(Nw, Nw)])) for a, P_wi in P_awi.items()]) P_aqp = dict([(a, np.dot(Uisq_qp, P_pp)) for a, P_pp in P_app.items()]) pickle.dump((g_qG, P_aqp), open(writeoptimizedpairs, 'wb'), 2) def makeV(gpwfile='grid.gpw', orbitalfile='w_wG__P_awi.pckl', rotationfile='eps_q__U_pq.pckl', coulombfile='V_qq.pckl', log='V_qq.log', fft=False): if isinstance(log, str) and world.rank == MASTER: log = open(log, 'w') # Extract data from files calc = GPAW(gpwfile, txt=None, communicator=serial_comm) spos_ac = calc.get_atoms().get_scaled_positions() % 1.0 coulomb = Coulomb(calc.wfs.gd, calc.wfs.setups, spos_ac, fft) w_wG, P_awi = pickle.load(open(orbitalfile, 'rb')) eps_q, U_pq = pickle.load(open(rotationfile, 'rb')) del calc # Make rotation matrix divided by sqrt of norm Nq = len(eps_q) Np = len(U_pq) Ni = len(w_wG) Uisq_iqj = (U_pq/np.sqrt(eps_q)).reshape(Ni, Ni, Nq).swapaxes(1, 2).copy() del eps_q, U_pq # Determine number of opt. pairorb on each cpu Ncpu = world.size nq, R = divmod(Nq, Ncpu) nq_r = nq * np.ones(Ncpu, int) if R > 0: nq_r[-R:] += 1 # Determine number of opt. pairorb on this cpu nq1 = nq_r[world.rank] q1end = nq_r[:world.rank + 1].sum() q1start = q1end - nq1 V_qq = np.zeros((Nq, nq1), float) def make_optimized(qstart, qend): g_qG = np.zeros((qend - qstart,) + w_wG.shape[1:], float) P_aqp = {} for a, P_wi in P_awi.items(): ni = P_wi.shape[1] nii = ni * (ni + 1) // 2 P_aqp[a] = np.zeros((qend - qstart, nii), float) for w1, w1_G in enumerate(w_wG): U = Uisq_iqj[w1, qstart: qend].copy() gemm(1., w1_G * w_wG, U, 1.0, g_qG) for a, P_wi in P_awi.items(): P_wp = np.array([pack(np.outer(P_wi[w1], P_wi[w2])) for w2 in range(Ni)]) gemm(1., P_wp, U, 1.0, P_aqp[a]) return g_qG, P_aqp g1_qG, P1_aqp = make_optimized(q1start, q1end) for block, nq2 in enumerate(nq_r): if block == world.rank: g2_qG, P2_aqp = g1_qG, P1_aqp q2start, q2end = q1start, q1end else: q2end = nq_r[:block + 1].sum() q2start = q2end - nq2 g2_qG, P2_aqp = make_optimized(q2start, q2end) for q1, q2 in np.ndindex(nq1, nq2): P1_ap = dict([(a, P_qp[q1]) for a, P_qp in P1_aqp.items()]) P2_ap = dict([(a, P_qp[q2]) for a, P_qp in P2_aqp.items()]) V_qq[q2 + q2start, q1] = coulomb.calculate(g1_qG[q1], g2_qG[q2], P1_ap, P2_ap) if q2 == 0 and world.rank == MASTER: T = localtime() log.write( 'Block %i/%i is %4.1f percent done at %02i:%02i:%02i\n' % ( block + 1, world.size, 100.0 * q1 / nq1, T[3], T[4], T[5])) log.flush() # Collect V_qq array on master node if world.rank == MASTER: T = localtime() log.write('Starting collect at %02i:%02i:%02i\n' % ( T[3], T[4], T[5])) log.flush() V_qq = collect_orbitals(V_qq, coords=nq_r, root=MASTER) if world.rank == MASTER: # V can be slightly asymmetric due to numerics V_qq = 0.5 * (V_qq + V_qq.T) V_qq.dump(coulombfile) T = localtime() log.write('Finished at %02i:%02i:%02i\n' % ( T[3], T[4], T[5])) log.flush() gpaw-0.11.0.13004/gpaw/lcao/newoverlap.py0000664000175000017500000001174112553643472020072 0ustar jensjjensj00000000000000import numpy as np from ase import Atoms from ase.calculators.neighborlist import NeighborList from gpaw.lcao.overlap import AtomicDisplacement, TwoCenterIntegralCalculator from gpaw.utilities.partition import EvenPartitioning class DistsAndOffsets: def __init__(self, nl, spos_ac, cell_cv): #assert nl.bothways r_and_offset_aao = {} def add(a1, a2, R_c, offset): r_and_offset_aao.setdefault((a1, a2), []).append((R_c, offset)) for a1, spos1_c in enumerate(spos_ac): a2_a, offsets = nl.get_neighbors(a1) for a2, offset in zip(a2_a, offsets): spos2_c = spos_ac[a2] + offset R_c = np.dot(spos2_c - spos1_c, cell_cv) add(a1, a2, R_c, offset) if a1 != a2 or offset.any(): add(a2, a1, -R_c, -offset) self.r_and_offset_aao = r_and_offset_aao def get(self, a1, a2): R_ca_and_offset_a = self.r_and_offset_aao.get((a1, a2)) return R_ca_and_offset_a def newoverlap(wfs, spos_ac): assert wfs.ksl.block_comm.size == wfs.gd.comm.size * wfs.bd.comm.size even_part = EvenPartitioning(wfs.gd.comm, #wfs.ksl.block_comm, len(wfs.atom_partition.rank_a)) atom_partition = even_part.as_atom_partition() tci = wfs.tci gd = wfs.gd kd = wfs.kd nq = len(kd.ibzk_qc) # New neighbor list because we want it "both ways", heh. Or do we? neighbors = NeighborList(tci.cutoff_a, skin=0, sorted=True, self_interaction=True, bothways=False) atoms = Atoms('X%d' % len(tci.cutoff_a), cell=gd.cell_cv, pbc=gd.pbc_c) atoms.set_scaled_positions(spos_ac) neighbors.update(atoms) # XXX pcutoff_a = [] phicutoff_a = [] for setup in wfs.setups: if setup.pt_j: pcutoff = max([pt.get_cutoff() for pt in setup.pt_j]) else: pcutoff = 0.0 if setup.phit_j: phicutoff = max([phit.get_cutoff() for phit in setup.phit_j]) else: phicutoff = 0.0 pcutoff_a.append(pcutoff) phicutoff_a.append(phicutoff) # Calculate the projector--basis function overlaps: # # a1 ~a1 # P = < p | Phi > , # i mu i mu # # i.e. projector is on a1 and basis function is on what we will call a2. overlapcalc = TwoCenterIntegralCalculator(wfs.kd.ibzk_qc, derivative=False) P_aaqim = {} # keys: (a1, a2). Values: matrix blocks dists_and_offsets = DistsAndOffsets(neighbors, spos_ac, gd.cell_cv) #ng = 2**extra_parameters.get('log2ng', 10) #transformer = FourierTransformer(rcmax, ng) #tsoc = TwoSiteOverlapCalculator(transformer) #msoc = ManySiteOverlapCalculator(tsoc, I_a, I_a) msoc = wfs.tci.msoc phit_Ij = [setup.phit_j for setup in tci.setups_I] l_Ij = [] for phit_j in phit_Ij: l_Ij.append([phit.get_angular_momentum_number() for phit in phit_j]) pt_l_Ij = [setup.l_j for setup in tci.setups_I] pt_Ij = [setup.pt_j for setup in tci.setups_I] phit_Ijq = msoc.transform(phit_Ij) pt_Ijq = msoc.transform(pt_Ij) #self.Theta_expansions = msoc.calculate_expansions(l_Ij, phit_Ijq, # l_Ij, phit_Ijq) #self.T_expansions = msoc.calculate_kinetic_expansions(l_Ij, phit_Ijq) P_expansions = msoc.calculate_expansions(pt_l_Ij, pt_Ijq, l_Ij, phit_Ijq) P_neighbors_a = {} for a1 in atom_partition.my_indices: for a2 in range(len(wfs.setups)): R_ca_and_offset_a = dists_and_offsets.get(a1, a2) if R_ca_and_offset_a is None: # No overlap between a1 and a2 continue maxdistance = pcutoff_a[a1] + phicutoff_a[a2] expansion = P_expansions.get(a1, a2) P_qim = expansion.zeros((nq,), dtype=wfs.dtype) disp = None for R_c, offset in R_ca_and_offset_a: r = np.linalg.norm(R_c) if r > maxdistance: continue # Below lines are meant to make use of symmetry. Will not # be relevant for P. #remainder = (a1 + a2) % 2 #if a1 < a2 and not remainder: # continue # if a1 > a2 and remainder: # continue phases = overlapcalc.phaseclass(overlapcalc.ibzk_qc, offset) disp = AtomicDisplacement(None, a1, a2, R_c, offset, phases) disp.evaluate_overlap(expansion, P_qim) if disp is not None: # there was at least one non-zero overlap assert (a1, a2) not in P_aaqim P_aaqim[(a1, a2)] = P_qim P_neighbors_a.setdefault(a1, []).append(a2) return P_neighbors_a, P_aaqim gpaw-0.11.0.13004/gpaw/lcao/generate_ngto_augmented.py0000664000175000017500000001265712553643472022571 0ustar jensjjensj00000000000000from __future__ import print_function import os import re import numpy as np from gpaw.atom.basis import BasisMaker from gpaw.atom.basis import QuasiGaussian from gpaw.atom.configurations import parameters, parameters_extra from gpaw.basis_data import BasisFunction from gpaw.mpi import world # Module for generating basis sets that compose of usual basis sets # augmented with Gaussian type orbital (GTO). # # GTOs are truncated and represented numerically. def read_gbs(fname): """Read gbs file. This reads only the first element/atom from the file as separated with line beginning with '*'. """ gto_k = [] description = '' f = open(fname, 'r') line_i = f.readlines() f.close() i = 0 Ni = len(line_i) while True: line = line_i[i].strip() if line == '' or line[0] == '*': pass elif line[0] == '!': description += '%s\n' % line[1:].strip() else: break i += 1 description = description.strip() atom = line_i[i].strip().split()[0] i += 1 while i < Ni: line = line_i[i] if line[0] == '*': break i += 1 d = line.split() l = 'spdfghi'.index(d[0].lower()) Nj = int(d[1]) alpha_j = [] coeff_j = [] for _ in range(Nj): line = line_i[i] d = line.split() alpha = float(d[0]) coeff = float(d[1]) alpha_j.append(alpha) coeff_j.append(coeff) i += 1 gto_k.append({'l': l, 'alpha_j': alpha_j, 'coeff_j': coeff_j}) return atom, description, gto_k def get_ngto(rgd, l, alpha, rcut): gaussian = QuasiGaussian(alpha, rcut) psi_g = gaussian(rgd.r_g) * rgd.r_g**l norm = np.sum(rgd.dr_g * (rgd.r_g * psi_g) **2) ** .5 psi_g /= norm return psi_g def add_ngto(basis, l, alpha, tol, label): rgd = basis.get_grid_descriptor() rmax = rgd.r_g[-1] # Get NGTO with the initial (large) rcut=rmax psiref_g = get_ngto(rgd, l, alpha, rmax) # Make rcut smaller # Guess initial rcut where we are close to the tolerance i = np.where(psiref_g > tol)[0][-1] rcut = rgd.r_g[i] psi_g = get_ngto(rgd, l, alpha, rcut) err = np.max(np.absolute(psi_g - psiref_g)) # Increase/decrease rcut to find the smallest rcut # that yields error within the tolerance if err > tol: # Increase rcut -> decrease err for i in range(i, basis.ng): rcut = rgd.r_g[i] psi_g = get_ngto(rgd, l, alpha, rcut) err = np.max(np.absolute(psi_g - psiref_g)) if err < tol: break else: # Decrease rcut -> increase err for i in range(i, 0, -1): rcut = rgd.r_g[i] psi_g = get_ngto(rgd, l, alpha, rcut) err = np.max(np.absolute(psi_g - psiref_g)) if err > tol: i += 1 break # Construct NGTO with the found rcut rcut = rgd.r_g[i] psi_g = get_ngto(rgd, l, alpha, rcut) # Change norm (maybe unnecessary) psi_g = psi_g[:(i + 1)] * 0.5 # Create associated basis function bf = BasisFunction(l, rcut, psi_g, label) basis.bf_j.append(bf) def do_nao_ngto_basis(atom, xc, naobasis, gbsfname, label): # Read Gaussians atomgbs, descriptiongbs, gto_k = read_gbs(gbsfname) assert atom == atomgbs # Generate nao basis assert naobasis == 'sz' # Choose basis sets without semi-core states XXXXXX if atom == 'Ag': label = '11.%s' % label p = parameters_extra else: p = parameters bm = BasisMaker(atom, label, run=False, gtxt=None, xc=xc) bm.generator.run(write_xml=False, use_restart_file=False, **p[atom]) basis = bm.generate(1, 0, txt=None) # Increase basis function max radius rmax = 100.0 basis.ng = int(rmax / basis.d) + 1 # Add NGTOs tol = 0.001 description = [] msg = 'Augmented with NGTOs' description.append(msg) description.append('=' * len(msg)) description.append('') msg = 'GTOs from file %s' % os.path.basename(gbsfname) description.append(msg) description.append('-' * len(msg)) description.append(descriptiongbs) description.append('') description.append('NGTO truncation tolerance: %f' % tol) description.append('Functions: NGTO(l,alpha)') for gto in gto_k: l = gto['l'] assert len(gto['alpha_j']) == 1, \ 'Only non-contracted GTOs supported' alpha = gto['alpha_j'][0] ngtolabel = 'NGTO(%s,%.7f)' % ('spdfghi'[l], alpha) description.append(' ' + ngtolabel) add_ngto(basis, l, alpha, tol, ngtolabel) basis.generatordata += '\n\n' + '\n'.join(description) basis.write_xml() def main(): xc = 'PBE' # Process all gbs files fname_i = [fname for fname in sorted(os.listdir('.')) if fname.endswith('.gbs')] for i, fname in enumerate(fname_i): if i % world.size != world.rank: continue m = re.match('(?P\w+)-(?P

nn' n n' /___ n i ii' i' n' aii' Fills in the lower part of *A_nn*, but only on domain and band masters. Parameters: psit_nG: ndarray Set of vectors in which the matrix elements are evaluated. P_ani: dict Dictionary of projector overlap integrals P_ni = . A: function Functional form of the operator A which works on psit_nG. Must accept and return an ndarray of the same shape as psit_nG. dA: function Operator which works on | phi_i >. Must accept atomic index a and P_ni and return an ndarray with the same shape as P_ni, thus representing P_ni multiplied by dA_ii. """ band_comm = self.bd.comm domain_comm = self.gd.comm block_comm = self.block_comm B = band_comm.size J = self.nblocks N = self.bd.mynbands M = int(np.ceil(N / float(J))) if self.A_nn is None: self.allocate_arrays() A_NN = self.A_nn if B == 1 and J == 1: # Simple case: Apsit_nG = A(psit_nG) self.gd.integrate(psit_nG, Apsit_nG, hermitian=self.hermitian, _transposed_result=A_NN) for a, P_ni in P_ani.items(): gemm(1.0, P_ni, dA(a, P_ni), 1.0, A_NN, 'c') domain_comm.sum(A_NN, 0) return self.bmd.redistribute_output(A_NN) # Now it gets nasty! We parallelize over B groups of bands and # each band group is blocked in J smaller slices (less memory). Q = self.Q # Buffer for storage of blocks of calculated matrix elements. if B == 1: A_qnn = A_NN.reshape((1, N, N)) else: A_qnn = self.A_qnn # Buffers for send/receive of operated-on versions of P_ani's. sbuf_nI = rbuf_nI = None if P_ani: sbuf_nI = np.hstack([dA(a, P_ni) for a, P_ni in P_ani.items()]) sbuf_nI = np.ascontiguousarray(sbuf_nI) if B > 1: rbuf_nI = np.empty_like(sbuf_nI) work1_xG = reshape(self.work1_xG, (self.X,) + psit_nG.shape[1:]) work2_xG = reshape(self.work2_xG, (self.X,) + psit_nG.shape[1:]) # Because of the amount of communication involved, we need to # be syncronized up to this point but only on the 1D band_comm # communication ring band_comm.barrier() while M * J >= N + M: # remove extra slice(s) J -= 1 assert 0 < J * M < N + M for j in range(J): n1 = j * M n2 = n1 + M if n2 > N: n2 = N M = n2 - n1 psit_mG = psit_nG[n1:n2] temp_mG = A(psit_mG) sbuf_mG = temp_mG[:M] # necessary only for last slice rbuf_mG = work2_xG[:M] cycle_P_ani = (j == J - 1 and P_ani) for q in range(Q): A_nn = A_qnn[q] A_mn = A_nn[n1:n2] # Start sending currently buffered kets to rank below # and receiving next set of kets from rank above us. # If we're at the last slice, start cycling P_ani too. if q < Q - 1: self._initialize_cycle(sbuf_mG, rbuf_mG, sbuf_nI, rbuf_nI, cycle_P_ani) # Calculate pseudo-braket contributions for the current slice # of bands in the current mynbands x mynbands matrix block. # The special case may no longer be valid when. Better to be # conservative, than to risk it. Moreover, this special case # seems is an accident waiting to happen. Always doing the # more general case is safer. # if q == 0 and self.hermitian and not self.bd.strided: # # Special case, we only need the lower part: # self._pseudo_braket(psit_nG[:n2], sbuf_mG, A_mn[:, :n2]) # else: self.gd.integrate(psit_nG, sbuf_mG, hermitian=False, _transposed_result=A_mn) # If we're at the last slice, add contributions from P_ani's. if cycle_P_ani: I1 = 0 for P_ni in P_ani.values(): I2 = I1 + P_ni.shape[1] gemm(1.0, P_ni, sbuf_nI[:, I1:I2], 1.0, A_nn, 'c') I1 = I2 # Wait for all send/receives to finish before next iteration. # Swap send and receive buffer such that next becomes current. # If we're at the last slice, also finishes the P_ani cycle. if q < Q - 1: sbuf_mG, rbuf_mG, sbuf_nI, rbuf_nI = self._finish_cycle( sbuf_mG, rbuf_mG, sbuf_nI, rbuf_nI, cycle_P_ani) # First iteration was special because we had the ket to ourself if q == 0: rbuf_mG = work1_xG[:M] domain_comm.sum(A_qnn, 0) if B == 1: return self.bmd.redistribute_output(A_NN) if domain_comm.rank == 0: self.bmd.assemble_blocks(A_qnn, A_NN, self.hermitian) # Because of the amount of communication involved, we need to # be syncronized up to this point. block_comm.barrier() return self.bmd.redistribute_output(A_NN) def matrix_multiply(self, C_NN, psit_nG, P_ani=None, out_nG=None): """Calculate new linear combinations of wave functions. Results will be put in the *P_ani* dict and a new psit_nG returned:: __ __ ~ \ ~ ~a ~ \ ~a ~ psi <-- ) C psi and

<-- ) C

n /__ nn' n' i n /__ nn' i n' n' n' Parameters: C_NN: ndarray Matrix representation of the requested linear combinations. Even with a hermitian operator, this matrix need not be self-adjoint. However, unlike the results from calculate_matrix_elements, it is assumed that all matrix elements are filled in (use e.g. tri2full). psit_nG: ndarray Set of vectors in which the matrix elements are evaluated. P_ani: dict Dictionary of projector overlap integrals P_ni = . """ if self.A_nn is None: self.allocate_arrays() band_comm = self.bd.comm B = band_comm.size J = self.nblocks N = self.bd.mynbands C_NN = self.bmd.redistribute_input(C_NN) if B == 1 and J == 1: # Simple case: work_nG = reshape(self.work1_xG, psit_nG.shape) if out_nG is None: out_nG = work_nG out_nG[:] = 117 # gemm may not like nan's elif out_nG is psit_nG: work_nG[:] = psit_nG psit_nG = work_nG self.gd.gemm(1.0, psit_nG, C_NN, 0.0, out_nG) if P_ani: for P_ni in P_ani.values(): gemm(1.0, P_ni.copy(), C_NN, 0.0, P_ni) return out_nG # Now it gets nasty! We parallelize over B groups of bands and # each grid chunk is divided in J smaller slices (less memory). Q = B # always non-hermitian XXX rank = band_comm.rank shape = psit_nG.shape psit_nG = psit_nG.reshape(N, -1) G = psit_nG.shape[1] # number of grid-points g = int(np.ceil(G / float(J))) # Buffers for send/receive of pre-multiplication versions of P_ani's. sbuf_nI = rbuf_nI = None if P_ani: sbuf_nI = np.hstack([P_ni for P_ni in P_ani.values()]) sbuf_nI = np.ascontiguousarray(sbuf_nI) if B > 1: rbuf_nI = np.empty_like(sbuf_nI) # Because of the amount of communication involved, we need to # be syncronized up to this point but only on the 1D band_comm # communication ring band_comm.barrier() while g * J >= G + g: # remove extra slice(s) J -= 1 assert 0 < g * J < G + g work1_xG = reshape(self.work1_xG, (self.X,) + psit_nG.shape[1:]) work2_xG = reshape(self.work2_xG, (self.X,) + psit_nG.shape[1:]) for j in range(J): G1 = j * g G2 = G1 + g if G2 > G: G2 = G g = G2 - G1 sbuf_ng = reshape(work1_xG, (N, g)) rbuf_ng = reshape(work2_xG, (N, g)) sbuf_ng[:] = psit_nG[:, G1:G2] beta = 0.0 cycle_P_ani = (j == J - 1 and P_ani) for q in range(Q): # Start sending currently buffered kets to rank below # and receiving next set of kets from rank above us. # If we're at the last slice, start cycling P_ani too. if q < Q - 1: self._initialize_cycle(sbuf_ng, rbuf_ng, sbuf_nI, rbuf_nI, cycle_P_ani) # Calculate wave-function contributions from the current slice # of grid data by the current mynbands x mynbands matrix block. C_nn = self.bmd.extract_block(C_NN, (rank + q) % B, rank) self.gd.gemm(1.0, sbuf_ng, C_nn, beta, psit_nG[:, G1:G2]) # If we're at the last slice, add contributions to P_ani's. if cycle_P_ani: I1 = 0 for P_ni in P_ani.values(): I2 = I1 + P_ni.shape[1] gemm(1.0, sbuf_nI[:, I1:I2], C_nn, beta, P_ni) I1 = I2 # Wait for all send/receives to finish before next iteration. # Swap send and receive buffer such that next becomes current. # If we're at the last slice, also finishes the P_ani cycle. if q < Q - 1: sbuf_ng, rbuf_ng, sbuf_nI, rbuf_nI = self._finish_cycle( sbuf_ng, rbuf_ng, sbuf_nI, rbuf_nI, cycle_P_ani) # First iteration was special because we initialized the kets if q == 0: beta = 1.0 psit_nG.shape = shape return psit_nG gpaw-0.11.0.13004/gpaw/setup_data.py0000664000175000017500000005357012553643472017131 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. from __future__ import print_function import hashlib import os import re import sys import xml.sax from glob import glob from math import sqrt, pi, factorial as fac import numpy as np from ase.data import atomic_names from ase.units import Bohr, Hartree from gpaw import setup_paths from gpaw.spline import Spline from gpaw.xc.pawcorrection import PAWXCCorrection from gpaw.mpi import broadcast from gpaw.atom.radialgd import AERadialGridDescriptor try: import gzip except ImportError: has_gzip = False else: has_gzip = True class SetupData: """Container class for persistent setup attributes and XML I/O.""" def __init__(self, symbol, xcsetupname, name='paw', readxml=True, zero_reference=False, world=None): self.symbol = symbol self.setupname = xcsetupname self.name = name self.zero_reference = zero_reference # Default filename if this setup is written if name is None or name == 'paw': self.stdfilename = '%s.%s' % (symbol, self.setupname) else: self.stdfilename = '%s.%s.%s' % (symbol, name, self.setupname) self.filename = None # full path if this setup was loaded from file self.fingerprint = None # hash value of file data if applicable self.Z = None self.Nc = None self.Nv = None # Quantum numbers, energies self.n_j = [] self.l_j = [] self.l_orb_j = self.l_j # pointer to same list! self.f_j = [] self.eps_j = [] self.e_kin_jj = None # - self.rgd = None self.rcgauss = None # For compensation charge expansion functions # State identifier, like "X-2s" or "X-p1", where X is chemical symbol, # for bound and unbound states self.id_j = [] # Partial waves, projectors self.phi_jg = [] self.phit_jg = [] self.pt_jg = [] self.rcut_j = [] # Densities, potentials self.nc_g = None self.nct_g = None self.nvt_g = None self.vbar_g = None # Kinetic energy densities of core electrons self.tauc_g = None self.tauct_g = None # Reference energies self.e_kinetic = 0.0 self.e_xc = 0.0 self.e_electrostatic = 0.0 self.e_total = 0.0 self.e_kinetic_core = 0.0 # Generator may store description of setup in this string self.generatorattrs = [] self.generatordata = '' # Optional quantities, normally not used self.X_p = None self.ExxC = None self.extra_xc_data = {} self.phicorehole_g = None self.fcorehole = 0.0 self.lcorehole = None self.ncorehole = None self.core_hole_e = None self.core_hole_e_kin = None self.has_corehole = False # Parameters for zero-potential: self.l0 = None self.e0 = None self.r0 = None self.nderiv0 = None self.orbital_free = False # orbital-free DFT if readxml: self.read_xml(world=world) def append(self, n, l, f, e, rcut, phi_g, phit_g, pt_g): self.n_j.append(n) self.l_j.append(l) self.f_j.append(f) self.eps_j.append(e) self.rcut_j.append(rcut) self.phi_jg.append(phi_g) self.phit_jg.append(phit_g) self.pt_jg.append(pt_g) def read_xml(self, source=None, world=None): PAWXMLParser(self).parse(source=source, world=world) nj = len(self.l_j) self.e_kin_jj.shape = (nj, nj) def is_compatible(self, xc): return xc.get_setup_name() == self.setupname def print_info(self, text, setup): if self.phicorehole_g is None: text(self.symbol + '-setup:') else: text('%s-setup (%.1f core hole):' % (self.symbol, self.fcorehole)) text(' name :', atomic_names[self.Z]) text(' id :', self.fingerprint) text(' Z :', self.Z) text(' valence:', self.Nv) if self.phicorehole_g is None: text(' core : %d' % self.Nc) else: text(' core : %.1f' % self.Nc) text(' charge :', self.Z - self.Nv - self.Nc) if setup.HubU is not None: text(' Hubbard U: %f eV (l=%d, scale=%s)' % (setup.HubU * Hartree, setup.Hubl, bool(setup.Hubs))) text(' file :', self.filename) text((' cutoffs: %4.2f(comp), %4.2f(filt), %4.2f(core),' ' lmax=%d' % (sqrt(10) * self.rcgauss * Bohr, # XXX is this really true? I don't think this is # actually the cutoff of the compensation charges setup.rcutfilter * Bohr, setup.rcore * Bohr, setup.lmax))) text(' valence states:') text(' energy radius') j = 0 for n, l, f, eps in zip(self.n_j, self.l_j, self.f_j, self.eps_j): if n > 0: f = '(%.2f)' % f text(' %d%s%-5s %7.3f %5.3f' % ( n, 'spdf'[l], f, eps * Hartree, self.rcut_j[j] * Bohr)) else: text(' *%s %7.3f %5.3f' % ( 'spdf'[l], eps * Hartree, self.rcut_j[j] * Bohr)) j += 1 text() def create_compensation_charge_functions(self, lmax): """Create Gaussians used to expand compensation charges.""" rcgauss = self.rcgauss g_lg = self.rgd.zeros(lmax + 1) r_g = self.rgd.r_g g_lg[0] = 4 / rcgauss**3 / sqrt(pi) * np.exp(-(r_g / rcgauss)**2) for l in range(1, lmax + 1): g_lg[l] = 2.0 / (2 * l + 1) / rcgauss**2 * r_g * g_lg[l - 1] for l in range(lmax + 1): g_lg[l] /= self.rgd.integrate(g_lg[l], l) / (4 * pi) return g_lg def get_smooth_core_density_integral(self, Delta0): return -Delta0 * sqrt(4 * pi) - self.Z + self.Nc def get_overlap_correction(self, Delta0_ii): return sqrt(4.0 * pi) * Delta0_ii def get_linear_kinetic_correction(self, T0_qp): e_kin_jj = self.e_kin_jj nj = len(e_kin_jj) K_q = [] for j1 in range(nj): for j2 in range(j1, nj): K_q.append(e_kin_jj[j1, j2]) K_p = sqrt(4 * pi) * np.dot(K_q, T0_qp) return K_p def get_ghat(self, lmax, alpha, r, rcut): d_l = [fac(l) * 2**(2 * l + 2) / sqrt(pi) / fac(2 * l + 1) for l in range(lmax + 1)] g = alpha**1.5 * np.exp(-alpha * r**2) g[-1] = 0.0 ghat_l = [Spline(l, rcut, d_l[l] * alpha**l * g) for l in range(lmax + 1)] return ghat_l def find_core_density_cutoff(self, nc_g): if self.Nc == 0: return 1.0 else: rgd = self.rgd N = 0.0 g = self.rgd.N - 1 while N < 1e-7: N += sqrt(4 * pi) * nc_g[g] * rgd.r_g[g]**2 * rgd.dr_g[g] g -= 1 return rgd.r_g[g] def get_max_projector_cutoff(self): g = self.rgd.N - 1 pt_g = self.pt_jg[0] while pt_g[g] == 0.0: g -= 1 gcutfilter = g + 1 return gcutfilter def get_xc_correction(self, rgd, xc, gcut2, lcut): phicorehole_g = self.phicorehole_g if phicorehole_g is not None: phicorehole_g = phicorehole_g[:gcut2].copy() xc_correction = PAWXCCorrection( [phi_g[:gcut2] for phi_g in self.phi_jg], [phit_g[:gcut2] for phit_g in self.phit_jg], self.nc_g[:gcut2] / sqrt(4 * pi), self.nct_g[:gcut2] / sqrt(4 * pi), rgd, list(enumerate(self.l_j)), min(2 * lcut, 4), self.e_xc, phicorehole_g, self.fcorehole, self.tauc_g[:gcut2].copy(), self.tauct_g[:gcut2].copy()) return xc_correction def write_xml(self): l_j = self.l_j xml = open(self.stdfilename, 'w') print('', file=xml) print('', file=xml) name = atomic_names[self.Z].title() comment1 = name + ' setup for the Projector Augmented Wave method.' comment2 = 'Units: Hartree and Bohr radii.' comment2 += ' ' * (len(comment1) - len(comment2)) print(' ', file=xml) print(' ', file=xml) print((' ' % (self.symbol, self.Z, self.Nc, self.Nv)), file=xml) if self.orbital_free: type = 'OFDFT' name = self.setupname elif self.setupname == 'LDA': type = 'LDA' name = 'PW' else: type = 'GGA' name = self.setupname print(' ' % (type, name), file=xml) gen_attrs = ' '.join(['%s="%s"' % (key, value) for key, value in self.generatorattrs]) print(' ' % gen_attrs, file=xml) print(' %s' % self.generatordata, file=xml) print(' ', file=xml) print(' ' % (self.e_electrostatic, self.e_total), file=xml) print(' ' % self.e_kinetic_core, file=xml) print(' ', file=xml) line1 = ' ' line2 = ' ' for id, l, n, f, e, rc in zip(self.id_j, l_j, self.n_j, self.f_j, self.eps_j, self.rcut_j): if n > 0: print(line1 % (n, l, f, rc, e, id), file=xml) else: print(line2 % (l, rc, e, id), file=xml) print(' ', file=xml) print(self.rgd.xml('g1'), file=xml) print((' ' % self.rcgauss), file=xml) if self.r0 is None: # Old setups: xml.write(' \n') elif self.l0 is None: xml.write(' \n' % (self.nderiv0, self.r0)) else: xml.write((' \n') % ('spdfg'[self.l0], self.e0, self.nderiv0, self.r0)) for x in self.vbar_g: print('%r' % x, end=' ', file=xml) print('\n ', file=xml) if self.has_corehole: print(((' ') % (self.ncorehole, 'spdf'[self.lcorehole], self.fcorehole, self.core_hole_e, self.core_hole_e_kin)), file=xml) for x in self.phicorehole_g: print('%r' % x, end=' ', file=xml) print('\n ', file=xml) for name, a in [('ae_core_density', self.nc_g), ('pseudo_core_density', self.nct_g), ('ae_core_kinetic_energy_density', self.tauc_g), ('pseudo_core_kinetic_energy_density', self.tauct_g)]: print(' <%s grid="g1">\n ' % name, end=' ', file=xml) for x in a: print('%r' % x, end=' ', file=xml) print('\n ' % name, file=xml) # Print xc-specific data to setup file (used so for KLI and GLLB) for name, a in self.extra_xc_data.items(): newname = 'GLLB_' + name print(' <%s grid="g1">\n ' % newname, end=' ', file=xml) for x in a: print('%r' % x, end=' ', file=xml) print('\n ' % newname, file=xml) for id, l, u, s, q, in zip(self.id_j, l_j, self.phi_jg, self.phit_jg, self.pt_jg): for name, a in [('ae_partial_wave', u), ('pseudo_partial_wave', s), ('projector_function', q)]: print(' <%s state="%s" grid="g1">\n ' % (name, id), end=' ', file=xml) for x in a: print('%r' % x, end=' ', file=xml) print('\n ' % name, file=xml) print(' ', end=' ', file=xml) nj = len(self.e_kin_jj) for j1 in range(nj): print('\n ', end=' ', file=xml) for j2 in range(nj): print('%r' % self.e_kin_jj[j1, j2], end=' ', file=xml) print('\n ', file=xml) if self.X_p is not None: print(' \n ', end=' ', file=xml) for x in self.X_p: print('%r' % x, end=' ', file=xml) print('\n ', file=xml) print(' ' % self.ExxC, file=xml) print('', file=xml) def build(self, xcfunc, lmax, basis, filter=None): from gpaw.setup import Setup setup = Setup(self, xcfunc, lmax, basis, filter) return setup def search_for_file(name, world=None): """Traverse gpaw setup paths to find file. Returns the file path and file contents. If the file is not found, raises RuntimeError.""" if world is None or world.rank == 0: source = None filename = None for path in setup_paths: pattern = os.path.join(path, name) filenames = glob(pattern) + glob('%s.gz' % pattern) if filenames: # The globbing is a hack to grab the 'newest' version if # the files are somehow version numbered; then we want the # last/newest of the results (used with SG15). (User must # instantiate (UPF)SetupData directly to override.) filename = max(filenames) assert has_gzip # Which systems do not have the gzip module? if filename.endswith('.gz'): fd = gzip.open(filename) else: fd = open(filename, 'rb') source = fd.read() break if world is not None: if world.rank == 0: broadcast((filename, source), 0, world) else: filename, source = broadcast(None, 0, world) if source is None: if name.endswith('basis'): _type = 'basis set' else: _type = 'PAW dataset' err = 'Could not find required %s file "%s".' % (_type, name) helpful_message = """ You need to set the GPAW_SETUP_PATH environment variable to point to the directories where setup and basis files are stored. See http://wiki.fysik.dtu.dk/gpaw/install/installationguide.html for details.""" raise RuntimeError('%s\n%s' % (err, helpful_message)) return filename, source class PAWXMLParser(xml.sax.handler.ContentHandler): def __init__(self, setup): xml.sax.handler.ContentHandler.__init__(self) self.setup = setup self.id = None self.data = None def parse(self, source=None, world=None): setup = self.setup if source is None: setup.filename, source = search_for_file(setup.stdfilename, world) setup.fingerprint = hashlib.md5(source).hexdigest() # XXXX There must be a better way! # We don't want to look at the dtd now. Remove it: source = re.compile(b'', re.DOTALL).sub(b'', source, 1) xml.sax.parseString(source, self) if setup.zero_reference: setup.e_total = 0.0 setup.e_kinetic = 0.0 setup.e_electrostatic = 0.0 setup.e_xc = 0.0 def startElement(self, name, attrs): if sys.version_info[0] < 3: attrs.__contains__ = attrs.has_key setup = self.setup if name == 'paw_setup': setup.version = attrs['version'] assert setup.version >= '0.4' if name == 'atom': setup.Z = int(attrs['Z']) setup.Nc = float(attrs['core']) setup.Nv = int(attrs['valence']) elif name == 'xc_functional': if attrs['type'] == 'LDA': setup.xcname = 'LDA' else: setup.xcname = attrs['name'] if attrs['type'] == 'OFDFT': setup.orbital_free = True else: assert attrs['type'] == 'GGA' elif name == 'ae_energy': setup.e_total = float(attrs['total']) setup.e_kinetic = float(attrs['kinetic']) setup.e_electrostatic = float(attrs['electrostatic']) setup.e_xc = float(attrs['xc']) elif name == 'core_energy': setup.e_kinetic_core = float(attrs['kinetic']) elif name == 'state': setup.n_j.append(int(attrs.get('n', -1))) setup.l_j.append(int(attrs['l'])) setup.f_j.append(float(attrs.get('f', 0))) setup.eps_j.append(float(attrs['e'])) setup.rcut_j.append(float(attrs.get('rc', -1))) setup.id_j.append(attrs['id']) # Compatibility with old setups: if setup.version < '0.6' and setup.f_j[-1] == 0: setup.n_j[-1] = -1 elif name == 'radial_grid': if attrs['eq'] == 'r=a*i/(n-i)': beta = float(attrs['a']) ng = int(attrs['n']) setup.rgd = AERadialGridDescriptor(beta / ng, 1.0 / ng, ng) elif attrs['eq'] == 'r=a*i/(1-b*i)': a = float(attrs['a']) b = float(attrs['b']) N = int(attrs['n']) setup.rgd = AERadialGridDescriptor(a, b, N) else: raise ValueError('Unknown grid:' + attrs['eq']) elif name == 'shape_function': if 'rc' in attrs: assert attrs['type'] == 'gauss' setup.rcgauss = float(attrs['rc']) else: # Old style: XXX setup.rcgauss = max(setup.rcut_j) / sqrt(float(attrs['alpha'])) elif name in ['ae_core_density', 'pseudo_core_density', 'localized_potential', 'kinetic_energy_differences', 'exact_exchange_X_matrix', 'ae_core_kinetic_energy_density', 'pseudo_core_kinetic_energy_density']: self.data = [] elif name.startswith('GLLB_'): self.data = [] elif name in ['ae_partial_wave', 'pseudo_partial_wave']: self.data = [] self.id = attrs['state'] elif name == 'projector_function': self.id = attrs['state'] self.data = [] elif name == 'exact_exchange': setup.ExxC = float(attrs['core-core']) elif name == 'core_hole_state': setup.has_corehole = True setup.fcorehole = float(attrs['removed']) setup.lcorehole = 'spdf'.find(attrs['state'][1]) setup.core_hole_e = float(attrs['eig']) setup.core_hole_e_kin = float(attrs['ekin']) self.data = [] elif name == 'zero_potential': if 'type' in attrs: setup.r0 = float(attrs['r0']) setup.nderiv0 = int(attrs['nderiv']) if attrs['type'] == 'polynomial': setup.e0 = None setup.l0 = None else: setup.e0 = float(attrs['e0']) setup.l0 = 'spdfg'.find(attrs['type']) self.data = [] elif name == 'generator': setup.type = attrs['type'] setup.generator_version = attrs.get('version', 1) else: self.data = None def characters(self, data): if self.data is not None: self.data.append(data) def endElement(self, name): setup = self.setup if self.data is None: return x_g = np.array([float(x) for x in ''.join(self.data).split()]) if name == 'ae_core_density': setup.nc_g = x_g elif name == 'pseudo_core_density': setup.nct_g = x_g elif name == 'kinetic_energy_differences': setup.e_kin_jj = x_g elif name == 'ae_core_kinetic_energy_density': setup.tauc_g = x_g elif name == 'pseudo_valence_density': setup.nvt_g = x_g elif name == 'pseudo_core_kinetic_energy_density': setup.tauct_g = x_g elif name in ['localized_potential', 'zero_potential']: # XXX setup.vbar_g = x_g elif name.startswith('GLLB_'): # Add setup tags starting with GLLB_ to extra_xc_data. Remove # GLLB_ from front of string: setup.extra_xc_data[name[5:]] = x_g elif name == 'ae_partial_wave': j = len(setup.phi_jg) assert self.id == setup.id_j[j] setup.phi_jg.append(x_g) elif name == 'pseudo_partial_wave': j = len(setup.phit_jg) assert self.id == setup.id_j[j] setup.phit_jg.append(x_g) elif name == 'projector_function': j = len(setup.pt_jg) assert self.id == setup.id_j[j] setup.pt_jg.append(x_g) elif name == 'exact_exchange_X_matrix': setup.X_p = x_g elif name == 'core_hole_state': setup.phicorehole_g = x_g gpaw-0.11.0.13004/gpaw/mpi/0000775000175000017500000000000012553644063015176 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/mpi/config.py0000664000175000017500000000377312553643470017030 0ustar jensjjensj00000000000000import os import platform import sys def get_mpi_implementation(): mpi = os.environ.get('GPAW_MPI_IMPLEMENTATION') if mpi is not None: return mpi machine = platform.uname()[4] if machine == 'sun4u': return 'sun' if sys.platform == 'aix5': return 'poe' if sys.platform == 'ia64': return 'mpich' output = os.popen('mpicc --showme 2> /dev/null', 'r').read() if output != '': if 'openmpi' in output: return 'openmpi' else: return 'lam' output = os.popen('mpicc -show 2> /dev/null', 'r').read() if output != '': if 'mvapich' in output: return 'mvapich' else: return 'mpich' return '' def get_mpi_command(debug=False): cmd = os.environ.get('GPAW_MPI_COMMAND') if cmd is not None: return cmd mpi = get_mpi_implementation() if mpi == 'sun': return 'mprun -np %(np)d %(job)s &' if mpi == 'poe': if 'LOADL_PROCESSOR_LIST' in os.environ: return "poe '%(job)s' &" else: return "poe '%(job)s' -procs %(np)d -hfile %(hostfile)s &" if mpi == 'mpich': output = os.popen('mpiexec', 'r').read() if output != '': return 'mpiexec -n %(np)d %(job)s' output = os.popen('mpirun', 'r').read() if output != '': return 'mpirun -n %(np)d %(job)s' raise NotImplementedError if mpi == 'mvapich': raise NotImplementedError if mpi == 'lam': return ('lamnodes; ' 'if [ $? != 0 ]; then ' ' lamboot -H %(hostfile)s; ' 'fi; ' 'mpirun -np %(np)d %(job)s &') if mpi == 'openmpi': return 'mpirun -np %(np)d --hostfile %(hostfile)s %(job)s &' raise NotImplementedError if __name__ == '__main__': print(get_mpi_implementation()) print(get_mpi_command(debug=False)) print(get_mpi_command(debug=True)) gpaw-0.11.0.13004/gpaw/mpi/__init__.py0000664000175000017500000010704212553643470017314 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. import os import sys import time import traceback import atexit import pickle from fractions import gcd import numpy as np from gpaw import debug from gpaw import dry_run as dry_run_size from gpaw.utilities import is_contiguous import _gpaw MASTER = 0 class _Communicator: def __init__(self, comm, parent=None): """Construct a wrapper of the C-object for any MPI-communicator. Parameters: comm: MPI-communicator Communicator. Attributes: ============ ====================================================== ``size`` Number of ranks in the MPI group. ``rank`` Number of this CPU in the MPI group. ``parent`` Parent MPI-communicator. ============ ====================================================== """ self.comm = comm self.size = comm.size self.rank = comm.rank self.parent = parent # XXX check C-object against comm.parent? def new_communicator(self, ranks): """Create a new MPI communicator for a subset of ranks in a group. Must be called with identical arguments by all relevant processes. Note that a valid communicator is only returned to the processes which are included in the new group; other ranks get None returned. Parameters: ranks: ndarray (type int) List of integers of the ranks to include in the new group. Note that these ranks correspond to indices in the current group whereas the rank attribute in the new communicators correspond to their respective index in the subset. """ comm = self.comm.new_communicator(ranks) if comm is None: # This cpu is not in the new communicator: return None else: return _Communicator(comm, parent=self) def sum(self, a, root=-1): """Perform summation by MPI reduce operations of numerical data. Parameters: a: ndarray or value (type int, float or complex) Numerical data to sum over all ranks in the communicator group. If the data is a single value of type int, float or complex, the result is returned because the input argument is immutable. Otherwise, the reduce operation is carried out in-place such that the elements of the input array will represent the sum of the equivalent elements across all processes in the group. root: int (default -1) Rank of the root process, on which the outcome of the reduce operation is valid. A root rank of -1 signifies that the result will be distributed back to all processes, i.e. a broadcast. """ if isinstance(a, (int, float, complex)): return self.comm.sum(a, root) else: tc = a.dtype assert tc == int or tc == float or tc == complex assert is_contiguous(a, tc) assert root == -1 or 0 <= root < self.size self.comm.sum(a, root) def product(self, a, root=-1): """Do multiplication by MPI reduce operations of numerical data. Parameters: a: ndarray or value (type int or float) Numerical data to multiply across all ranks in the communicator group. NB: Find the global product from the local products. If the data is a single value of type int or float (no complex), the result is returned because the input argument is immutable. Otherwise, the reduce operation is carried out in-place such that the elements of the input array will represent the product of the equivalent elements across all processes in the group. root: int (default -1) Rank of the root process, on which the outcome of the reduce operation is valid. A root rank of -1 signifies that the result will be distributed back to all processes, i.e. a broadcast. """ if isinstance(a, (int, float)): return self.comm.product(a, root) else: tc = a.dtype assert tc == int or tc == float assert is_contiguous(a, tc) assert root == -1 or 0 <= root < self.size self.comm.product(a, root) def max(self, a, root=-1): """Find maximal value by an MPI reduce operation of numerical data. Parameters: a: ndarray or value (type int or float) Numerical data to find the maximum value of across all ranks in the communicator group. NB: Find global maximum from local max. If the data is a single value of type int or float (no complex), the result is returned because the input argument is immutable. Otherwise, the reduce operation is carried out in-place such that the elements of the input array will represent the max of the equivalent elements across all processes in the group. root: int (default -1) Rank of the root process, on which the outcome of the reduce operation is valid. A root rank of -1 signifies that the result will be distributed back to all processes, i.e. a broadcast. """ if isinstance(a, (int, float)): return self.comm.max(a, root) else: tc = a.dtype assert tc == int or tc == float assert is_contiguous(a, tc) assert root == -1 or 0 <= root < self.size self.comm.max(a, root) def min(self, a, root=-1): """Find minimal value by an MPI reduce operation of numerical data. Parameters: a: ndarray or value (type int or float) Numerical data to find the minimal value of across all ranks in the communicator group. NB: Find global minimum from local min. If the data is a single value of type int or float (no complex), the result is returned because the input argument is immutable. Otherwise, the reduce operation is carried out in-place such that the elements of the input array will represent the min of the equivalent elements across all processes in the group. root: int (default -1) Rank of the root process, on which the outcome of the reduce operation is valid. A root rank of -1 signifies that the result will be distributed back to all processes, i.e. a broadcast. """ if isinstance(a, (int, float)): return self.comm.min(a, root) else: tc = a.dtype assert tc == int or tc == float assert is_contiguous(a, tc) assert root == -1 or 0 <= root < self.size self.comm.min(a, root) def scatter(self, a, b, root): """Distribute data from one rank to all other processes in a group. Parameters: a: ndarray (ignored on all ranks different from root; use None) Source of the data to distribute, i.e. send buffer on root rank. b: ndarray Destination of the distributed data, i.e. local receive buffer. The size of this array multiplied by the number of process in the group must match the size of the source array on the root. root: int Rank of the root process, from which the source data originates. The reverse operation is ``gather``. Example:: # The master has all the interesting data. Distribute it. if comm.rank == 0: data = np.random.normal(size=N*comm.size) else: data = None mydata = np.empty(N, dtype=float) comm.scatter(data, mydata, 0) # .. which is equivalent to .. if comm.rank == 0: # Extract my part directly mydata[:] = data[0:N] # Distribute parts to the slaves for rank in range(1, comm.size): buf = data[rank*N:(rank+1)*N] comm.send(buf, rank, tag=123) else: # Receive from the master comm.receive(mydata, 0, tag=123) """ if self.rank == root: assert a.dtype == b.dtype assert a.size == self.size * b.size assert a.flags.contiguous assert b.flags.contiguous assert 0 <= root < self.size self.comm.scatter(a, b, root) def alltoallv(self, sbuffer, scounts, sdispls, rbuffer, rcounts, rdispls): """All-to-all in a group. Parameters: sbuffer: ndarray Source of the data to distribute, i.e. send buffers on all rank. scounts: ndarray Integer array equal to the group size specifying the number of elements to send to each processor sbuffer: ndarray Integer array (of length group size). Entry j specifies the displacement (relative to sendbuf from which to take the outgoing data destined for process j rbuffer: ndarray Destination of the distributed data, i.e. local receive buffer. rcounts: ndarray Integer array equal to the group size specifying the maximum number of elements that can be received from each processor. rdispls: Integer array (of length group size). Entry i specifies the displacement (relative to recvbuf at which to place the incoming data from process i """ assert sbuffer.flags.contiguous assert scounts.flags.contiguous assert sdispls.flags.contiguous assert rbuffer.flags.contiguous assert rcounts.flags.contiguous assert rdispls.flags.contiguous assert sbuffer.dtype == rbuffer.dtype # FIXME: more tests self.comm.alltoallv(sbuffer, scounts, sdispls, rbuffer, rcounts, rdispls) def all_gather(self, a, b): """Gather data from all ranks onto all processes in a group. Parameters: a: ndarray Source of the data to gather, i.e. send buffer of this rank. b: ndarray Destination of the distributed data, i.e. receive buffer. The size of this array must match the size of the distributed source arrays multiplied by the number of process in the group. Example:: # All ranks have parts of interesting data. Gather on all ranks. mydata = np.random.normal(size=N) data = np.empty(N*comm.size, dtype=float) comm.all_gather(mydata, data) # .. which is equivalent to .. if comm.rank == 0: # Insert my part directly data[0:N] = mydata # Gather parts from the slaves buf = np.empty(N, dtype=float) for rank in range(1, comm.size): comm.receive(buf, rank, tag=123) data[rank*N:(rank+1)*N] = buf else: # Send to the master comm.send(mydata, 0, tag=123) # Broadcast from master to all slaves comm.broadcast(data, 0) """ assert a.flags.contiguous assert b.flags.contiguous assert b.dtype == a.dtype assert (b.shape[0] == self.size and a.shape == b.shape[1:] or a.size * self.size == b.size) self.comm.all_gather(a, b) def gather(self, a, root, b=None): """Gather data from all ranks onto a single process in a group. Parameters: a: ndarray Source of the data to gather, i.e. send buffer of this rank. root: int Rank of the root process, on which the data is to be gathered. b: ndarray (ignored on all ranks different from root; default None) Destination of the distributed data, i.e. root's receive buffer. The size of this array must match the size of the distributed source arrays multiplied by the number of process in the group. The reverse operation is ``scatter``. Example:: # All ranks have parts of interesting data. Gather it on master. mydata = np.random.normal(size=N) if comm.rank == 0: data = np.empty(N*comm.size, dtype=float) else: data = None comm.gather(mydata, 0, data) # .. which is equivalent to .. if comm.rank == 0: # Extract my part directly data[0:N] = mydata # Gather parts from the slaves buf = np.empty(N, dtype=float) for rank in range(1, comm.size): comm.receive(buf, rank, tag=123) data[rank*N:(rank+1)*N] = buf else: # Send to the master comm.send(mydata, 0, tag=123) """ assert a.flags.contiguous assert 0 <= root < self.size if root == self.rank: assert b.flags.contiguous and b.dtype == a.dtype assert (b.shape[0] == self.size and a.shape == b.shape[1:] or a.size * self.size == b.size) self.comm.gather(a, root, b) else: assert b is None self.comm.gather(a, root) def broadcast(self, a, root): """Share data from a single process to all ranks in a group. Parameters: a: ndarray Data, i.e. send buffer on root rank, receive buffer elsewhere. Note that after the broadcast, all ranks have the same data. root: int Rank of the root process, from which the data is to be shared. Example:: # All ranks have parts of interesting data. Take a given index. mydata[:] = np.random.normal(size=N) # Who has the element at global index 13? Everybody needs it! index = 13 root, myindex = divmod(index, N) element = np.empty(1, dtype=float) if comm.rank == root: # This process has the requested element so extract it element[:] = mydata[myindex] # Broadcast from owner to everyone else comm.broadcast(element, root) # .. which is equivalent to .. if comm.rank == root: # We are root so send it to the other ranks for rank in range(comm.size): if rank != root: comm.send(element, rank, tag=123) else: # We don't have it so receive from root comm.receive(element, root, tag=123) """ assert 0 <= root < self.size assert is_contiguous(a) self.comm.broadcast(a, root) def sendreceive(self, a, dest, b, src, sendtag=123, recvtag=123): assert 0 <= dest < self.size assert dest != self.rank assert is_contiguous(a) assert 0 <= src < self.size assert src != self.rank assert is_contiguous(b) return self.comm.sendreceive(a, dest, b, src, sendtag, recvtag) def send(self, a, dest, tag=123, block=True): assert 0 <= dest < self.size assert dest != self.rank assert is_contiguous(a) if not block: pass # assert sys.getrefcount(a) > 3 return self.comm.send(a, dest, tag, block) def ssend(self, a, dest, tag=123): assert 0 <= dest < self.size assert dest != self.rank assert is_contiguous(a) return self.comm.ssend(a, dest, tag) def receive(self, a, src, tag=123, block=True): assert 0 <= src < self.size assert src != self.rank assert is_contiguous(a) return self.comm.receive(a, src, tag, block) def test(self, request): """Test whether a non-blocking MPI operation has completed. A boolean is returned immediately and the request is not modified in any way. Parameters: request: MPI request Request e.g. returned from send/receive when block=False is used. """ return self.comm.test(request) def testall(self, requests): """Test whether non-blocking MPI operations have completed. A boolean is returned immediately but requests may have been deallocated as a result, provided they have completed before or during this invokation. Parameters: request: MPI request Request e.g. returned from send/receive when block=False is used. """ return self.comm.testall(requests) # may deallocate requests! def wait(self, request): """Wait for a non-blocking MPI operation to complete before returning. Parameters: request: MPI request Request e.g. returned from send/receive when block=False is used. """ self.comm.wait(request) def waitall(self, requests): """Wait for non-blocking MPI operations to complete before returning. Parameters: requests: list List of MPI requests e.g. aggregated from returned requests of multiple send/receive calls where block=False was used. """ self.comm.waitall(requests) def abort(self, errcode): """Terminate MPI execution environment of all tasks in the group. This function only returns in the advent of an error occurring. Parameters: errcode: int Error code to return to the invoking environment. """ return self.comm.abort(errcode) def name(self): """Return the name of the processor as a string.""" return self.comm.name() def barrier(self): """Block execution until all process have reached this point.""" self.comm.barrier() def get_members(self): """Return the subset of processes which are members of this MPI group in terms of the ranks they are assigned on the parent communicator. For the world communicator, this is all integers up to ``size``. Example:: >>> world.rank, world.size (3, 4) >>> world.get_members() array([0, 1, 2, 3]) >>> comm = world.new_communicator(array([2, 3])) >>> comm.rank, comm.size (1, 2) >>> comm.get_members() array([2, 3]) >>> comm.get_members()[comm.rank] == world.rank True """ return self.comm.get_members() def get_c_object(self): """Return the C-object wrapped by this debug interface. Whenever a communicator object is passed to C code, that object must be a proper C-object - *not* e.g. this debug wrapper. For this reason. The C-communicator object has a get_c_object() implementation which returns itself; thus, always call comm.get_c_object() and pass the resulting object to the C code. """ c_obj = self.comm.get_c_object() assert isinstance(c_obj, _gpaw.Communicator) return c_obj # Serial communicator class SerialCommunicator: size = 1 rank = 0 def __init__(self, parent=None): self.parent = parent def sum(self, array, root=-1): if isinstance(array, (int, float, complex)): return array def scatter(self, s, r, root): r[:] = s def min(self, value, root=-1): return value def max(self, value, root=-1): return value def broadcast(self, buf, root): pass def send(self, buff, root, tag=123, block=True): pass def barrier(self): pass def gather(self, a, root, b): b[:] = a def all_gather(self, a, b): b[:] = a def alltoallv(self, sbuffer, scounts, sdispls, rbuffer, rcounts, rdispls): rbuffer[:] = sbuffer rcounts[:] = scounts rdispls[:] = sdispls def new_communicator(self, ranks): if self.rank not in ranks: return None return SerialCommunicator(parent=self) def test(self, request): return 1 def testall(self, requests): return 1 def wait(self, request): raise NotImplementedError('Calls to mpi wait should not happen in ' 'serial mode') def waitall(self, requests): if not requests: return raise NotImplementedError('Calls to mpi waitall should not happen in ' 'serial mode') def get_members(self): return np.array([0]) def get_c_object(self): raise NotImplementedError('Should not get C-object for serial comm') serial_comm = SerialCommunicator() libmpi = os.environ.get('GPAW_MPI') if libmpi: import ctypes ctypes.CDLL(libmpi, ctypes.RTLD_GLOBAL) world = _gpaw.Communicator() if world.size == 1: world = serial_comm else: try: world = _gpaw.Communicator() except AttributeError: world = serial_comm class DryRunCommunicator(SerialCommunicator): def __init__(self, size=1, parent=None): self.size = size self.parent = parent def new_communicator(self, ranks): return DryRunCommunicator(len(ranks), parent=self) def get_c_object(self): return None # won't actually be passed to C if dry_run_size > 1: world = DryRunCommunicator(dry_run_size) if debug: serial_comm = _Communicator(serial_comm) world = _Communicator(world) size = world.size rank = world.rank parallel = (size > 1) # XXXXXXXXXX for easier transition to Parallelization class def distribute_cpus(parsize_domain, parsize_bands, nspins, nibzkpts, comm=world, idiotproof=True, mode='fd'): nsk = nspins * nibzkpts if mode in ['fd', 'lcao']: if parsize_bands is None: parsize_bands = 1 else: # Plane wave mode: if parsize_bands is None: parsize_bands = comm.size // gcd(nsk, comm.size) p = Parallelization(comm, nsk) return p.build_communicators(domain=np.prod(parsize_domain), band=parsize_bands) def broadcast(obj, root=0, comm=world): """Broadcast a Python object across an MPI communicator and return it.""" if comm.rank == root: assert obj is not None b = pickle.dumps(obj, pickle.HIGHEST_PROTOCOL) else: assert obj is None b = None b = broadcast_bytes(b, root, comm) if comm.rank == root: return obj else: return pickle.loads(b) def synchronize_atoms(atoms, comm, tolerance=1e-8): """Synchronize atoms between multiple CPUs removing numerical noise. If the atoms differ significantly, raise ValueError on all ranks. The error object contains the ranks where the check failed. In debug mode, write atoms to files in case of failure.""" if len(atoms) == 0: return if comm.rank == 0: src_atoms = atoms else: src_atoms = None newatoms = broadcast(src_atoms, root=0, comm=comm) err = np.abs(newatoms.positions - atoms.positions).max() # Now copy positions array so we can check for strict identity atoms.positions[:, :] = newatoms.positions[:, :] # We need to fail equally on all ranks to avoid trouble. Thus # we use an array to gather check results from everyone. my_fail = np.array(err > tolerance or newatoms != atoms, dtype=bool) all_fail = np.zeros(comm.size, dtype=bool) comm.all_gather(my_fail, all_fail) if all_fail.any(): err_ranks = np.arange(comm.size)[all_fail] if debug: fd = open('synchronize_atoms_r%d.pckl' % comm.rank, 'wb') pickle.dump((newatoms, atoms), fd) fd.close() raise ValueError('Mismatch of Atoms objects. In debug ' 'mode, atoms will be dumped to files.', err_ranks) def broadcast_string(string=None, root=0, comm=world): if comm.rank == root: string = string.encode() return broadcast_bytes(string, root, comm).decode() def broadcast_bytes(b=None, root=0, comm=world): """Broadcast a bytes across an MPI communicator and return it.""" if comm.rank == root: assert isinstance(b, bytes) n = np.array(len(b), int) else: assert b is None n = np.zeros(1, int) comm.broadcast(n, root) if comm.rank == root: b = np.fromstring(b, np.int8) else: b = np.zeros(n, np.int8) comm.broadcast(b, root) return b.tostring() def send_string(string, rank, comm=world): comm.send(np.array(len(string)), rank) comm.send(np.fromstring(string, np.int8), rank) def receive_string(rank, comm=world): n = np.array(0) comm.receive(n, rank) string = np.empty(n, np.int8) comm.receive(string, rank) return string.tostring().decode() def alltoallv_string(send_dict, comm=world): scounts = np.zeros(comm.size, dtype=np.int) sdispls = np.zeros(comm.size, dtype=np.int) stotal = 0 for proc in range(comm.size): if proc in send_dict: data = np.fromstring(send_dict[proc], np.int8) scounts[proc] = data.size sdispls[proc] = stotal stotal += scounts[proc] rcounts = np.zeros(comm.size, dtype=np.int) comm.alltoallv(scounts, np.ones(comm.size, dtype=np.int), np.arange(comm.size, dtype=np.int), rcounts, np.ones(comm.size, dtype=np.int), np.arange(comm.size, dtype=np.int)) rdispls = np.zeros(comm.size, dtype=np.int) rtotal = 0 for proc in range(comm.size): rdispls[proc] = rtotal rtotal += rcounts[proc] # rtotal += rcounts[proc] # CHECK: is this correct? sbuffer = np.zeros(stotal, dtype=np.int8) for proc in range(comm.size): sbuffer[sdispls[proc]:(sdispls[proc] + scounts[proc])] = ( np.fromstring(send_dict[proc], np.int8)) rbuffer = np.zeros(rtotal, dtype=np.int8) comm.alltoallv(sbuffer, scounts, sdispls, rbuffer, rcounts, rdispls) rdict = {} for proc in range(comm.size): i = rdispls[proc] rdict[proc] = rbuffer[i:i + rcounts[proc]].tostring().decode() return rdict def ibarrier(timeout=None, root=0, tag=123, comm=world): """Non-blocking barrier returning a list of requests to wait for. An optional time-out may be given, turning the call into a blocking barrier with an upper time limit, beyond which an exception is raised.""" requests = [] byte = np.ones(1, dtype=np.int8) if comm.rank == root: # Everybody else: for rank in range(comm.size): if rank == root: continue rbuf, sbuf = np.empty_like(byte), byte.copy() requests.append(comm.send(sbuf, rank, tag=2 * tag + 0, block=False)) requests.append(comm.receive(rbuf, rank, tag=2 * tag + 1, block=False)) else: rbuf, sbuf = np.empty_like(byte), byte requests.append(comm.receive(rbuf, root, tag=2 * tag + 0, block=False)) requests.append(comm.send(sbuf, root, tag=2 * tag + 1, block=False)) if comm.size == 1 or timeout is None: return requests t0 = time.time() while not comm.testall(requests): # automatic clean-up upon success if time.time() - t0 > timeout: raise RuntimeError('MPI barrier timeout.') return [] def run(iterators): """Run through list of iterators one step at a time.""" if not isinstance(iterators, list): # It's a single iterator - empty it: for i in iterators: pass return if len(iterators) == 0: return while True: try: results = [next(iter) for iter in iterators] except StopIteration: return results class Parallelization: def __init__(self, comm, nspinkpts): self.comm = comm self.size = comm.size self.nspinkpts = nspinkpts self.kpt = None self.domain = None self.band = None self.nclaimed = 1 self.navail = comm.size def set(self, kpt=None, domain=None, band=None): if kpt is not None: self.kpt = kpt if domain is not None: self.domain = domain if band is not None: self.band = band nclaimed = 1 for group, name in zip([self.kpt, self.domain, self.band], ['k-point', 'domain', 'band']): if group is not None: if self.size % group != 0: msg = ('Cannot parallelize as the ' 'communicator size %d is not divisible by the ' 'requested number %d of ranks for %s ' 'parallelization' % (self.size, group, name)) raise ValueError(msg) nclaimed *= group navail = self.size // nclaimed assert self.size % nclaimed == 0 assert self.size % navail == 0 self.navail = navail self.nclaimed = nclaimed def get_communicator_sizes(self, kpt=None, domain=None, band=None): self.set(kpt=kpt, domain=domain, band=band) self.autofinalize() return self.kpt, self.domain, self.band def build_communicators(self, kpt=None, domain=None, band=None, order='kbd'): """Construct communicators. Returns a communicator for k-points, domains, bands and k-points/bands. The last one "unites" all ranks that are responsible for the same domain. The order must be a permutation of the characters 'kbd', each corresponding to each a parallelization mode. The last character signifies the communicator that will be assigned contiguous ranks, i.e. order='kbd' will yield contiguous domain ranks, whereas order='kdb' will yield contiguous band ranks.""" self.set(kpt=kpt, domain=domain, band=band) self.autofinalize() comm = self.comm rank = comm.rank communicators = {} parent_stride = self.size offset = 0 groups = dict(k=self.kpt, b=self.band, d=self.domain) # Build communicators in hierachical manner # The ranks in the first group have largest separation while # the ranks in the last group are next to each other for name in order: group = groups[name] stride = parent_stride // group # First rank in this group r0 = rank % stride + offset # Last rank in this group r1 = r0 + stride * group ranks = np.arange(r0, r1, stride) communicators[name] = comm.new_communicator(ranks) parent_stride = stride # Offset for the next communicator offset += communicators[name].rank * stride # We want a communicator for kpts/bands, i.e. the complement of the # grid comm: a communicator uniting all cores with the same domain. c1, c2, c3 = [communicators[name] for name in order] allranks = [range(c1.size), range(c2.size), range(c3.size)] def get_communicator_complement(name): relevant_ranks = list(allranks) relevant_ranks[order.find(name)] = [communicators[name].rank] ranks = np.array([r3 + c3.size * (r2 + c2.size * r1) for r1 in relevant_ranks[0] for r2 in relevant_ranks[1] for r3 in relevant_ranks[2]]) return comm.new_communicator(ranks) # The communicator of all processes that share a domain, i.e. # the combination of k-point and band dommunicators. communicators['D'] = get_communicator_complement('d') # For each k-point comm rank, a communicator of all # band/domain ranks. This is typically used with ScaLAPACK # and LCAO orbital stuff. communicators['K'] = get_communicator_complement('k') return communicators def autofinalize(self): if self.kpt is None: self.set(kpt=self.get_optimal_kpt_parallelization()) if self.domain is None: self.set(domain=self.navail) if self.band is None: self.set(band=self.navail) if self.navail > 1: raise RuntimeError('All the CPUs must be used') def get_optimal_kpt_parallelization(self, kptprioritypower=1.4): if self.domain and self.band: # Try to use all the CPUs for k-point parallelization ncpus = min(self.nspinkpts, self.navail) return ncpus ncpuvalues, wastevalues = self.find_kpt_parallelizations() scores = ((self.navail // ncpuvalues) * ncpuvalues**kptprioritypower)**(1.0 - wastevalues) arg = np.argmax(scores) ncpus = ncpuvalues[arg] return ncpus def find_kpt_parallelizations(self): nspinkpts = self.nspinkpts ncpuvalues = [] wastevalues = [] ncpus = nspinkpts while ncpus > 0: if self.navail % ncpus == 0: nkptsmax = -(-nspinkpts // ncpus) effort = nkptsmax * ncpus efficiency = nspinkpts / float(effort) waste = 1.0 - efficiency wastevalues.append(waste) ncpuvalues.append(ncpus) ncpus -= 1 return np.array(ncpuvalues), np.array(wastevalues) def cleanup(): error = getattr(sys, 'last_type', None) if error is not None: # else: Python script completed or raise SystemExit if parallel and not (dry_run_size > 1): sys.stdout.flush() sys.stderr.write(('GPAW CLEANUP (node %d): %s occurred. ' 'Calling MPI_Abort!\n') % (world.rank, error)) sys.stderr.flush() # Give other nodes a moment to crash by themselves (perhaps # producing helpful error messages) time.sleep(10) world.abort(42) def print_mpi_stack_trace(type, value, tb): """Format exceptions nicely when running in parallel. Use this function as an except hook. Adds rank and line number to each line of the exception. Lines will still be printed from different ranks in random order, but one can grep for a rank or run 'sort' on the output to obtain readable data.""" exception_text = traceback.format_exception(type, value, tb) ndigits = len(str(world.size - 1)) rankstring = ('%%0%dd' % ndigits) % world.rank lines = [] # The exception elements may contain newlines themselves for element in exception_text: lines.extend(element.splitlines()) line_ndigits = len(str(len(lines) - 1)) for lineno, line in enumerate(lines): lineno = ('%%0%dd' % line_ndigits) % lineno sys.stderr.write('rank=%s L%s: %s\n' % (rankstring, lineno, line)) if world.size > 1: # Triggers for dry-run communicators too, but we care not. sys.excepthook = print_mpi_stack_trace def exit(error='Manual exit'): # Note that exit must be called on *all* MPI tasks atexit._exithandlers = [] # not needed because we are intentially exiting if parallel and not (dry_run_size > 1): sys.stdout.flush() sys.stderr.write(('GPAW CLEANUP (node %d): %s occurred. ' + 'Calling MPI_Finalize!\n') % (world.rank, error)) sys.stderr.flush() else: cleanup(error) world.barrier() # sync up before exiting sys.exit() # quit for serial case, return to _gpaw.c for parallel case atexit.register(cleanup) gpaw-0.11.0.13004/gpaw/symmetry.py0000664000175000017500000004025512553643470016663 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Copyright (C) 2014 R. Warmbier Materials for Energy Research Group, # Wits University # Please see the accompanying LICENSE file for further information. from __future__ import print_function, division import functools from fractions import gcd import numpy as np import _gpaw import gpaw.mpi as mpi def frac(f, n=2 * 3 * 4 * 5, tol=1e-6): if not isinstance(f, (int, float)): return np.array([frac(a, n, tol) for a in f]).T if f == 0: return 0, 1 x = n * f if abs(x - round(x)) > n * tol: raise ValueError x = int(round(x)) d = gcd(x, n) return x // d, n // d def sfrac(f): if f == 0: return '0' return '%d/%d' % frac(f) class Symmetry: """Interface class for determination of symmetry, point and space groups. It also provides to apply symmetry operations to kpoint grids, wavefunctions and forces. """ def __init__(self, id_a, cell_cv, pbc_c=np.ones(3, bool), tolerance=1e-7, point_group=True, time_reversal=True, symmorphic=True): """Construct symmetry object. Parameters: id_a: list of int Numbered atomic types cell_cv: array(3,3), float Cartesian lattice vectors pbc_c: array(3), bool Periodic boundary conditions. tolerance: float Tolerance for symmetry determination. symmorphic: bool Switch for the use of non-symmorphic symmetries aka: symmetries with fractional translations. Default is to use only symmorphic symmetries. point_group: bool Use point-group symmetries. time_reversal: bool Use time-reversal symmetry. tolerance: float Relative tolerance. Attributes: op_scc: Array of rotation matrices ft_sc: Array of fractional translation vectors a_sa: Array of atomic indices after symmetry operation has_inversion: (bool) Have inversion """ self.id_a = id_a self.cell_cv = np.array(cell_cv, float) assert self.cell_cv.shape == (3, 3) self.pbc_c = np.array(pbc_c, bool) self.tol = tolerance self.symmorphic = symmorphic self.point_group = point_group self.time_reversal = time_reversal # Disable fractional translations for non-periodic boundary conditions: if not self.pbc_c.all(): self.symmorphic = True self.op_scc = np.identity(3, int).reshape((1, 3, 3)) self.ft_sc = np.zeros((1, 3)) self.a_sa = np.arange(len(id_a)).reshape((1, -1)) self.has_inversion = False self.gcd_c = np.ones(3, int) def analyze(self, spos_ac): """Determine list of symmetry operations. First determine all symmetry operations of the cell. Then call ``prune_symmetries`` to remove those symmetries that are not satisfied by the atoms. """ if self.point_group: self.find_lattice_symmetry() self.prune_symmetries_atoms(spos_ac) def find_lattice_symmetry(self): """Determine list of symmetry operations.""" # Symmetry operations as matrices in 123 basis self.op_scc = [] # Metric tensor metric_cc = np.dot(self.cell_cv, self.cell_cv.T) # Generate all possible 3x3 symmetry matrices using base-3 integers power = (6561, 2187, 729, 243, 81, 27, 9, 3, 1) # operation is a 3x3 matrix, with possible elements -1, 0, 1, thus # there are 3**9 = 19683 possible matrices for base3id in range(19683): op_cc = np.empty((3, 3), dtype=int) m = base3id for ip, p in enumerate(power): d, m = divmod(m, p) op_cc[ip // 3, ip % 3] = 1 - d # The metric of the cell should be conserved after applying # the operation opmetric_cc = np.dot(np.dot(op_cc, metric_cc), op_cc.T) if np.abs(metric_cc - opmetric_cc).sum() > self.tol: continue # Operation must not swap axes that are not both periodic pbc_cc = np.logical_and.outer(self.pbc_c, self.pbc_c) if op_cc[~(pbc_cc | np.identity(3, bool))].any(): continue # Operation must not invert axes that are not periodic pbc_cc = np.logical_and.outer(self.pbc_c, self.pbc_c) if not (op_cc[np.diag(~self.pbc_c)] == 1).all(): continue # operation is a valid symmetry of the unit cell self.op_scc.append(op_cc) self.op_scc = np.array(self.op_scc) self.ft_sc = np.zeros((len(self.op_scc), 3)) def prune_symmetries_atoms(self, spos_ac): """Remove symmetries that are not satisfied by the atoms.""" if len(spos_ac) == 0: return # Build lists of atom numbers for each type of atom - one # list for each combination of atomic number, setup type, # magnetic moment and basis set: a_ij = {} for a, id in enumerate(self.id_a): if id in a_ij: a_ij[id].append(a) else: a_ij[id] = [a] a_j = a_ij[self.id_a[0]] # just pick the first species # if supercell disable fractional translations: if not self.symmorphic: op_cc = np.identity(3, int) ftrans_sc = spos_ac[a_j[1:]] - spos_ac[a_j[0]] ftrans_sc -= np.rint(ftrans_sc) for ft_c in ftrans_sc: a_a = self.check_one_symmetry(spos_ac, op_cc, ft_c, a_ij) if a_a is not None: self.symmorphic = True break symmetries = [] ftsymmetries = [] # go through all possible symmetry operations for op_cc in self.op_scc: # first ignore fractional translations a_a = self.check_one_symmetry(spos_ac, op_cc, [0, 0, 0], a_ij) if a_a is not None: symmetries.append((op_cc, [0, 0, 0], a_a)) elif not self.symmorphic: # check fractional translations sposrot_ac = np.dot(spos_ac, op_cc) ftrans_jc = sposrot_ac[a_j] - spos_ac[a_j[0]] ftrans_jc -= np.rint(ftrans_jc) for ft_c in ftrans_jc: try: nom_c, denom_c = frac(ft_c, tol=self.tol) except ValueError: continue ft_c = nom_c / denom_c a_a = self.check_one_symmetry(spos_ac, op_cc, ft_c, a_ij) if a_a is not None: ftsymmetries.append((op_cc, ft_c, a_a)) for c, d in enumerate(denom_c): self.gcd_c[c] = gcd(self.gcd_c[c] * d, d) # Add symmetry operations with fractional translations at the end: symmetries.extend(ftsymmetries) self.op_scc = np.array([sym[0] for sym in symmetries]) self.ft_sc = np.array([sym[1] for sym in symmetries]) self.a_sa = np.array([sym[2] for sym in symmetries]) inv_cc = -np.eye(3, dtype=int) self.has_inversion = (self.op_scc == inv_cc).all(2).all(1).any() def check_one_symmetry(self, spos_ac, op_cc, ft_c, a_ij): """Checks whether atoms satisfy one given symmetry operation.""" a_a = np.zeros(len(spos_ac), int) for a_j in a_ij.values(): spos_jc = spos_ac[a_j] for a in a_j: spos_c = np.dot(spos_ac[a], op_cc) sdiff_jc = spos_c - spos_jc - ft_c sdiff_jc -= sdiff_jc.round() indices = np.where(abs(sdiff_jc).max(1) < self.tol)[0] if len(indices) == 1: j = indices[0] a_a[a] = a_j[j] else: assert len(indices) == 0 return return a_a def check(self, spos_ac): """Check if positions satisfy symmetry operations.""" nsymold = len(self.op_scc) self.prune_symmetries_atoms(spos_ac) if len(self.op_scc) < nsymold: raise RuntimeError('Broken symmetry!') def reduce(self, bzk_kc, comm=None): """Reduce k-points to irreducible part of the BZ. Returns the irreducible k-points and the weights and other stuff. """ nbzkpts = len(bzk_kc) U_scc = self.op_scc nsym = len(U_scc) time_reversal = self.time_reversal and not self.has_inversion bz2bz_ks = map_k_points(bzk_kc, U_scc, time_reversal, comm, self.tol) bz2bz_k = -np.ones(nbzkpts + 1, int) ibz2bz_k = [] for k in range(nbzkpts - 1, -1, -1): # Reverse order looks more natural if bz2bz_k[k] == -1: bz2bz_k[bz2bz_ks[k]] = k ibz2bz_k.append(k) ibz2bz_k = np.array(ibz2bz_k[::-1]) bz2bz_k = bz2bz_k[:-1].copy() bz2ibz_k = np.empty(nbzkpts, int) bz2ibz_k[ibz2bz_k] = np.arange(len(ibz2bz_k)) bz2ibz_k = bz2ibz_k[bz2bz_k] weight_k = np.bincount(bz2ibz_k) * (1.0 / nbzkpts) # Symmetry operation mapping IBZ to BZ: sym_k = np.empty(nbzkpts, int) for k in range(nbzkpts): # We pick the first one found: try: sym_k[k] = np.where(bz2bz_ks[bz2bz_k[k]] == k)[0][0] except IndexError: print(nbzkpts) print(k) print(bz2bz_k) print(bz2bz_ks[bz2bz_k[k]]) print(np.shape(np.where(bz2bz_ks[bz2bz_k[k]] == k))) print(bz2bz_k[k]) print(bz2bz_ks[bz2bz_k[k]] == k) raise # Time-reversal symmetry used on top of the point group operation: if time_reversal: time_reversal_k = sym_k >= nsym sym_k %= nsym else: time_reversal_k = np.zeros(nbzkpts, bool) assert (ibz2bz_k[bz2ibz_k] == bz2bz_k).all() for k in range(nbzkpts): sign = 1 - 2 * time_reversal_k[k] dq_c = (np.dot(U_scc[sym_k[k]], bzk_kc[bz2bz_k[k]]) - sign * bzk_kc[k]) dq_c -= dq_c.round() assert abs(dq_c).max() < 1e-10 return (bzk_kc[ibz2bz_k], weight_k, sym_k, time_reversal_k, bz2ibz_k, ibz2bz_k, bz2bz_ks) def check_grid(self, N_c): """Check that symmetries are comensurate with grid.""" for U_cc, ft_c in zip(self.op_scc, self.ft_sc): assert not (U_cc * N_c - (U_cc.T * N_c).T).any() t_c = ft_c * N_c assert np.allclose(t_c, t_c.round()) def symmetrize(self, a, gd): """Symmetrize array.""" gd.symmetrize(a, self.op_scc, self.ft_sc) def symmetrize_positions(self, spos_ac): """Symmetrizes the atomic positions.""" spos_tmp_ac = np.zeros_like(spos_ac) spos_new_ac = np.zeros_like(spos_ac) for i, op_cc in enumerate(self.op_scc): spos_tmp_ac[:] = 0. for a in range(len(spos_ac)): spos_c = np.dot(spos_ac[a], op_cc) - self.ft_sc[i] # Bring back the negative ones: spos_c = spos_c - np.floor(spos_c + 1e-5) spos_tmp_ac[self.a_sa[i][a]] += spos_c spos_new_ac += spos_tmp_ac spos_new_ac /= len(self.op_scc) return spos_new_ac def symmetrize_wavefunction(self, a_g, kibz_c, kbz_c, op_cc, time_reversal): """Generate Bloch function from symmetry related function in the IBZ. a_g: ndarray Array with Bloch function from the irreducible BZ. kibz_c: ndarray Corresponing k-point coordinates. kbz_c: ndarray K-point coordinates of the symmetry related k-point. op_cc: ndarray Point group operation connecting the two k-points. time-reversal: bool Time-reversal symmetry required in addition to the point group symmetry to connect the two k-points. """ # Identity if (np.abs(op_cc - np.eye(3, dtype=int)) < 1e-10).all(): if time_reversal: return a_g.conj() else: return a_g # Inversion symmetry elif (np.abs(op_cc + np.eye(3, dtype=int)) < 1e-10).all(): return a_g.conj() # General point group symmetry else: import _gpaw b_g = np.zeros_like(a_g) if time_reversal: # assert abs(np.dot(op_cc, kibz_c) - -kbz_c) < tol _gpaw.symmetrize_wavefunction(a_g, b_g, op_cc.T.copy(), kibz_c, -kbz_c) return b_g.conj() else: # assert abs(np.dot(op_cc, kibz_c) - kbz_c) < tol _gpaw.symmetrize_wavefunction(a_g, b_g, op_cc.T.copy(), kibz_c, kbz_c) return b_g def symmetrize_forces(self, F0_av): """Symmetrize forces.""" F_ac = np.zeros_like(F0_av) for map_a, op_cc in zip(self.a_sa, self.op_scc): op_vv = np.dot(np.linalg.inv(self.cell_cv), np.dot(op_cc, self.cell_cv)) for a1, a2 in enumerate(map_a): F_ac[a2] += np.dot(F0_av[a1], op_vv) return F_ac / len(self.op_scc) def print_symmetries(self, fd): """Print symmetry information.""" p = functools.partial(print, file=fd) n = len(self.op_scc) nft = self.ft_sc.any(1).sum() p('Symmetries present (total):', n) if not self.symmorphic: p('Symmetries with fractional translations:', nft) # X-Y grid of symmetry matrices: p() nx = 6 if self.symmorphic else 3 ns = len(self.op_scc) y = 0 for y in range((ns + nx - 1) // nx): for c in range(3): for x in range(nx): s = x + y * nx if s == ns: break op_c = self.op_scc[s, c] ft = self.ft_sc[s, c] p(' (%2d %2d %2d)' % tuple(op_c), end='') if not self.symmorphic: p(' + (%4s)' % sfrac(ft), end='') p() p() def map_k_points(bzk_kc, U_scc, time_reversal, comm=None, tol=1e-11): """Find symmetry relations between k-points. This is a Python-wrapper for a C-function that does the hard work which is distributed over comm. The map bz2bz_ks is returned. If there is a k2 for which:: = _ _ _ U q = q + N, s k1 k2 where N is a vector of integers, then bz2bz_ks[k1, s] = k2, otherwise if there is a k2 for which:: = _ _ _ U q = -q + N, s k1 k2 then bz2bz_ks[k1, s + nsym] = k2, where nsym = len(U_scc). Otherwise bz2bz_ks[k1, s] = -1. """ if comm is None or isinstance(comm, mpi.DryRunCommunicator): comm = mpi.serial_comm nbzkpts = len(bzk_kc) ka = nbzkpts * comm.rank // comm.size kb = nbzkpts * (comm.rank + 1) // comm.size assert comm.sum(kb - ka) == nbzkpts if time_reversal: U_scc = np.concatenate([U_scc, -U_scc]) bz2bz_ks = np.zeros((nbzkpts, len(U_scc)), int) bz2bz_ks[ka:kb] = -1 _gpaw.map_k_points(np.ascontiguousarray(bzk_kc), np.ascontiguousarray(U_scc), tol, bz2bz_ks, ka, kb) comm.sum(bz2bz_ks) return bz2bz_ks def atoms2symmetry(atoms, id_a=None): """Create symmetry object from atoms object.""" if id_a is None: id_a = atoms.get_atomic_numbers() symmetry = Symmetry(id_a, atoms.cell, atoms.pbc, symmorphic=False, time_reversal=False) symmetry.analyze(atoms.get_scaled_positions()) return symmetry def analyze_atoms(filename): """Analyse symmetry. filename: str filename containing atomic positions and unit cell.""" import sys from ase.io import read atoms = read(filename) symmetry = atoms2symmetry(atoms) symmetry.print_symmetries(sys.stdout) gpaw-0.11.0.13004/gpaw/kpoint.py0000664000175000017500000001150112553643470016266 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. """This module defines a ``KPoint`` class and the derived ``GlobalKPoint``.""" import numpy as np class KPoint: """Class for a single k-point. The KPoint class takes care of all wave functions for a certain k-point and a certain spin. XXX This needs to be updated. Attributes: phase_cd: complex ndarray Bloch phase-factors for translations - axis c=0,1,2 and direction d=0,1. eps_n: float ndarray Eigenvalues. f_n: float ndarray Occupation numbers. The occupation numbers already include the k-point weight in supercell calculations. psit_nG: ndarray Wave functions. nbands: int Number of bands. Parallel stuff: comm: Communicator object MPI-communicator for domain. root: int Rank of the CPU that does the matrix diagonalization of H_nn and the Cholesky decomposition of S_nn. """ def __init__(self, weight, s, k, q, phase_cd): """Construct k-point object. Parameters: gd: GridDescriptor object Descriptor for wave-function grid. weight: float Weight of this k-point. s: int Spin index: up or down (0 or 1). k: int k-point index. q: int local k-point index. dtype: type object Data type of wave functions (float or complex). timer: Timer object Optional. Note that s and k are global spin/k-point indices, whereas u is a local spin/k-point pair index for this processor. So if we have `S` spins and `K` k-points, and the spins/k-points are parallelized over `P` processors (kpt_comm), then we have this equation relating s, k and u:: rSK --- + u = sK + k, P where `r` is the processor rank within kpt_comm. The total number of spin/k-point pairs, `SK`, is always a multiple of the number of processors, `P`. """ self.weight = weight self.s = s # spin index self.k = k # k-point index self.q = q # local k-point index self.phase_cd = phase_cd self.eps_n = None self.f_n = None self.P_ani = None # Only one of these two will be used: self.psit_nG = None # wave functions on 3D grid self.C_nM = None # LCAO coefficients for wave functions XXX self.rho_MM = None self.S_MM = None self.T_MM = None class GlobalKPoint(KPoint): def update(self, wfs): """Distribute requested kpoint data across the kpoint communicator.""" # Locate rank and index of requested k-point nks = len(wfs.kd.ibzk_kc) mynu = len(wfs.kpt_u) kpt_rank, u = divmod(self.k + nks * self.s, mynu) kpt_comm = wfs.kd.comm my_atom_indices = wfs.atom_partition.my_atom_indices mynproj = sum([wfs.setups[a].ni for a in my_atom_indices]) my_P_ni = np.empty((wfs.mynbands, mynproj), wfs.dtype) self.P_ani = {} if self.phase_cd is None: self.phase_cd = np.empty((3,2), wfs.dtype) if self.psit_nG is None: self.psit_nG = wfs.gd.empty(wfs.mynbands, wfs.dtype) reqs = [] # Do I have the requested kpoint? if kpt_comm.rank == kpt_rank: self.phase_cd[:] = wfs.kpt_u[u].phase_cd self.psit_nG[:] = wfs.kpt_u[u].psit_nG # Compress entries in requested P_ani dict into my_P_ni ndarray i = 0 for a,P_ni in wfs.kpt_u[u].P_ani.items(): ni = wfs.setups[a].ni my_P_ni[:,i:i+ni] = P_ni i += ni assert (my_atom_indices == wfs.kpt_u[u].P_ani.keys()).all() # Send phase_cd, psit_nG and my_P_ni to kpoint slaves for rank in range(kpt_comm.size): if rank != kpt_rank: reqs.append(kpt_comm.send(self.phase_cd, rank, 256, False)) reqs.append(kpt_comm.send(self.psit_nG, rank, 257, False)) reqs.append(kpt_comm.send(my_P_ni, rank, 258, False)) else: # Receive phase_cd, psit_nG and my_P_ni from kpoint master reqs.append(kpt_comm.receive(self.phase_cd, kpt_rank, 256, False)) reqs.append(kpt_comm.receive(self.psit_nG, kpt_rank, 257, False)) reqs.append(kpt_comm.receive(my_P_ni, kpt_rank, 258, False)) for request in reqs: kpt_comm.wait(request) # Decompress my_P_ni ndarray into entries in my P_ani dict i = 0 for a in my_atom_indices: ni = wfs.setups[a].ni self.P_ani[a] = my_P_ni[:,i:i+ni] #copy? i += ni gpaw-0.11.0.13004/gpaw/coding_style.py0000664000175000017500000000617212553643470017455 0ustar jensjjensj00000000000000# Copyright (C) 2008 CAMd # Please see the accompanying LICENSE file for further information. """This module is an example of good coding style. This docstring should begin with a one-line description followed by a blank line, and then this paragraph describing in more word what kind of functionality this module implements. After this docstring we have import statements in this order: 1. From the Python standard library. 2. Other libraries (numpy, ase, ...). 3. GPAW stuff. """ from math import pi import numpy as np from ase.units import kJ, Hartree from gpaw import debug from gpaw.fd_operators import Gradient import gpaw.mpi as mpi class SimpleExample: """A simple example class. A headline, a blank line and then this longer description of the class. Here one could put an example of how to use the class:: ex = SimpleExample('Test', (2, 3), int, verbose=False) ex.run(7, verbose=True) """ def __init__(self, name, shape, dtype=float, verbose=True): """Create an example object. Again, headline, blank line, ... . If there are many parameters, there should be a parameter section (see below). If there only a few possible arguments, then the parameter section can be left out and the arguments can be described in the section folowing the headline and blank line (see the `run` method). If a method is real simple and self-explanatory, the docstring can be the headline only (see the `reset` method). Parameters: name : string Name of the example. shape: tuple Shape of the ndarray. dtype: ndarray datatype The datatype of the ndarray. Here, the description can go on to a second line if needed. Make sure that the indentation is like shown here, and remember to end with a period. verbose: boolean Print information about this and that. Other sections: There can be other sections - see bolow and here: http://scipy.org/... """ self.name = name if verbose: print(name) self.a = np.zeros(shape, dtype) self.verbose = verbose def method_with_long_name(self, b, out=None): """Do something very complicated. Long story with all details here ... Parameters: b : ndarray Add this array. out : ndarray Optional output array. Returns: The sum of ... """ if out is none: return self.a + b else: return np.add(self.a, b, out) def run(self, n): """Do something. Do it n times, where n must be a positive integer. The final result bla-bla is returned. """ for i in range(n): self.a += i if self.verbose: print(self.a) return pi * self.a / n + 1 def reset(self): """Simple method - no explanation needed.""" self.a[:] = 0 def function(a, b): """Headline. Long story ...""" return a + b gpaw-0.11.0.13004/gpaw/cli/0000775000175000017500000000000012553644063015160 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/cli/run.py0000664000175000017500000000313512553643472016343 0ustar jensjjensj00000000000000import sys import optparse from ase.cli.run import Runner, str2dict from gpaw import GPAW from gpaw.mixer import Mixer, MixerSum from gpaw.occupations import FermiDirac, MethfesselPaxton from gpaw.wavefunctions.pw import PW class GPAWRunner(Runner): def __init__(self): Runner.__init__(self) self.calculator_name = 'gpaw' def make_parser(self): parser = optparse.OptionParser( usage='gwap run [options] [system, ...]', description='Run calculation for system(s).') return parser def add_options(self, parser): Runner.add_options(self, parser) parser.add_option('-w', '--write', help='Write gpw-file.') parser.add_option('-W', '--write-all', help='Write gpw-file with wave functions.') def set_calculator(self, atoms, name): parameter_namespace = { 'PW': PW, 'FermiDirac': FermiDirac, 'MethfesselPaxton': MethfesselPaxton, 'Mixer': Mixer, 'MixerSum': MixerSum} parameters = str2dict(self.opts.parameters, parameter_namespace) atoms.calc = GPAW(txt=self.get_filename(name, 'txt'), **parameters) def calculate(self, atoms, name): data = Runner.calculate(self, atoms, name) if self.opts.write: atoms.calc.write(self.opts.write) if self.opts.write_all: atoms.calc.write(self.opts.write_all, 'all') return data def main(args=None): runner = GPAWRunner() runner.parse(args) if runner.errors: sys.exit(runner.errors) gpaw-0.11.0.13004/gpaw/cli/quick.py0000664000175000017500000000150012553643472016645 0ustar jensjjensj00000000000000def quick(project='bulk', system=None): """Create Python script to get going quickly. project: str Must be 'bulk' or 'molecule'. system: str A string representing the system ('H2', 'Si'). """ if project == 'bulk': template = """\ from ase.lattice import bulk from gpaw import GPAW atoms = bulk('{0}') atoms.calc = GPAW(kpts={{'size': (4, 4, 4)}}, txt='{0}.txt') e = atoms.get_potential_energy() f = atoms.get_forces()""" else: template = """\ from ase.structure import molecule from ase.optimize import QuasiNewton from gpaw import GPAW atoms = molecule('{0}') atoms.center(vacuum=3.0) atoms.calc = GPAW(txt='{0}.txt') e = atoms.get_potential_energy() opt = QuasiNewton(atoms, traj='{0}.traj') opt.run(fmax=0.05)""" print(template.format(system)) gpaw-0.11.0.13004/gpaw/cli/dos.py0000664000175000017500000000154212553643472016324 0ustar jensjjensj00000000000000from __future__ import print_function import sys from ase.dft.dos import DOS from gpaw import GPAW def dos(filename, plot=False, output='dos.csv', width=0.1): """Calculate density of states. filename: str Name of restart-file. plot: bool Show a plot. output: str Name of CSV output file. width: float Width of Gaussians. """ calc = GPAW(filename, txt=None) dos = DOS(calc, width) D = [dos.get_dos(spin) for spin in range(calc.get_number_of_spins())] if output: fd = sys.stdout if output == '-' else open(output, 'w') for x in zip(dos.energies, *D): print(*x, sep=', ', file=fd) if output != '-': fd.close() if plot: import matplotlib.pyplot as plt for y in D: plt.plot(dos.energies, y) plt.show() gpaw-0.11.0.13004/gpaw/cli/info.py0000664000175000017500000000025112553643472016466 0ustar jensjjensj00000000000000def info(filename): """Write summary of GPAW-restart file. filename: str Name of restart-file. """ from gpaw import GPAW GPAW(filename) gpaw-0.11.0.13004/gpaw/cli/main.py0000664000175000017500000001114612553643472016464 0ustar jensjjensj00000000000000"""GPAW command-line tool.""" from __future__ import print_function import os import sys import inspect import optparse import textwrap functions = {'xc': 'gpaw.xc.xc', 'run': 'gpaw.cli.run.main', 'dos': 'gpaw.cli.dos.dos', 'rpa': 'gpaw.xc.rpa.rpa', 'info': 'gpaw.cli.info.info', 'test': 'gpaw.test.test.main', 'atom': 'gpaw.atom.aeatom.main', 'diag': 'gpaw.fulldiag.fulldiag', 'quick': 'gpaw.cli.quick.quick', 'dataset': 'gpaw.atom.generator2.main', 'symmetry': 'gpaw.symmetry.analyze_atoms'} def main(): commands = sorted(functions.keys()) parser1 = optparse.OptionParser( usage='Usage: gpaw [-h] [-v] [-P N] command [more options]\n' + ' gpaw command --help (for help on individual commands)', description='Run one of these commands: {0}.' .format(', '.join(commands))) parser1.disable_interspersed_args() add = parser1.add_option add('-v', '--verbose', action='store_true') add('-P', '--parallel', type=int, metavar='N', default=1, help="Run on N CPUs.") opts1, args1 = parser1.parse_args() if opts1.parallel > 1: from gpaw.mpi import size if size == 1: # Start again using gpaw-python in parallel: args = ['mpiexec', '-np', str(opts1.parallel), 'gpaw-python'] + sys.argv os.execvp('mpiexec', args) if len(args1) == 0: parser1.print_help() raise SystemExit command = args1[0] modulename, funcname = functions.get(command, command).rsplit('.', 1) module = __import__(modulename, globals(), locals(), [funcname]) func = getattr(module, funcname) kwargs = {} if funcname == 'main': args = [args1[1:]] else: nargs, optnames, parser = construct_parser(func, command) opts, args = parser.parse_args(args1[1:]) if len(args) != nargs: parser.error('Wrong number of arguments!') for optname in optnames: value = getattr(opts, optname) if value is not None: kwargs[optname] = value try: func(*args, **kwargs) except Exception as x: if opts1.verbose: raise else: print('{0}: {1}'.format(x.__class__.__name__, x), file=sys.stderr) print('To get a full traceback, use: gpaw --verbose', file=sys.stderr) def construct_parser(func, name): """Construct parser from function arguments and docstring.""" args, varargs, keywords, defaults = inspect.getargspec(func) assert varargs is None assert keywords is None if defaults: optnames = args[-len(defaults):] defaults = dict(zip(optnames, defaults)) del args[-len(defaults):] else: optnames = [] defaults = {} doc = func.__doc__ headline, doc = doc.split('\n', 1) lines = textwrap.dedent(doc).splitlines() description = None options = [] shortoptions = set() i = 0 while i < len(lines): words = lines[i].split(':') if (len(words) > 1 and i + 1 < len(lines) and lines[i + 1].startswith(' ')): if description is None: description = ' '.join([headline] + lines[:i]) arg = words[0] help = [] type = words[1].strip() i += 1 while i < len(lines) and lines[i].startswith(' '): help.append(lines[i][4:]) i += 1 kwargs = {'help': ' '.join(help)} if arg not in defaults: continue default = defaults.get(arg) if type == 'bool': kwargs['action'] = 'store_' + str(not default).lower() else: kwargs['type'] = type if default is not None: kwargs['default'] = default short = arg[0] if short in shortoptions: short = arg[1] shortoptions.add(short) options.append(optparse.Option('-' + short, '--' + arg.replace('_', '-'), **kwargs)) else: if description: break i += 1 epilog = ' '.join(lines[i:]) parser = optparse.OptionParser( usage='Usage: gpaw {0} <{1}> [options]'.format(name, '> <'.join(args)), description=description, option_list=options, epilog=epilog) return len(args), optnames, parser gpaw-0.11.0.13004/gpaw/cli/__init__.py0000664000175000017500000000000012553643472017262 0ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/lrtddft/0000775000175000017500000000000012553644063016054 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/lrtddft/excited_state.py0000664000175000017500000003403312553643472021261 0ustar jensjjensj00000000000000"""Excited state as calculator object.""" import sys import numpy as np from ase.utils import prnt from ase.units import Hartree from ase.calculators.general import Calculator from ase.calculators.test import numeric_force from ase.utils.timing import Timer from ase.parallel import distribute_cpus from gpaw import GPAW from gpaw.density import RealSpaceDensity from gpaw.output import get_txt from gpaw import mpi from gpaw.utilities.blas import axpy from gpaw.wavefunctions.lcao import LCAOWaveFunctions from gpaw.version import version class FiniteDifferenceCalculator(Calculator): def __init__(self, lrtddft, d=0.001, txt=None, parallel=None): """Finite difference calculator for LrTDDFT. parallel: Can be used to parallelize the numerical force calculation over images """ self.timer = Timer() self.atoms = None world = mpi.world if lrtddft is not None: self.lrtddft = lrtddft self.calculator = self.lrtddft.calculator self.atoms = self.calculator.atoms if self.calculator.initialized: world = self.calculator.wfs.world if txt is None: self.txt = self.lrtddft.txt else: self.txt = get_txt(txt, world.rank) prnt('#', self.__class__.__name__, version, file=self.txt) self.d = d self.parallel = { 'world': world, 'mycomm': world, 'ncalcs': 1, 'icalc': 0} if world.size < 2: if parallel: prnt('#', (self.__class__.__name__ + ':'), 'Serial calculation, keyword parallel ignored.', file=self.txt) elif parallel: mycomm, ncalcs, icalc = distribute_cpus(parallel, world) if not isinstance(ncalcs, int): # this is ase < r3431 ncalcs = world.size / parallel self.parallel = {'world': world, 'mycomm': mycomm, 'ncalcs': ncalcs, 'icalc': icalc} self.calculator.set(communicator=mycomm) def set(self, **kwargs): self.calculator.set(**kwargs) class ExcitedState(FiniteDifferenceCalculator, GPAW): def __init__(self, lrtddft, index, d=0.001, txt=None, parallel=None, name=None): """ExcitedState object. parallel: Can be used to parallelize the numerical force calculation over images. """ FiniteDifferenceCalculator.__init__(self, lrtddft, d, txt, parallel) if isinstance(index, int): self.index = UnconstraintIndex(index) else: self.index = index self.name = name self.energy = None self.F_av = None prnt('#', self.index, file=self.txt) if name: prnt(('name=' + name), file=self.txt) prnt('# Force displacement:', self.d, file=self.txt) if self.parallel: prnt('#', self.parallel['world'].size, 'cores in total, ', self.parallel['mycomm'].size, 'cores per energy evaluation', file=self.txt) def set_positions(self, atoms): """Update the positions of the atoms.""" self.atoms = atoms.copy() self.energy = None self.F_av = None self.atoms.set_calculator(self) def calculation_required(self, atoms, quantities): if len(quantities) == 0: return False if self.atoms is None: return True elif (len(atoms) != len(self.atoms) or (atoms.get_atomic_numbers() != self.atoms.get_atomic_numbers()).any() or (atoms.get_initial_magnetic_moments() != self.atoms.get_initial_magnetic_moments()).any() or (atoms.get_cell() != self.atoms.get_cell()).any() or (atoms.get_pbc() != self.atoms.get_pbc()).any()): return True elif (atoms.get_positions() != self.atoms.get_positions()).any(): return True for quantity in ['energy', 'F_av']: if quantity in quantities: quantities.remove(quantity) if self.__dict__[quantity] is None: return True return len(quantities) > 0 def get_potential_energy(self, atoms=None): """Evaluate potential energy for the given excitation.""" if atoms is None: atoms = self.atoms if self.calculation_required(atoms, ['energy']): self.energy = self.calculate(atoms) return self.energy def calculate(self, atoms): """Evaluate your energy if needed.""" self.set_positions(atoms) self.calculator.calculate(atoms) E0 = self.calculator.get_potential_energy() if hasattr(self, 'density'): del(self.density) self.lrtddft.forced_update() self.lrtddft.diagonalize() index = self.index.apply(self.lrtddft) energy = E0 + self.lrtddft[index].energy * Hartree return energy def get_forces(self, atoms=None): """Get finite-difference forces""" if atoms is None: atoms = self.atoms if self.calculation_required(atoms, ['F_av']): atoms.set_calculator(self) # do the ground state calculation to set all # ranks to the same density to start with self.calculator.calculate(atoms) world = self.parallel['world'] txt = self.txt if world.rank > 0: txt = sys.stdout mycomm = self.parallel['mycomm'] ncalcs = self.parallel['ncalcs'] icalc = self.parallel['icalc'] F_av = np.zeros((len(atoms), 3)) i = 0 for ia, a in enumerate(self.atoms): for ic in range(3): # print "ncalcs", ncalcs, "i", i, "icalc",icalc if (i % ncalcs) == icalc: F_av[ia, ic] = numeric_force( atoms, ia, ic, self.d) / mycomm.size prnt('# rank', world.rank, '-> force', (str(ia) + 'xyz'[ic]), file=txt) i += 1 energy = np.array([0.]) # array needed for world.sum() if (i % ncalcs) == icalc: self.energy = None energy[0] = self.get_potential_energy(atoms) / mycomm.size prnt('# rank', world.rank, '-> energy', energy[0] * mycomm.size, file=txt) self.set_positions(atoms) world.sum(F_av) world.sum(energy) self.energy = energy[0] self.F_av = F_av if self.txt: prnt('Excited state forces in eV/Ang:', file=self.txt) symbols = self.atoms.get_chemical_symbols() for a, symbol in enumerate(symbols): prnt(('%3d %-2s %10.5f %10.5f %10.5f' % ((a, symbol) + tuple(self.F_av[a]))), file=self.txt) return self.F_av def get_stress(self, atoms): """Return the stress for the current state of the Atoms.""" raise NotImplementedError def initialize_density(self, method='dipole'): if hasattr(self, 'density') and self.density.method == method: return gsdensity = self.calculator.density lr = self.lrtddft self.density = ExcitedStateDensity( gsdensity.gd, gsdensity.finegd, lr.kss.npspins, gsdensity.charge, method=method) index = self.index.apply(self.lrtddft) self.density.initialize(self.lrtddft, index) self.density.update(self.calculator.wfs) def get_pseudo_density(self, **kwargs): """Return pseudo-density array.""" method = kwargs.pop('method', 'dipole') self.initialize_density(method) return GPAW.get_pseudo_density(self, **kwargs) def get_all_electron_density(self, **kwargs): """Return all electron density array.""" method = kwargs.pop('method', 'dipole') self.initialize_density(method) return GPAW.get_all_electron_density(self, **kwargs) class UnconstraintIndex: def __init__(self, index): self.index = index def apply(self, *argv): return self.index def __str__(self): return (self.__class__.__name__ + '(' + str(self.index) + ')') class MinimalOSIndex: """ Constraint on minimal oscillator strength. Searches for the first excitation that has a larger oscillator strength than the given minimum. direction: None: averaged (default) 0, 1, 2: x, y, z """ def __init__(self, fmin=0.02, direction=None): self.fmin = fmin self.direction = direction def apply(self, lrtddft): i = 0 fmax = 0. idir = 0 if self.direction is not None: idir = 1 + self.direction while i < len(lrtddft): ex = lrtddft[i] f = ex.get_oscillator_strength()[idir] fmax = max(f, fmax) if f > self.fmin: return i i += 1 error = 'The intensity constraint |f| > ' + str(self.fmin) + ' ' error += 'can not be satisfied (max(f) = ' + str(fmax) + ').' raise RuntimeError(error) class MaximalOSIndex: """ Select maximal oscillator strength. Searches for the excitation with maximal oscillator strength in a given energy range. energy_range: None: take all (default) [Emin, Emax]: take only transition in this energy range Emax: the same as [0, Emax] direction: None: averaged (default) 0, 1, 2: x, y, z """ def __init__(self, energy_range=None, direction=None): if energy_range is None: energy_range = np.array([0.0, 1.e32]) elif isinstance(energy_range, (int, float)): energy_range = np.array([0.0, energy_range]) / Hartree self.energy_range = energy_range self.direction = direction def apply(self, lrtddft): index = None fmax = 0. idir = 0 if self.direction is not None: idir = 1 + self.direction emin, emax = self.energy_range for i, ex in enumerate(lrtddft): f = ex.get_oscillator_strength()[idir] e = ex.get_energy() if e >= emin and e < emax and f > fmax: fmax = f index = i if index is None: raise RuntimeError('No transition in the energy range ' + '[%g,%g]' % self.energy_range) return index class ExcitedStateDensity(RealSpaceDensity): """Approximate excited state density object.""" def __init__(self, *args, **kwargs): self.method = kwargs.pop('method', 'dipole') RealSpaceDensity.__init__(self, *args, **kwargs) def initialize(self, lrtddft, index): self.lrtddft = lrtddft self.index = index calc = lrtddft.calculator self.gsdensity = calc.density self.gd = self.gsdensity.gd self.nbands = calc.wfs.bd.nbands # obtain weights ex = lrtddft[index] wocc_sn = np.zeros((self.nspins, self.nbands)) wunocc_sn = np.zeros((self.nspins, self.nbands)) for f, k in zip(ex.f, ex.kss): # XXX why not k.fij * k.energy / energy ??? if self.method == 'dipole': erat = k.energy / ex.energy elif self.method == 'orthogonal': erat = 1. else: raise NotImplementedError( 'method should be either "dipole" or "orthogonal"') wocc_sn[k.pspin, k.i] += erat * f ** 2 wunocc_sn[k.pspin, k.j] += erat * f ** 2 self.wocc_sn = wocc_sn self.wunocc_sn = wunocc_sn RealSpaceDensity.initialize( self, calc.wfs.setups, calc.timer, None, False) spos_ac = calc.get_atoms().get_scaled_positions() % 1.0 self.set_positions(spos_ac, calc.wfs.atom_partition) D_asp = {} for a, D_sp in self.gsdensity.D_asp.items(): repeats = self.ns // self.gsdensity.ns # XXX does this work always? D_asp[a] = (1. * D_sp).repeat(repeats, axis=0) self.D_asp = D_asp def update(self, wfs): self.timer.start('Density') self.timer.start('Pseudo density') self.calculate_pseudo_density(wfs) self.timer.stop('Pseudo density') self.timer.start('Atomic density matrices') f_un = [] for kpt in wfs.kpt_u: f_n = kpt.f_n - self.wocc_sn[kpt.s] + self.wunocc_sn[kpt.s] if self.nspins > self.gsdensity.nspins: f_n = kpt.f_n - self.wocc_sn[1] + self.wunocc_sn[1] f_un.append(f_n) wfs.calculate_atomic_density_matrices_with_occupation(self.D_asp, f_un) self.timer.stop('Atomic density matrices') self.timer.start('Multipole moments') comp_charge = self.calculate_multipole_moments() self.timer.stop('Multipole moments') if isinstance(wfs, LCAOWaveFunctions): self.timer.start('Normalize') self.normalize(comp_charge) self.timer.stop('Normalize') self.timer.stop('Density') def calculate_pseudo_density(self, wfs): """Calculate nt_sG from scratch. nt_sG will be equal to nct_G plus the contribution from wfs.add_to_density(). """ nvspins = wfs.kd.nspins npspins = self.nspins self.nt_sG = self.gd.zeros(npspins) for s in range(npspins): for kpt in wfs.kpt_u: if s == kpt.s or npspins > nvspins: f_n = kpt.f_n / (1. + int(npspins > nvspins)) for f, psit_G in zip((f_n - self.wocc_sn[s] + self.wunocc_sn[s]), kpt.psit_nG): axpy(f, psit_G ** 2, self.nt_sG[s]) self.nt_sG[:self.nspins] += self.nct_G gpaw-0.11.0.13004/gpaw/lrtddft/omega_matrix.py0000664000175000017500000005623112553643472021114 0ustar jensjjensj00000000000000from __future__ import print_function from math import sqrt import numpy as np import gpaw.mpi as mpi MASTER = mpi.MASTER from ase.units import Hartree from ase.utils.timing import Timer import gpaw.mpi as mpi #from gpaw.poisson import PoissonSolver from gpaw.output import get_txt from gpaw.lrtddft.kssingle import KSSingles from gpaw.transformers import Transformer from gpaw.utilities import pack from gpaw.utilities.lapack import diagonalize from gpaw.xc import XC """This module defines a Omega Matrix class.""" class OmegaMatrix: """ Omega matrix in Casidas linear response formalism Parameters - calculator: the calculator object the ground state calculation - kss: the Kohn-Sham singles object - xc: the exchange correlation approx. to use - derivativeLevel: which level i of d^i Exc/dn^i to use - numscale: numeric epsilon for derivativeLevel=0,1 - filehandle: the oject can be read from a filehandle - txt: output stream or file name - finegrid: level of fine grid to use. 0: nothing, 1 for poisson only, 2 everything on the fine grid """ def __init__(self, calculator=None, kss=None, xc=None, derivativeLevel=None, numscale=0.001, filehandle=None, txt=None, finegrid=2, eh_comm=None, ): if not txt and calculator: txt = calculator.txt self.txt = get_txt(txt, mpi.rank) if eh_comm is None: eh_comm = mpi.serial_comm self.eh_comm = eh_comm if filehandle is not None: self.kss = kss self.read(fh=filehandle) return None self.fullkss = kss self.finegrid = finegrid if calculator is None: return self.paw = calculator wfs = self.paw.wfs # handle different grid possibilities self.restrict = None # self.poisson = PoissonSolver(nn=self.paw.hamiltonian.poisson.nn) self.poisson = calculator.hamiltonian.poisson if finegrid: self.poisson.set_grid_descriptor(self.paw.density.finegd) self.poisson.initialize() self.gd = self.paw.density.finegd if finegrid == 1: self.gd = wfs.gd else: self.poisson.set_grid_descriptor(wfs.gd) self.poisson.initialize() self.gd = wfs.gd self.restrict = Transformer(self.paw.density.finegd, wfs.gd, self.paw.input_parameters.stencils[1] ).apply if xc == 'RPA': xc = None # enable RPA as keyword if xc is not None: self.xc = XC(xc) self.xc.initialize(self.paw.density, self.paw.hamiltonian, wfs, self.paw.occupations) # check derivativeLevel if derivativeLevel is None: derivativeLevel = \ self.xc.get_functional().get_max_derivative_level() self.derivativeLevel = derivativeLevel else: self.xc = None self.numscale = numscale self.singletsinglet = False if kss.nvspins < 2 and kss.npspins < 2: # this will be a singlet to singlet calculation only self.singletsinglet = True nij = len(kss) self.Om = np.zeros((nij, nij)) self.get_full() def get_full(self): self.paw.timer.start('Omega RPA') self.get_rpa() self.paw.timer.stop() if self.xc is not None: self.paw.timer.start('Omega XC') self.get_xc() self.paw.timer.stop() self.eh_comm.sum(self.Om) self.full = self.Om def get_xc(self): """Add xc part of the coupling matrix""" # shorthands paw = self.paw wfs = paw.wfs gd = paw.density.finegd eh_comm = self.eh_comm fg = self.finegrid is 2 kss = self.fullkss nij = len(kss) Om_xc = self.Om # initialize densities # nt_sg is the smooth density on the fine grid with spin index if kss.nvspins == 2: # spin polarised ground state calc. nt_sg = paw.density.nt_sg else: # spin unpolarised ground state calc. if kss.npspins == 2: # construct spin polarised densities nt_sg = np.array([.5 * paw.density.nt_sg[0], .5 * paw.density.nt_sg[0]]) else: nt_sg = paw.density.nt_sg # check if D_sp have been changed before D_asp = {} for a, D_sp in self.paw.density.D_asp.items(): if len(D_sp) != kss.npspins: if len(D_sp) == 1: D_asp[a] = np.array([0.5 * D_sp[0], 0.5 * D_sp[0]]) else: D_asp[a] = np.array([D_sp[0] + D_sp[1]]) else: D_asp[a] = D_sp.copy() # restrict the density if needed if fg: nt_s = nt_sg else: nt_s = self.gd.zeros(nt_sg.shape[0]) for s in range(nt_sg.shape[0]): self.restrict(nt_sg[s], nt_s[s]) gd = paw.density.gd # initialize vxc or fxc if self.derivativeLevel == 0: raise NotImplementedError if kss.npspins == 2: v_g = nt_sg[0].copy() else: v_g = nt_sg.copy() elif self.derivativeLevel == 1: pass elif self.derivativeLevel == 2: fxc_sg = np.zeros(nt_sg.shape) self.xc.calculate_fxc(gd, nt_sg, fxc_sg) else: raise ValueError('derivativeLevel can only be 0,1,2') # self.paw.my_nuclei = [] ns = self.numscale xc = self.xc print('XC', nij, 'transitions', file=self.txt) for ij in range(eh_comm.rank, nij, eh_comm.size): print('XC kss[' + '%d' % ij + ']', file=self.txt) timer = Timer() timer.start('init') timer2 = Timer() if self.derivativeLevel >= 1: # vxc is available # We use the numerical two point formula for calculating # the integral over fxc*n_ij. The results are # vvt_s smooth integral # nucleus.I_sp atom based correction matrices (pack2) # stored on each nucleus timer2.start('init v grids') vp_s = np.zeros(nt_s.shape, nt_s.dtype.char) vm_s = np.zeros(nt_s.shape, nt_s.dtype.char) if kss.npspins == 2: # spin polarised nv_s = nt_s.copy() nv_s[kss[ij].pspin] += ns * kss[ij].get(fg) xc.calculate(gd, nv_s, vp_s) nv_s = nt_s.copy() nv_s[kss[ij].pspin] -= ns * kss[ij].get(fg) xc.calculate(gd, nv_s, vm_s) else: # spin unpolarised nv = nt_s + ns * kss[ij].get(fg) xc.calculate(gd, nv, vp_s) nv = nt_s - ns * kss[ij].get(fg) xc.calculate(gd, nv, vm_s) vvt_s = (0.5 / ns) * (vp_s - vm_s) timer2.stop() # initialize the correction matrices timer2.start('init v corrections') I_asp = {} for a, P_ni in wfs.kpt_u[kss[ij].spin].P_ani.items(): # create the modified density matrix Pi_i = P_ni[kss[ij].i] Pj_i = P_ni[kss[ij].j] P_ii = np.outer(Pi_i, Pj_i) # we need the symmetric form, hence we can pack P_p = pack(P_ii) D_sp = D_asp[a].copy() D_sp[kss[ij].pspin] -= ns * P_p setup = wfs.setups[a] I_sp = np.zeros_like(D_sp) self.xc.calculate_paw_correction(setup, D_sp, I_sp) I_sp *= -1.0 D_sp = D_asp[a].copy() D_sp[kss[ij].pspin] += ns * P_p self.xc.calculate_paw_correction(setup, D_sp, I_sp) I_sp /= 2.0 * ns I_asp[a] = I_sp timer2.stop() timer.stop() t0 = timer.get_time('init') timer.start(ij) for kq in range(ij, nij): weight = self.weight_Kijkq(ij, kq) if self.derivativeLevel == 0: # only Exc is available if kss.npspins == 2: # spin polarised nv_g = nt_sg.copy() nv_g[kss[ij].pspin] += kss[ij].get(fg) nv_g[kss[kq].pspin] += kss[kq].get(fg) Excpp = xc.get_energy_and_potential( nv_g[0], v_g, nv_g[1], v_g) nv_g = nt_sg.copy() nv_g[kss[ij].pspin] += kss[ij].get(fg) nv_g[kss[kq].pspin] -= kss[kq].get(fg) Excpm = xc.get_energy_and_potential( nv_g[0], v_g, nv_g[1], v_g) nv_g = nt_sg.copy() nv_g[kss[ij].pspin] -=\ kss[ij].get(fg) nv_g[kss[kq].pspin] +=\ kss[kq].get(fg) Excmp = xc.get_energy_and_potential( nv_g[0], v_g, nv_g[1], v_g) nv_g = nt_sg.copy() nv_g[kss[ij].pspin] -= \ kss[ij].get(fg) nv_g[kss[kq].pspin] -=\ kss[kq].get(fg) Excpp = xc.get_energy_and_potential( nv_g[0], v_g, nv_g[1], v_g) else: # spin unpolarised nv_g = nt_sg + ns * kss[ij].get(fg)\ + ns * kss[kq].get(fg) Excpp = xc.get_energy_and_potential(nv_g, v_g) nv_g = nt_sg + ns * kss[ij].get(fg)\ - ns * kss[kq].get(fg) Excpm = xc.get_energy_and_potential(nv_g, v_g) nv_g = nt_sg - ns * kss[ij].get(fg)\ + ns * kss[kq].get(fg) Excmp = xc.get_energy_and_potential(nv_g, v_g) nv_g = nt_sg - ns * kss[ij].get(fg)\ - ns * kss[kq].get(fg) Excmm = xc.get_energy_and_potential(nv_g, v_g) Om_xc[ij, kq] += weight *\ 0.25 * \ (Excpp - Excmp - Excpm + Excmm) / (ns * ns) elif self.derivativeLevel == 1: # vxc is available timer2.start('integrate') Om_xc[ij, kq] += weight *\ self.gd.integrate(kss[kq].get(fg) * vvt_s[kss[kq].pspin]) timer2.stop() timer2.start('integrate corrections') Exc = 0. for a, P_ni in wfs.kpt_u[kss[kq].spin].P_ani.items(): # create the modified density matrix Pk_i = P_ni[kss[kq].i] Pq_i = P_ni[kss[kq].j] P_ii = np.outer(Pk_i, Pq_i) # we need the symmetric form, hence we can pack # use pack as I_sp used pack2 P_p = pack(P_ii) Exc += np.dot(I_asp[a][kss[kq].pspin], P_p) Om_xc[ij, kq] += weight * self.gd.comm.sum(Exc) timer2.stop() elif self.derivativeLevel == 2: # fxc is available if kss.npspins == 2: # spin polarised Om_xc[ij, kq] += weight *\ gd.integrate(kss[ij].get(fg) * kss[kq].get(fg) * fxc_sg[kss[ij].pspin, kss[kq].pspin]) else: # spin unpolarised Om_xc[ij, kq] += weight *\ gd.integrate(kss[ij].get(fg) * kss[kq].get(fg) * fxc_sg) # XXX still numeric derivatives for local terms timer2.start('integrate corrections') Exc = 0. for a, P_ni in wfs.kpt_u[kss[kq].spin].P_ani.items(): # create the modified density matrix Pk_i = P_ni[kss[kq].i] Pq_i = P_ni[kss[kq].j] P_ii = np.outer(Pk_i, Pq_i) # we need the symmetric form, hence we can pack # use pack as I_sp used pack2 P_p = pack(P_ii) Exc += np.dot(I_asp[a][kss[kq].pspin], P_p) Om_xc[ij, kq] += weight * self.gd.comm.sum(Exc) timer2.stop() if ij != kq: Om_xc[kq, ij] = Om_xc[ij, kq] timer.stop() # timer2.write() if ij < (nij - 1): print('XC estimated time left', self.time_left(timer, t0, ij, nij), file=self.txt) def Coulomb_integral_kss(self, kss_ij, kss_kq, phit, rhot, timer=None): # smooth part if timer: timer.start('integrate') I = self.gd.integrate(rhot * phit) if timer: timer.stop() timer.start('integrate corrections 2') wfs = self.paw.wfs Pij_ani = wfs.kpt_u[kss_ij.spin].P_ani Pkq_ani = wfs.kpt_u[kss_kq.spin].P_ani # Add atomic corrections Ia = 0.0 for a, Pij_ni in Pij_ani.items(): Pi_i = Pij_ni[kss_ij.i] Pj_i = Pij_ni[kss_ij.j] Dij_ii = np.outer(Pi_i, Pj_i) Dij_p = pack(Dij_ii) Pk_i = Pkq_ani[a][kss_kq.i] Pq_i = Pkq_ani[a][kss_kq.j] Dkq_ii = np.outer(Pk_i, Pq_i) Dkq_p = pack(Dkq_ii) C_pp = wfs.setups[a].M_pp # ---- # 2 > P P C P P # ---- ip jr prst ks qt # prst Ia += 2.0 * np.dot(Dkq_p, np.dot(C_pp, Dij_p)) I += self.gd.comm.sum(Ia) if timer: timer.stop() return I def get_rpa(self): """calculate RPA part of the omega matrix""" # shorthands kss = self.fullkss finegrid = self.finegrid eh_comm = self.eh_comm # calculate omega matrix nij = len(kss) print('RPA', nij, 'transitions', file=self.txt) Om = self.Om for ij in range(eh_comm.rank, nij, eh_comm.size): print('RPA kss[' + '%d' % ij + ']=', kss[ij], file=self.txt) timer = Timer() timer.start('init') timer2 = Timer() # smooth density including compensation charges timer2.start('with_compensation_charges 0') rhot_p = kss[ij].with_compensation_charges( finegrid is not 0) timer2.stop() # integrate with 1/|r_1-r_2| timer2.start('poisson') phit_p = np.zeros(rhot_p.shape, rhot_p.dtype.char) self.poisson.solve(phit_p, rhot_p, charge=None) timer2.stop() timer.stop() t0 = timer.get_time('init') timer.start(ij) if finegrid == 1: rhot = kss[ij].with_compensation_charges() phit = self.gd.zeros() # print "shapes 0=",phit.shape,rhot.shape self.restrict(phit_p, phit) else: phit = phit_p rhot = rhot_p for kq in range(ij, nij): if kq != ij: # smooth density including compensation charges timer2.start('kq with_compensation_charges') rhot = kss[kq].with_compensation_charges( finegrid is 2) timer2.stop() pre = 2 * sqrt(kss[ij].get_energy() * kss[kq].get_energy() * kss[ij].get_weight() * kss[kq].get_weight()) I = self.Coulomb_integral_kss(kss[ij], kss[kq], rhot, phit, timer2) Om[ij, kq] = pre * I if ij == kq: Om[ij, kq] += kss[ij].get_energy() ** 2 else: Om[kq, ij] = Om[ij, kq] timer.stop() # timer2.write() if ij < (nij - 1): t = timer.get_time(ij) # time for nij-ij calculations t = .5 * t * \ (nij - ij) # estimated time for n*(n+1)/2, n=nij-(ij+1) print('RPA estimated time left', self.timestring(t0 * (nij - ij - 1) + t), file=self.txt) def singlets_triplets(self): """Split yourself into singlet and triplet transitions""" assert(self.fullkss.npspins == 2) assert(self.fullkss.nvspins == 1) # strip kss from down spins skss = KSSingles() tkss = KSSingles() map = [] for ij, ks in enumerate(self.fullkss): if ks.pspin == ks.spin: skss.append((ks + ks) / sqrt(2)) tkss.append((ks - ks) / sqrt(2)) map.append(ij) nkss = len(skss) # define the singlet and the triplet omega-matrixes sOm = OmegaMatrix(kss=skss) sOm.full = np.empty((nkss, nkss)) tOm = OmegaMatrix(kss=tkss) tOm.full = np.empty((nkss, nkss)) for ij in range(nkss): for kl in range(nkss): sOm.full[ij, kl] = (self.full[map[ij], map[kl]] + self.full[map[ij], nkss + map[kl]]) tOm.full[ij, kl] = (self.full[map[ij], map[kl]] - self.full[map[ij], nkss + map[kl]]) return sOm, tOm def timestring(self, t): ti = int(t + 0.5) td = ti // 86400 st = '' if td > 0: st += '%d' % td + 'd' ti -= td * 86400 th = ti // 3600 if th > 0: st += '%d' % th + 'h' ti -= th * 3600 tm = ti // 60 if tm > 0: st += '%d' % tm + 'm' ti -= tm * 60 st += '%d' % ti + 's' return st def time_left(self, timer, t0, ij, nij): t = timer.get_time(ij) # time for nij-ij calculations t = .5 * t * (nij - ij) # estimated time for n*(n+1)/2, n=nij-(ij+1) return self.timestring(t0 * (nij - ij - 1) + t) def get_map(self, istart=None, jend=None, energy_range=None): """Return the reduction map for the given requirements""" self.istart = istart self.jend = jend if istart is None and jend is None and energy_range is None: return None, self.fullkss # reduce the matrix print('# diagonalize: %d transitions original' % len(self.fullkss), file=self.txt) if energy_range is None: if istart is None: istart = self.kss.istart if self.fullkss.istart > istart: raise RuntimeError('istart=%d has to be >= %d' % (istart, self.kss.istart)) if jend is None: jend = self.kss.jend if self.fullkss.jend < jend: raise RuntimeError('jend=%d has to be <= %d' % (jend, self.kss.jend)) else: try: emin, emax = energy_range except: emax = energy_range emin = 0. emin /= Hartree emax /= Hartree map = [] kss = KSSingles() for ij, k in zip(range(len(self.fullkss)), self.fullkss): if energy_range is None: if k.i >= istart and k.j <= jend: kss.append(k) map.append(ij) else: if k.energy >= emin and k.energy < emax: kss.append(k) map.append(ij) kss.update() print('# diagonalize: %d transitions now' % len(kss), file=self.txt) return map, kss def diagonalize(self, istart=None, jend=None, energy_range=None, TDA=False): """Evaluate Eigenvectors and Eigenvalues:""" if TDA: raise NotImplementedError map, kss = self.get_map(istart, jend, energy_range) nij = len(kss) if map is None: evec = self.full.copy() else: evec = np.zeros((nij, nij)) for ij in range(nij): for kq in range(nij): evec[ij, kq] = self.full[map[ij], map[kq]] assert(len(evec) > 0) self.eigenvectors = evec self.eigenvalues = np.zeros((len(kss))) self.kss = kss diagonalize(self.eigenvectors, self.eigenvalues) def Kss(self, kss=None): """Set and get own Kohn-Sham singles""" if kss is not None: self.fullkss = kss if(hasattr(self, 'fullkss')): return self.fullkss else: return None def read(self, filename=None, fh=None): """Read myself from a file""" if fh is None: f = open(filename, 'r') else: f = fh f.readline() nij = int(f.readline()) full = np.zeros((nij, nij)) for ij in range(nij): l = f.readline().split() for kq in range(ij, nij): full[ij, kq] = float(l[kq - ij]) full[kq, ij] = full[ij, kq] self.full = full if fh is None: f.close() def write(self, filename=None, fh=None): """Write current state to a file.""" if mpi.rank == mpi.MASTER: if fh is None: f = open(filename, 'w') else: f = fh f.write('# OmegaMatrix\n') nij = len(self.fullkss) f.write('%d\n' % nij) for ij in range(nij): for kq in range(ij, nij): f.write(' %g' % self.full[ij, kq]) f.write('\n') if fh is None: f.close() def weight_Kijkq(self, ij, kq): """weight for the coupling matrix terms""" kss = self.fullkss return 2. * sqrt(kss[ij].get_energy() * kss[kq].get_energy() * kss[ij].get_weight() * kss[kq].get_weight()) def __str__(self): str = ' ' if hasattr(self, 'eigenvalues'): str += 'dimension ' + ('%d' % len(self.eigenvalues)) str += '\neigenvalues: ' for ev in self.eigenvalues: str += ' ' + ('%f' % (sqrt(ev) * Hartree)) return str gpaw-0.11.0.13004/gpaw/lrtddft/kssingle.py0000664000175000017500000004526712553643472020266 0ustar jensjjensj00000000000000"""Kohn-Sham single particle excitations realated objects. """ from __future__ import print_function import sys from math import pi, sqrt import numpy as np from ase.units import Bohr, Hartree, alpha from ase.parallel import paropen import gpaw.mpi as mpi from gpaw.utilities import packed_index from gpaw.lrtddft.excitation import Excitation, ExcitationList from gpaw.pair_density import PairDensity from gpaw.fd_operators import Gradient from gpaw.utilities.tools import coordinates class KSSingles(ExcitationList): """Kohn-Sham single particle excitations Input parameters: calculator: the calculator object after a ground state calculation nspins: number of spins considered in the calculation Note: Valid only for unpolarised ground state calculation eps: Minimal occupation difference for a transition (default 0.001) istart: First occupied state to consider jend: Last unoccupied state to consider energy_range: The energy range [emin, emax] or emax for KS transitions to use as basis """ def __init__(self, calculator=None, nspins=None, eps=0.001, istart=0, jend=sys.maxsize, energy_range=None, filehandle=None, txt=None): self.eps = None if isinstance(calculator, str): filehandle = open(calculator) if filehandle is not None: self.world = mpi.world self.read(fh=filehandle, istart=istart, jend=jend) return None # LCAO calculation requires special actions if calculator is not None: self.lcao = calculator.input_parameters.mode == 'lcao' ExcitationList.__init__(self, calculator, txt=txt) if calculator is None: return # leave the list empty # deny hybrids as their empty states are wrong # gsxc = calculator.hamiltonian.xc # hybrid = hasattr(gsxc, 'hybrid') and gsxc.hybrid > 0.0 # assert(not hybrid) # ensure correctly initialized wave functions calculator.converge_wave_functions() self.world = calculator.wfs.world # parallelization over bands not yet supported assert(calculator.wfs.band_comm.size == 1) self.select(nspins, eps, istart, jend, energy_range) trkm = self.get_trk() print('KSS TRK sum %g (%g,%g,%g)' % (np.sum(trkm) / 3., trkm[0], trkm[1], trkm[2]), file=self.txt) pol = self.get_polarizabilities(lmax=3) print('KSS polarisabilities(l=0-3) %g, %g, %g, %g' % tuple(pol.tolist()), file=self.txt) def select(self, nspins=None, eps=0.001, istart=0, jend=sys.maxsize, energy_range=None): """Select KSSingles according to the given criterium.""" paw = self.calculator wfs = paw.wfs self.dtype = wfs.dtype self.kpt_u = wfs.kpt_u if not self.lcao and self.kpt_u[0].psit_nG is None: raise RuntimeError('No wave functions in calculator!') # criteria emin = -sys.float_info.max emax = sys.float_info.max if energy_range is not None: try: emin, emax = energy_range emin /= Hartree emax /= Hartree except: emax = energy_range / Hartree self.istart = istart self.jend = jend self.eps = eps # here, we need to take care of the spins also for # closed shell systems (Sz=0) # vspin is the virtual spin of the wave functions, # i.e. the spin used in the ground state calculation # pspin is the physical spin of the wave functions # i.e. the spin of the excited states self.nvspins = wfs.nspins self.npspins = wfs.nspins fijscale = 1 ispins = [0] nks = wfs.kd.nks if self.nvspins < 2: if (nspins or 0) > self.nvspins: self.npspins = nspins fijscale = 0.5 ispins = [0, 1] nks = 2 * wfs.kd.nks kpt_comm = self.calculator.wfs.kd.comm nbands = len(self.kpt_u[0].f_n) # select take = np.zeros((nks, nbands, nbands), dtype=int) u = 0 for ispin in ispins: for ks in range(wfs.kd.nks): myks = ks - wfs.kd.ks0 if myks >= 0 and myks < wfs.kd.mynks: kpt = self.kpt_u[myks] for i in range(nbands): for j in range(i + 1, nbands): fij = kpt.f_n[i] - kpt.f_n[j] epsij = kpt.eps_n[j] - kpt.eps_n[i] if (fij > eps and epsij >= emin and epsij < emax and i >= self.istart and j <= self.jend): take[u, i, j] = 1 u += 1 kpt_comm.sum(take) # calculate in parallel u = 0 for ispin in ispins: for ks in range(wfs.kd.nks): myks = ks - wfs.kd.ks0 for i in range(nbands): for j in range(i + 1, nbands): if take[u, i, j]: if myks >= 0 and myks < wfs.kd.mynks: kpt = self.kpt_u[myks] pspin = max(kpt.s, ispin) self.append( KSSingle(i, j, pspin, kpt, paw, fijscale=fijscale, dtype=self.dtype)) else: self.append(KSSingle(i, j, pspin=0, kpt=None, paw=paw, dtype=self.dtype)) u += 1 # distribute for kss in self: kss.distribute() def read(self, filename=None, fh=None, istart=0, jend=sys.maxsize): """Read myself from a file""" if fh is None: if filename.endswith('.gz'): import gzip f = gzip.open(filename) else: f = open(filename, 'r') else: f = fh try: assert(f.readline().strip() == '# KSSingles') except: raise RuntimeError(f.name + ' is not a ' + self.__class__.__name__ + ' data file') words = f.readline().split() n = int(words[0]) if len(words) == 1: # old output style for real wave functions (finite systems) self.dtype = float else: if words[1].startswith('complex'): self.dtype = complex else: self.dtype = float self.eps = float(f.readline()) self.npspins = 1 for i in range(n): kss = KSSingle(string=f.readline(), dtype=self.dtype) if (kss.i >= istart) and (kss.j <= jend): self.append(kss) self.npspins = max(self.npspins, kss.pspin + 1) self.update() if fh is None: f.close() def update(self): istart = self[0].i jend = 0 npspins = 1 nvspins = 1 for kss in self: istart = min(kss.i, istart) jend = max(kss.j, jend) if kss.pspin == 1: npspins = 2 if kss.spin == 1: nvspins = 2 self.istart = istart self.jend = jend self.npspins = npspins self.nvspins = nvspins if hasattr(self, 'energies'): del(self.energies) def set_arrays(self): if hasattr(self, 'energies'): return energies = [] fij = [] me = [] mur = [] muv = [] magn = [] for k in self: energies.append(k.energy) fij.append(k.fij) me.append(k.me) mur.append(k.mur) if k.muv is not None: muv.append(k.muv) if k.magn is not None: magn.append(k.magn) self.energies = np.array(energies) self.fij = np.array(fij) self.me = np.array(me) self.mur = np.array(mur) if len(muv): self.muv = np.array(muv) else: self.muv = None if len(magn): self.magn = np.array(magn) else: self.magn = None def write(self, filename=None, fh=None): """Write current state to a file. 'filename' is the filename. If the filename ends in .gz, the file is automatically saved in compressed gzip format. 'fh' is a filehandle. This can be used to write into already opened files. """ if self.world.rank != 0: return if fh is None: if filename.endswith('.gz') and mpi.rank == mpi.MASTER: import gzip f = gzip.open(filename, 'wb') else: f = paropen(filename, 'w') else: f = fh f.write('# KSSingles\n') f.write('{0} {1}\n'.format(len(self), np.dtype(self.dtype))) f.write('{0}\n'.format(self.eps)) for kss in self: f.write(kss.outstring()) if fh is None: f.close() class KSSingle(Excitation, PairDensity): """Single Kohn-Sham transition containing all it's indicees :: pspin=physical spin spin=virtual spin, i.e. spin in the ground state calc. kpt=the Kpoint object fijscale=weight for the occupation difference:: me = sqrt(fij*epsij) * mur = - muv = - /omega_ia with omega_ia>0 magn = / (2 m_e c) """ def __init__(self, iidx=None, jidx=None, pspin=None, kpt=None, paw=None, string=None, fijscale=1, dtype=float): if string is not None: self.fromstring(string, dtype) return None # normal entry PairDensity.__init__(self, paw) PairDensity.initialize(self, kpt, iidx, jidx) self.pspin = pspin self.energy = 0.0 self.fij = 0.0 self.me = np.zeros((3), dtype=dtype) self.mur = np.zeros((3), dtype=dtype) self.muv = np.zeros((3), dtype=dtype) self.magn = np.zeros((3), dtype=dtype) self.kpt_comm = paw.wfs.kd.comm # leave empty if not my kpt if kpt is None: return wfs = paw.wfs gd = wfs.gd self.energy = kpt.eps_n[jidx] - kpt.eps_n[iidx] self.fij = (kpt.f_n[iidx] - kpt.f_n[jidx]) * fijscale # calculate matrix elements ----------- # length form .......................... # course grid contribution # is the negative of the dipole moment (because of negative # e- charge) me = - gd.calculate_dipole_moment(self.get()) # augmentation contributions ma = np.zeros(me.shape, dtype=dtype) pos_av = paw.atoms.get_positions() / Bohr for a, P_ni in kpt.P_ani.items(): Ra = pos_av[a] Pi_i = P_ni[self.i].conj() Pj_i = P_ni[self.j] Delta_pL = wfs.setups[a].Delta_pL ni = len(Pi_i) ma0 = 0 ma1 = np.zeros(me.shape, dtype=me.dtype) for i in range(ni): for j in range(ni): pij = Pi_i[i] * Pj_i[j] ij = packed_index(i, j, ni) # L=0 term ma0 += Delta_pL[ij, 0] * pij # L=1 terms if wfs.setups[a].lmax >= 1: # see spherical_harmonics.py for # L=1:y L=2:z; L=3:x ma1 += np.array([Delta_pL[ij, 3], Delta_pL[ij, 1], Delta_pL[ij, 2]]) * pij ma += sqrt(4 * pi / 3) * ma1 + Ra * sqrt(4 * pi) * ma0 gd.comm.sum(ma) self.me = sqrt(self.energy * self.fij) * (me + ma) self.mur = - (me + ma) # velocity form ............................. if self.lcao: # XXX Velocity form not supported in LCAO return me = np.zeros(self.mur.shape, dtype=dtype) # get derivatives dtype = self.wfj.dtype dwfj_cg = gd.empty((3), dtype=dtype) if not hasattr(gd, 'ddr'): gd.ddr = [Gradient(gd, c, dtype=dtype).apply for c in range(3)] for c in range(3): gd.ddr[c](self.wfj, dwfj_cg[c], kpt.phase_cd) me[c] = gd.integrate(self.wfi.conj() * dwfj_cg[c]) if 0: me2 = np.zeros(self.mur.shape) for c in range(3): gd.ddr[c](self.wfi, dwfj_cg[c], kpt.phase_cd) me2[c] = gd.integrate(self.wfj * dwfj_cg[c]) print(me, -me2, me2 + me) # augmentation contributions ma = np.zeros(me.shape, dtype=me.dtype) for a, P_ni in kpt.P_ani.items(): Pi_i = P_ni[self.i].conj() Pj_i = P_ni[self.j] nabla_iiv = paw.wfs.setups[a].nabla_iiv for c in range(3): for i1, Pi in enumerate(Pi_i): for i2, Pj in enumerate(Pj_i): ma[c] += Pi * Pj * nabla_iiv[i1, i2, c] gd.comm.sum(ma) self.muv = - (me + ma) / self.energy # magnetic transition dipole ................ r_cg, r2_g = coordinates(gd) magn = np.zeros(me.shape, dtype=dtype) wfi_g = self.wfi.conj() for ci in range(3): cj = (ci + 1) % 3 ck = (ci + 2) % 3 magn[ci] = gd.integrate(wfi_g * r_cg[cj] * dwfj_cg[ck] - wfi_g * r_cg[ck] * dwfj_cg[cj]) # augmentation contributions ma = np.zeros(magn.shape, dtype=magn.dtype) for a, P_ni in kpt.P_ani.items(): Pi_i = P_ni[self.i].conj() Pj_i = P_ni[self.j] rnabla_iiv = paw.wfs.setups[a].rnabla_iiv for c in range(3): for i1, Pi in enumerate(Pi_i): for i2, Pj in enumerate(Pj_i): ma[c] += Pi * Pj * rnabla_iiv[i1, i2, c] gd.comm.sum(ma) self.magn = -alpha / 2. * (magn + ma) def distribute(self): """Distribute results to all cores.""" self.spin = self.kpt_comm.sum(self.spin) self.pspin = self.kpt_comm.sum(self.pspin) self.k = self.kpt_comm.sum(self.k) self.weight = self.kpt_comm.sum(self.weight) self.energy = self.kpt_comm.sum(self.energy) self.fij = self.kpt_comm.sum(self.fij) self.kpt_comm.sum(self.me) self.kpt_comm.sum(self.mur) self.kpt_comm.sum(self.muv) self.kpt_comm.sum(self.magn) def __add__(self, other): """Add two KSSingles""" result = self.copy() result.me = self.me + other.me result.mur = self.mur + other.mur result.muv = self.muv + other.muv result.magn = self.magn - other.magn return result def __sub__(self, other): """Subtract two KSSingles""" result = self.copy() result.me = self.me - other.me result.mur = self.mur - other.mur result.muv = self.muv - other.muv result.magn = self.magn - other.magn return result def __rmul__(self, x): return self.__mul__(x) def __mul__(self, x): """Multiply a KSSingle with a number""" if isinstance(x, (float, int)): result = self.copy() result.me = self.me * x result.mur = self.mur * x result.muv = self.muv * x return result else: return RuntimeError('not a number') def __truediv__(self, x): return self.__mul__(1. / x) __div__ = __truediv__ def copy(self): if self.mur.dtype == complex: return KSSingle(string=self.outstring(), dtype=complex) else: return KSSingle(string=self.outstring(), dtype=float) def fromstring(self, string, dtype=float): l = string.split() self.i = int(l.pop(0)) self.j = int(l.pop(0)) self.pspin = int(l.pop(0)) self.spin = int(l.pop(0)) if dtype == float: self.k = 0 self.weight = 1 else: self.k = int(l.pop(0)) self.weight = float(l.pop(0)) self.energy = float(l.pop(0)) self.fij = float(l.pop(0)) self.mur = np.array([dtype(l.pop(0)) for i in range(3)]) self.me = - self.mur * sqrt(self.energy * self.fij) self.muv = self.magn = None if len(l): self.muv = np.array([dtype(l.pop(0)) for i in range(3)]) if len(l): self.magn = np.array([dtype(l.pop(0)) for i in range(3)]) return None def outstring(self): if self.mur.dtype == float: string = '{0:d} {1:d} {2:d} {3:d} {4:g} {5:g}'.format( self.i, self.j, self.pspin, self.spin, self.energy, self.fij) else: string = ( '{0:d} {1:d} {2:d} {3:d} {4:d} {5:g} {6:g} {7:g}'.format( self.i, self.j, self.pspin, self.spin, self.k, self.weight, self.energy, self.fij)) string += ' ' def format_me(me): string = '' if me.dtype == float: for m in me: string += ' {0:.5e}'.format(m) else: for m in me: string += ' {0.real:.5e}{0.imag:+.5e}j'.format(m) return string string += ' ' + format_me(self.mur) if self.muv is not None: string += ' ' + format_me(self.muv) if self.magn is not None: string += ' ' + format_me(self.magn) string += '\n' return string def __str__(self): string = '# %d->%d %d(%d) eji=%g[eV]' % \ (self.i, self.j, self.pspin, self.spin, self.energy * Hartree) if self.me.dtype == float: string += ' (%g,%g,%g)' % (self.me[0], self.me[1], self.me[2]) else: string += ' kpt={0:d} w={1:g}'.format(self.k, self.weight) string += ' (' # use velocity form s = - np.sqrt(self.energy * self.fij) for c, m in enumerate(s * self.me): string += '{0.real:.5e}{0.imag:+.5e}j'.format(m) if c < 2: string += ',' string += ')' return string # # User interface: ## # def get_weight(self): return self.fij gpaw-0.11.0.13004/gpaw/lrtddft/excitation.py0000664000175000017500000001271312553643472020604 0ustar jensjjensj00000000000000"""Excitation lists base classes """ from math import sqrt import numpy as np import gpaw.mpi as mpi from gpaw.output import get_txt from ase.units import A, m, s, Bohr, _aut, C class ExcitationList(list): """General Excitation List class. """ def __init__(self, calculator=None, txt=None): # initialise empty list list.__init__(self) self.calculator = calculator if not txt and calculator: txt = calculator.txt self.txt = get_txt(txt, mpi.rank) def get_calculator(self): return self.calculator def get_energies(self): """Get excitation energies in Hartrees""" el = [] for ex in self: el.append(ex.get_energy()) return np.array(el) def get_trk(self): """Evaluate the Thomas Reiche Kuhn sum rule""" trkm = np.zeros((3)) for ex in self: me = ex.get_dipole_me() trkm += ex.get_energy() * (me.real ** 2 + me.imag ** 2) return 2. * trkm # scale to get the number of electrons XXX spinpol ? def get_polarizabilities(self, lmax=7): """Calculate the Polarisabilities see Jamorski et al. J. Chem. Phys. 104 (1996) 5134""" S = np.zeros((lmax + 1)) for ex in self: e = ex.get_energy() f = ex.get_oscillator_strength()[0] for l in range(lmax + 1): S[l] += e ** (-2 * l) * f return S def set_calculator(self, calculator): self.calculator = calculator def __truediv__(self, x): return self.__mul__(1. / x) __div__ = __truediv__ def __rmul__(self, x): return self.__mul__(x) def __mul__(self, x): """Multiply with a number""" if isinstance(x, (float, int)): result = self.__class__() result.dtype = self.dtype for kss in self: result.append(x * kss) return result else: return RuntimeError('not a number') def __sub__(self, other): result = self.__class__() result.dtype = self.dtype assert(len(self) == len(other)) for kss, ksso in zip(self, other): result.append(kss - ksso) return result def __str__(self): string = '# ' + str(type(self)) if len(self) != 0: string += ', %d excitations:' % len(self) string += '\n' for ex in self: string += '# ' + ex.__str__() + '\n' return string def get_alpha(self, omega): """Return the polarization tensor""" alpha_cc = np.zeros((3, 3)) for ex in self: alpha_cc += ex.get_alpha(omega) return alpha_cc class Excitation: def get_energy(self): """Get the excitations energy relative to the ground state energy in Hartrees. """ return self.energy def get_dipole_me(self, form='r'): """return the excitations dipole matrix element including the occupation factor sqrt(fij)""" if form == 'r': # length form return self.me / sqrt(self.energy) elif form == 'v': # velocity form return - np.sqrt(self.fij) * self.muv else: raise RuntimeError('Unknown form >' + form + '<') def get_oscillator_strength(self, form='r'): """Return the excitations dipole oscillator strength. self.me is assumed to be:: form='r': sqrt(f * E) * , form='v': sqrt(f / E) * for f = multiplicity, E = transition energy and initial and final states:: |I>, |J> """ if form == 'r': # length form me = self.me elif form == 'v': # velocity form me = self.muv * np.sqrt(self.fij * self.energy) else: raise RuntimeError('Unknown form >' + form + '<') osz = [0.] for c in range(3): val = 2. * (me[c].real ** 2 + me[c].imag ** 2) osz.append(val) osz[0] += val / 3. return osz def get_rotatory_strength(self, form='r', units='cgs'): """Return rotatory strength""" if self.magn is None: raise RuntimeError('Magnetic moment not available.') if units == 'cgs': # 10^-40 esu cm erg / G # = 3.33564095 * 10^-15 A^2 m^3 s # conversion factor after # T. B. Pedersen and A. E. Hansen, # Chem. Phys. Lett. 246 (1995) 1 # pre = 471.43 # From TurboMole pre = 64604.8164 elif uints == 'a.u.': pre = 1. else: raise RuntimeError('Unknown units >' + units + '<') if form == 'r': # length form mu = self.mur elif form == 'v': # velocity form mu = self.muv else: raise RuntimeError('Unknown form >' + form + '<') return pre * np.dot(mu, self.magn) def set_energy(self, E): """Set the excitations energy relative to the ground state energy""" self.energy = E def get_alpha(self, omega): """Return the polarization tensor""" me = self.me alpha_cc = np.zeros((3, 3)) for c1 in range(3): for c2 in range(c1, 3): alpha_cc[c1, c2] = alpha_cc[c2, c1] = me[c1] * me[c2] return 2 * self.energy / (self.energy ** 2 - omega ** 2) * alpha_cc gpaw-0.11.0.13004/gpaw/lrtddft/spectrum.py0000664000175000017500000001230712553643472020276 0ustar jensjjensj00000000000000from __future__ import print_function import sys import numpy as np from ase.units import _hbar, _c, _e, Hartree from gpaw.version import version from gpaw.utilities.folder import Folder def spectrum(exlist=None, filename=None, emin=None, emax=None, de=None, energyunit='eV', folding='Gauss', width=0.08, # Gauss/Lorentz width comment=None, form='r' ): """Write out a folded spectrum. Parameters: =============== =================================================== ``exlist`` ExcitationList ``filename`` File name for the output file, STDOUT if not given ``emin`` min. energy, set to cover all energies if not given ``emax`` max. energy, set to cover all energies if not given ``de`` energy spacing ``energyunit`` Energy unit 'eV' or 'nm', default 'eV' ``folding`` Gauss (default) or Lorentz ``width`` folding width in terms of the chosen energyunit =============== =================================================== all energies in [eV] """ # output out = sys.stdout if filename is not None: out = open(filename, 'w') if comment: print('#', comment, file=out) print('# Photoabsorption spectrum from linear response TD-DFT', file=out) print('# GPAW version:', version, file=out) if folding is not None: # fold the spectrum print('# %s folded, width=%g [%s]' % (folding, width, energyunit), file=out) if form == 'r': out.write('# length form') else: assert(form == 'v') out.write('# velocity form') print('# om [%s] osz osz x osz y osz z' % energyunit, file=out) x = [] y = [] for ex in exlist: x.append(ex.get_energy() * Hartree) y.append(ex.get_oscillator_strength(form)) if energyunit == 'nm': # transform to experimentally used wavelength [nm] x = 1.e+9 * 2 * np.pi * _hbar * _c / _e / np.array(x) y = np.array(y) elif energyunit != 'eV': raise RuntimeError('currently only eV and nm are supported') energies, values = Folder(width, folding).fold(x, y, de, emin, emax) for e, val in zip(energies, values): print('%10.5f %12.7e %12.7e %11.7e %11.7e' % (e, val[0], val[1], val[2], val[3]), file=out) if filename is not None: out.close() def rotatory_spectrum(exlist=None, filename=None, emin=None, emax=None, de=None, energyunit='eV', folding='Gauss', width=0.08, # Gauss/Lorentz width comment=None ): """Write out a folded rotatory spectrum. See spectrum() for explanation of the parameters. """ # output out = sys.stdout if filename is not None: out = open(filename, 'w') if comment: print('#', comment, file=out) print('# Rotatory spectrum from linear response TD-DFT', file=out) print('# GPAW version:', version, file=out) if folding is not None: # fold the spectrum print('# %s folded, width=%g [%s]' % (folding, width, energyunit), file=out) print('# om [%s] R [cgs]' % energyunit, file=out) x = [] y = [] for ex in exlist: x.append(ex.get_energy() * Hartree) y.append(ex.get_rotatory_strength()) if energyunit == 'nm': # transform to experimentally used wavelength [nm] x = 1.e+9 * 2 * np.pi * _hbar * _c / _e / np.array(x) y = np.array(y) elif energyunit != 'eV': raise RuntimeError('currently only eV and nm are supported') energies, values = Folder(width, folding).fold(x, y, de, emin, emax) for e, val in zip(energies, values): print('%10.5f %12.7e' % (e, val), file=out) if filename is not None: out.close() class Writer(Folder): def __init__(self, folding=None, width=0.08, # Gauss/Lorentz width ): self.folding = folding Folder.__init__(self, width, folding) def write(self, filename=None, emin=None, emax=None, de=None, comment=None): out = sys.stdout if filename is not None: out = open(filename, 'w') print('#', self.title, file=out) print('# GPAW version:', version, file=out) if comment: print('#', comment, file=out) if self.folding is not None: print('# %s folded, width=%g [eV]' % (self.folding, self.width), file=out) print('#', self.fields, file=out) energies, values = self.fold(self.energies, self.values, de, emin, emax) for e, val in zip(energies, values): string = '%10.5f' % e for vf in val: string += ' %12.7e' % vf print(string, file=out) if filename is not None: out.close() gpaw-0.11.0.13004/gpaw/lrtddft/convergence.py0000664000175000017500000001263612553643472020737 0ustar jensjjensj00000000000000from __future__ import print_function import os from ase.units import Hartree from gpaw.lrtddft import LrTDDFT from gpaw.lrtddft.spectrum import spectrum, rotatory_spectrum def check_convergence(lr, # LrTDDFT object dirname='conv', # directory name to store the files title=None, # title for gnuplot dn=None, # steps to vary istart/jend dE=None, # steps to vary energy range emin=None, emax=None, folding='Gauss', istart=None, jend=None, width=0.03): # Gauss/Lorentz width """Study the convergence of a LrTDDFT calcualtion by varying istart/jend. A gnuplot file will be created with the name 'dirname'/conv.gpl.""" if istart is None: istart0 = lr.kss.istart else: if istart < lr.kss.istart: raise RuntimeError istart0 = istart if jend is None: jend0 = lr.kss.jend else: if jend > lr.kss.jend: raise RuntimeError jend0 = jend # create subdirectory for the files if not os.path.isdir(dirname): if not os.path.exists(dirname): os.makedirs(dirname) else: raise RuntimeError('Can\'t create directory ' + dirname) def fname(filename): return dirname + '/' + filename fgpl = open(fname('conv.gpl'), 'w') print('set xlabel "omega [eV]"', file=fgpl) print('set ylabel "Folded osc. strength [1/eV]"', file=fgpl) if not emin: emin_gpl = '*' else: emin_gpl = str(emin) if not emax: emax_gpl = '*' else: emax_gpl = str(emax) print('set range [' + emin_gpl + ':' + emax_gpl + ']', file=fgpl) if title: print('set title "' + str(title) + '"', file=fgpl) # kss spectrum(lr.kss, fname('kss.dat'), width=width) spectrum(lr.kss, fname('ksssticks.dat'), folding=None) # full lr.diagonalize(istart=istart0, jend=jend0) spectrum(lr, fname('full.dat'), width=width) spectrum(lr, fname('fullsticks.dat'), folding=None) print('plot "' + fname('full.dat') + '" t "full" w l lt 1, \\', file=fgpl) print(' "' + fname('fullsticks.dat') + '" u 1:($2*20) t "" w impulses lt 1, \\', file=fgpl) print(' "' + fname('kss.dat') + '" t "Kohn-Sham" w l lt 2', file=fgpl) print('pause -10', file=fgpl) if dn is None: dn = -istart0 + jend0 dn = int(dn / 10.) if dE is None: # vary istart print('plot "' + fname('full.dat') + '" t "istart=' + str(istart0) + '" w l lt 1, \\', file=fgpl) for i in range(1, 4): istart = istart0 + i * dn lr.diagonalize(istart=istart, jend=jend0) fn = fname('istart' + str(istart) + '.dat') spectrum(lr, fn, width=width) print(' "' + fn + '" t "istart=' + str(istart) + '" w l lt', i + 1, end=' ', file=fgpl) if i < 3: print(', \\', end=' ', file=fgpl) print(file=fgpl) print('pause -10', file=fgpl) # vary jend print('plot "' + fname('full.dat') + '" t "jend=' + str(jend0) + '" w l lt 1, \\', file=fgpl) for i in range(1, 4): jend = jend0 - i * dn lr.diagonalize(jend=jend, istart=istart0) fn = fname('jend' + str(jend) + '.dat') spectrum(lr, fn, width=width) print(' "' + fn + '" t "jend=' + str(jend) + '" w l lt', i + 1, end=' ', file=fgpl) if i < 3: print(', \\', end=' ', file=fgpl) print(file=fgpl) print('pause -10', file=fgpl) else: # vary the enrgy range max_kss_energy = 0. for kss in lr.Om.kss: max_kss_energy = max(max_kss_energy, kss.get_energy() * Hartree) print('plot "' + fname('full.dat') + '" t "full"' + ' w l lt 1, \\', file=fgpl) for i in range(1, 4): max_energy = max_kss_energy - i * dE lr.diagonalize(energy_range=max_energy) fn = fname('max_energy' + str(max_energy) + '.dat') spectrum(lr, fn, width=width) print(' "' + fn + '" t "dE=-' + str( i * dE) + '" w l lt', end=' ', file=fgpl) print(i + 1, end=' ', file=fgpl) if i < 3: print(', \\', end=' ', file=fgpl) print(file=fgpl) print('pause -10', file=fgpl) # plot different directions print('plot "' + fname('full.dat') + '" u 1:3 t "x" w l lt 1, \\', file=fgpl) print(' "' + fname('full.dat') + '" u 1:4 t "y" w l lt 2, \\', file=fgpl) print(' "' + fname('full.dat') + '" u 1:5 t "z" w l lt 3', file=fgpl) print('pause -10', file=fgpl) # plot rotary strength if lr[0].magn is not None: print('set ylabel "Folded rot. strength [cgs/eV]"', file=fgpl) rotatory_spectrum(lr, fname('rotatory.dat'), width=width) rotatory_spectrum(lr, fname('rotatory_sticks.dat'), folding=None) print('plot "' + fname('rotatory.dat') + '" t "rotatory" w l lt 1, \\', file=fgpl) print(' "' + fname('rotatory_sticks.dat') + '" u 1:($2*20) t "" w impulses lt 1', file=fgpl) print('pause -10', file=fgpl) fgpl.close() gpaw-0.11.0.13004/gpaw/lrtddft/__init__.py0000664000175000017500000004231112553643472020171 0ustar jensjjensj00000000000000"""This module defines a linear response TDDFT-class. """ from __future__ import print_function import numbers import sys from math import sqrt import numpy as np from ase.units import Hartree from ase.utils.timing import Timer import _gpaw import gpaw.mpi as mpi from gpaw.lrtddft.excitation import Excitation, ExcitationList from gpaw.lrtddft.kssingle import KSSingles from gpaw.lrtddft.omega_matrix import OmegaMatrix from gpaw.lrtddft.apmb import ApmB # from gpaw.lrtddft.transition_density import TransitionDensity from gpaw.xc import XC from gpaw.lrtddft.spectrum import spectrum from gpaw.wavefunctions.fd import FDWaveFunctions __all__ = ['LrTDDFT', 'photoabsorption_spectrum', 'spectrum'] class LrTDDFT(ExcitationList): """Linear Response TDDFT excitation class Input parameters: calculator: the calculator object after a ground state calculation nspins: number of spins considered in the calculation Note: Valid only for unpolarised ground state calculation eps: Minimal occupation difference for a transition (default 0.001) istart: First occupied state to consider jend: Last unoccupied state to consider xc: Exchange-Correlation approximation in the Kernel derivative_level: 0: use Exc, 1: use vxc, 2: use fxc if available filename: read from a file """ def __init__(self, calculator=None, **kwargs): self.timer = Timer() self.set(**kwargs) if isinstance(calculator, str): ExcitationList.__init__(self, None, self.txt) self.filename = calculator else: ExcitationList.__init__(self, calculator, self.txt) if self.filename is not None: return self.read(self.filename) if self.eh_comm is None: self.eh_comm = mpi.serial_comm elif isinstance(self.eh_comm, (mpi.world.__class__, mpi.serial_comm.__class__)): # Correct type already. pass else: # world should be a list of ranks: self.eh_comm = mpi.world.new_communicator(np.asarray(eh_comm)) if calculator is not None and calculator.initialized: if not isinstance(calculator.wfs, FDWaveFunctions): raise RuntimeError( 'Linear response TDDFT supported only in real space mode') if calculator.wfs.kd.comm.size > 1: err_txt = 'Spin parallelization with Linear response ' err_txt += "TDDFT. Use parallel = {'domain' : 'domain_only'} " err_txt += 'calculator parameter.' raise NotImplementedError(err_txt) if self.xc == 'GS': self.xc = calculator.hamiltonian.xc.name if calculator.input_parameters.mode != 'lcao': calculator.converge_wave_functions() if calculator.density.nct_G is None: spos_ac = calculator.initialize_positions() calculator.wfs.initialize(calculator.density, calculator.hamiltonian, spos_ac) self.update(calculator) def set(self, **kwargs): defaults = { 'nspins': None, 'eps': 0.001, 'istart': 0, 'jend': sys.maxsize, 'energy_range': None, 'xc': 'GS', 'derivative_level': 1, 'numscale': 0.00001, 'txt': None, 'filename': None, 'finegrid': 2, 'force_ApmB': False, # for tests 'eh_comm': None # parallelization over eh-pairs } changed = False for key, value in defaults.items(): if hasattr(self, key): value = getattr(self, key) # do not overwrite setattr(self, key, kwargs.pop(key, value)) if value != getattr(self, key): changed = True for key in kwargs: raise KeyError('Unknown key ' + key) return changed def set_calculator(self, calculator): self.calculator = calculator # self.force_ApmB = parameters['force_ApmB'] self.force_ApmB = None # XXX def analyse(self, what=None, out=None, min=0.1): """Print info about the transitions. Parameters: 1. what: I list of excitation indicees, None means all 2. out : I where to send the output, None means sys.stdout 3. min : I minimal contribution to list (0 0.0: Om = ApmB name = 'LrTDDFThyb' else: Om = ApmB name = 'LrTDDFThyb' self.kss = KSSingles(calculator=self.calculator, nspins=self.nspins, eps=self.eps, istart=self.istart, jend=self.jend, energy_range=self.energy_range, txt=self.txt) self.Om = Om(self.calculator, self.kss, self.xc, self.derivative_level, self.numscale, finegrid=self.finegrid, eh_comm=self.eh_comm, txt=self.txt) self.name = name def diagonalize(self, istart=None, jend=None, energy_range=None, TDA=False): self.timer.start('diagonalize') self.timer.start('omega') self.Om.diagonalize(istart, jend, energy_range, TDA) self.timer.stop('omega') # remove old stuff self.timer.start('clean') while len(self): self.pop() self.timer.stop('clean') print('LrTDDFT digonalized:', file=self.txt) self.timer.start('build') for j in range(len(self.Om.kss)): self.append(LrTDDFTExcitation(self.Om, j)) print(' ', str(self[-1]), file=self.txt) self.timer.stop('build') self.timer.stop('diagonalize') def get_Om(self): return self.Om def read(self, filename=None, fh=None): """Read myself from a file""" if fh is None: if filename.endswith('.gz'): try: import gzip f = gzip.open(filename, 'rt') except: f = open(filename, 'r') else: f = open(filename, 'r') self.filename = filename else: f = fh self.filename = None # get my name s = f.readline().replace('\n', '') self.name = s.split()[1] self.xc = f.readline().replace('\n', '').split()[0] values = f.readline().split() self.eps = float(values[0]) if len(values) > 1: self.derivative_level = int(values[1]) self.numscale = float(values[2]) self.finegrid = int(values[3]) else: # old writing style, use old defaults self.numscale = 0.001 self.kss = KSSingles(filehandle=f) if self.name == 'LrTDDFT': self.Om = OmegaMatrix(kss=self.kss, filehandle=f, txt=self.txt) else: self.Om = ApmB(kss=self.kss, filehandle=f, txt=self.txt) self.Om.Kss(self.kss) # check if already diagonalized p = f.tell() s = f.readline() if s != '# Eigenvalues\n': # go back to previous position f.seek(p) else: # load the eigenvalues n = int(f.readline().split()[0]) for i in range(n): self.append(LrTDDFTExcitation(string=f.readline())) # load the eigenvectors f.readline() for i in range(n): values = f.readline().split() weights = [float(val) for val in values] self[i].f = np.array(weights) self[i].kss = self.kss if fh is None: f.close() # update own variables self.istart = self.Om.fullkss.istart self.jend = self.Om.fullkss.jend def singlets_triplets(self): """Split yourself into a singlet and triplet object""" slr = LrTDDFT(None, nspins=self.nspins, eps=self.eps, istart=self.istart, jend=self.jend, xc=self.xc, derivative_level=self.derivative_level, numscale=self.numscale) tlr = LrTDDFT(None, nspins=self.nspins, eps=self.eps, istart=self.istart, jend=self.jend, xc=self.xc, derivative_level=self.derivative_level, numscale=self.numscale) slr.Om, tlr.Om = self.Om.singlets_triplets() for lr in [slr, tlr]: lr.kss = lr.Om.fullkss return slr, tlr def single_pole_approximation(self, i, j): """Return the excitation according to the single pole approximation. See e.g.: Grabo et al, Theochem 501 (2000) 353-367 """ for ij, kss in enumerate(self.kss): if kss.i == i and kss.j == j: return sqrt(self.Om.full[ij][ij]) * Hartree return self.Om.full[ij][ij] / kss.energy * Hartree def __str__(self): string = ExcitationList.__str__(self) string += '# derived from:\n' string += self.Om.kss.__str__() return string def write(self, filename=None, fh=None): """Write current state to a file. 'filename' is the filename. If the filename ends in .gz, the file is automatically saved in compressed gzip format. 'fh' is a filehandle. This can be used to write into already opened files. """ if mpi.rank == 0: if fh is None: if filename.endswith('.gz'): try: import gzip f = gzip.open(filename, 'wt') except: f = open(filename, 'w') else: f = open(filename, 'w') else: f = fh f.write('# ' + self.name + '\n') xc = self.xc if xc is None: xc = 'RPA' if self.calculator is not None: xc += ' ' + self.calculator.get_xc_functional() f.write(xc + '\n') f.write('%g %d %g %d' % (self.eps, int(self.derivative_level), self.numscale, int(self.finegrid)) + '\n') self.kss.write(fh=f) self.Om.write(fh=f) if len(self): f.write('# Eigenvalues\n') istart = self.istart if istart is None: istart = self.kss.istart jend = self.jend if jend is None: jend = self.kss.jend f.write('%d %d %d' % (len(self), istart, jend) + '\n') for ex in self: f.write(ex.outstring()) f.write('# Eigenvectors\n') for ex in self: for w in ex.f: f.write('%g ' % w) f.write('\n') if fh is None: f.close() def d2Excdnsdnt(dup, ddn): """Second derivative of Exc polarised""" res = [[0, 0], [0, 0]] for ispin in range(2): for jspin in range(2): res[ispin][jspin] = np.zeros(dup.shape) _gpaw.d2Excdnsdnt(dup, ddn, ispin, jspin, res[ispin][jspin]) return res def d2Excdn2(den): """Second derivative of Exc unpolarised""" res = np.zeros(den.shape) _gpaw.d2Excdn2(den, res) return res class LrTDDFTExcitation(Excitation): def __init__(self, Om=None, i=None, e=None, m=None, string=None): if string is not None: self.fromstring(string) return None # multiplicity comes from Kohn-Sham contributions self.fij = 1 # define from the diagonalized Omega matrix if Om is not None: if i is None: raise RuntimeError ev = Om.eigenvalues[i] if ev < 0: # we reached an instability, mark it with a negative value self.energy = -sqrt(-ev) else: self.energy = sqrt(ev) self.f = Om.eigenvectors[i] self.kss = Om.kss self.kss.set_arrays() self.me = np.dot(self.f, self.kss.me) erat_k = np.sqrt(self.kss.energies / self.energy) wght_k = np.sqrt(self.kss.fij) * self.f ew_k = erat_k * wght_k self.mur = np.dot(ew_k, self.kss.mur) if self.kss.muv is not None: self.muv = np.dot(ew_k, self.kss.muv) else: self.muv = None if self.kss.magn is not None: self.magn = np.dot(1. / ew_k, self.kss.magn) else: self.magn = None return # define from energy and matrix element if e is not None: self.energy = e if m is None: if mur is None or muv is None or magn is None: raise RuntimeError self.mur = mur self.muv = muv self.magn = magn else: self.me = m return raise RuntimeError def density_change(self, paw): """get the density change associated with this transition""" raise NotImplementedError def fromstring(self, string): l = string.split() self.energy = float(l.pop(0)) if len(l) == 3: # old writing style self.me = np.array([float(l.pop(0)) for i in range(3)]) else: self.mur = np.array([float(l.pop(0)) for i in range(3)]) self.me = - self.mur * sqrt(self.energy) self.muv = np.array([float(l.pop(0)) for i in range(3)]) self.magn = np.array([float(l.pop(0)) for i in range(3)]) def outstring(self): str = '%g ' % self.energy str += ' ' for m in self.mur: str += '%12.4e' % m str += ' ' for m in self.muv: str += '%12.4e' % m str += ' ' for m in self.magn: str += '%12.4e' % m str += '\n' return str def __str__(self): m2 = np.sum(self.me * self.me) m = sqrt(m2) if m > 0: me = self.me / m else: me = self.me str = ' om=%g[eV] |me|=%g (%.2f,%.2f,%.2f)' % \ (self.energy * Hartree, m, me[0], me[1], me[2]) return str def analyse(self, min=.1): """Return an analysis string of the excitation""" osc = self.get_oscillator_strength() s = ('E=%.3f' % (self.energy * Hartree) + ' eV, ' + 'f=%.5g' % osc[0] + ', (%.5g,%.5g,%.5g) ' % (osc[1], osc[2], osc[3]) + '\n') #'R=%.5g' % self.get_rotatory_strength() + ' cgs\n') def sqr(x): return x * x spin = ['u', 'd'] min2 = sqr(min) rest = np.sum(self.f ** 2) for f, k in zip(self.f, self.kss): f2 = sqr(f) if f2 > min2: s += ' %d->%d ' % (k.i, k.j) + spin[k.pspin] + ' ' s += '%.3g \n' % f2 rest -= f2 s += ' rest=%.3g' % rest return s def photoabsorption_spectrum(excitation_list, spectrum_file=None, e_min=None, e_max=None, delta_e=None, folding='Gauss', width=0.1, comment=None): """Uniform absorption spectrum interface Parameters: ================= =================================================== ``exlist`` ExcitationList ``spectrum_file`` File name for the output file, STDOUT if not given ``e_min`` min. energy, set to cover all energies if not given ``e_max`` max. energy, set to cover all energies if not given ``delta_e`` energy spacing ``energyunit`` Energy unit, default 'eV' ``folding`` Gauss (default) or Lorentz ``width`` folding width in terms of the chosen energyunit ================= =================================================== all energies in [eV] """ spectrum(exlist=excitation_list, filename=spectrum_file, emin=e_min, emax=e_max, de=delta_e, energyunit='eV', folding=folding, width=width, comment=comment) gpaw-0.11.0.13004/gpaw/lrtddft/apmb.py0000664000175000017500000002521112553643472017351 0ustar jensjjensj00000000000000"""Omega matrix for functionals with Hartree-Fock exchange. """ from __future__ import print_function from math import sqrt import numpy as np from numpy.linalg import inv from ase.units import Hartree from ase.utils.timing import Timer import gpaw.mpi as mpi from gpaw.lrtddft.omega_matrix import OmegaMatrix from gpaw.pair_density import PairDensity from gpaw.utilities import pack from gpaw.utilities.lapack import diagonalize, gemm, sqrt_matrix class ApmB(OmegaMatrix): """Omega matrix for functionals with Hartree-Fock exchange. """ def get_full(self): hybrid = ((self.xc is not None) and hasattr(self.xc, 'hybrid') and (self.xc.hybrid > 0.0)) if self.fullkss.npspins < 2 and hybrid: raise RuntimeError('Does not work spin-unpolarized ' + 'with hybrids (use nspins=2)') self.paw.timer.start('ApmB RPA') self.ApB = self.Om self.AmB = self.get_rpa() self.paw.timer.stop() if self.xc is not None: self.paw.timer.start('ApmB XC') self.get_xc() # inherited from OmegaMatrix self.paw.timer.stop() def get_rpa(self): """Calculate RPA and Hartree-fock part of the A+-B matrices.""" # shorthands kss = self.fullkss finegrid = self.finegrid # calculate omega matrix nij = len(kss) print('RPAhyb', nij, 'transitions', file=self.txt) AmB = np.zeros((nij, nij)) ApB = self.ApB # storage place for Coulomb integrals integrals = {} for ij in range(nij): print('RPAhyb kss[' + '%d' % ij + ']=', kss[ij], file=self.txt) timer = Timer() timer.start('init') timer2 = Timer() # smooth density including compensation charges timer2.start('with_compensation_charges 0') rhot_p = kss[ij].with_compensation_charges( finegrid is not 0) timer2.stop() # integrate with 1/|r_1-r_2| timer2.start('poisson') phit_p = np.zeros(rhot_p.shape, rhot_p.dtype) self.poisson.solve(phit_p, rhot_p, charge=None) timer2.stop() timer.stop() t0 = timer.get_time('init') timer.start(ij) if finegrid == 1: rhot = kss[ij].with_compensation_charges() phit = self.gd.zeros() self.restrict(phit_p, phit) else: phit = phit_p rhot = rhot_p for kq in range(ij, nij): if kq != ij: # smooth density including compensation charges timer2.start('kq with_compensation_charges') rhot = kss[kq].with_compensation_charges( finegrid is 2) timer2.stop() pre = self.weight_Kijkq(ij, kq) timer2.start('integrate') I = self.Coulomb_integral_kss(kss[ij], kss[kq], phit, rhot) if kss[ij].spin == kss[kq].spin: name = self.Coulomb_integral_name(kss[ij].i, kss[ij].j, kss[kq].i, kss[kq].j, kss[ij].spin) integrals[name] = I ApB[ij, kq] = pre * I timer2.stop() if ij == kq: epsij = kss[ij].get_energy() / kss[ij].get_weight() AmB[ij, kq] += epsij ApB[ij, kq] += epsij timer.stop() # timer2.write() if ij < (nij - 1): print('RPAhyb estimated time left', self.time_left(timer, t0, ij, nij), file=self.txt) # add HF parts and apply symmetry if hasattr(self.xc, 'hybrid'): weight = self.xc.hybrid else: weight = 0.0 for ij in range(nij): print('HF kss[' + '%d' % ij + ']', file=self.txt) timer = Timer() timer.start('init') timer.stop() t0 = timer.get_time('init') timer.start(ij) i = kss[ij].i j = kss[ij].j s = kss[ij].spin for kq in range(ij, nij): if kss[ij].pspin == kss[kq].pspin: k = kss[kq].i q = kss[kq].j ikjq = self.Coulomb_integral_ijkq(i, k, j, q, s, integrals) iqkj = self.Coulomb_integral_ijkq(i, q, k, j, s, integrals) ApB[ij, kq] -= weight * (ikjq + iqkj) AmB[ij, kq] -= weight * (ikjq - iqkj) ApB[kq, ij] = ApB[ij, kq] AmB[kq, ij] = AmB[ij, kq] timer.stop() if ij < (nij - 1): print('HF estimated time left', self.time_left(timer, t0, ij, nij), file=self.txt) return AmB def Coulomb_integral_name(self, i, j, k, l, spin): """return a unique name considering the Coulomb integral symmetry""" def ij_name(i, j): return str(max(i, j)) + ' ' + str(min(i, j)) # maximal gives the first if max(i, j) >= max(k, l): base = ij_name(i, j) + ' ' + ij_name(k, l) else: base = ij_name(k, l) + ' ' + ij_name(i, j) return base + ' ' + str(spin) def Coulomb_integral_ijkq(self, i, j, k, q, spin, integrals): name = self.Coulomb_integral_name(i, j, k, q, spin) if name in integrals: return integrals[name] # create the Kohn-Sham singles kss_ij = PairDensity(self.paw) kss_ij.initialize(self.paw.wfs.kpt_u[spin], i, j) kss_kq = PairDensity(self.paw) kss_kq.initialize(self.paw.wfs.kpt_u[spin], k, q) rhot_p = kss_ij.with_compensation_charges( self.finegrid is not 0) phit_p = np.zeros(rhot_p.shape, rhot_p.dtype) self.poisson.solve(phit_p, rhot_p, charge=None) if self.finegrid == 1: phit = self.gd.zeros() self.restrict(phit_p, phit) else: phit = phit_p rhot = kss_kq.with_compensation_charges( self.finegrid is 2) integrals[name] = self.Coulomb_integral_kss(kss_ij, kss_kq, phit, rhot) return integrals[name] def timestring(self, t): ti = int(t + .5) td = int(ti // 86400) st = '' if td > 0: st += '%d' % td + 'd' ti -= td * 86400 th = int(ti // 3600) if th > 0: st += '%d' % th + 'h' ti -= th * 3600 tm = int(ti // 60) if tm > 0: st += '%d' % tm + 'm' ti -= tm * 60 st += '%d' % ti + 's' return st def map(self, istart=None, jend=None, energy_range=None): """Map A+B, A-B matrices according to constraints.""" map, self.kss = self.get_map(istart, jend, energy_range) if map is None: ApB = self.ApB.copy() AmB = self.AmB.copy() else: nij = len(self.kss) ApB = np.empty((nij, nij)) AmB = np.empty((nij, nij)) for ij in range(nij): for kq in range(nij): ApB[ij, kq] = self.ApB[map[ij], map[kq]] AmB[ij, kq] = self.AmB[map[ij], map[kq]] return ApB, AmB def diagonalize(self, istart=None, jend=None, energy_range=None, TDA=False): """Evaluate Eigenvectors and Eigenvalues""" ApB, AmB = self.map(istart, jend, energy_range) nij = len(self.kss) if TDA: # Tamm-Dancoff approximation (B=0) self.eigenvectors = 0.5 * (ApB + AmB) eigenvalues = np.zeros((nij)) diagonalize(self.eigenvectors, eigenvalues) self.eigenvalues = eigenvalues ** 2 else: # the occupation matrix C = np.empty((nij,)) for ij in range(nij): C[ij] = 1. / self.kss[ij].fij S = C * inv(AmB) * C S = sqrt_matrix(inv(S).copy()) # get Omega matrix M = np.zeros(ApB.shape) gemm(1.0, ApB, S, 0.0, M) self.eigenvectors = np.zeros(ApB.shape) gemm(1.0, S, M, 0.0, self.eigenvectors) self.eigenvalues = np.zeros((nij)) diagonalize(self.eigenvectors, self.eigenvalues) def read(self, filename=None, fh=None): """Read myself from a file""" if mpi.rank == mpi.MASTER: if fh is None: f = open(filename, 'r') else: f = fh f.readline() nij = int(f.readline()) ApB = np.zeros((nij, nij)) for ij in range(nij): l = f.readline().split() for kq in range(ij, nij): ApB[ij, kq] = float(l[kq - ij]) ApB[kq, ij] = ApB[ij, kq] self.ApB = ApB f.readline() nij = int(f.readline()) AmB = np.zeros((nij, nij)) for ij in range(nij): l = f.readline().split() for kq in range(ij, nij): AmB[ij, kq] = float(l[kq - ij]) AmB[kq, ij] = AmB[ij, kq] self.AmB = AmB if fh is None: f.close() def weight_Kijkq(self, ij, kq): """weight for the coupling matrix terms""" return 2. def write(self, filename=None, fh=None): """Write current state to a file.""" if mpi.rank == mpi.MASTER: if fh is None: f = open(filename, 'w') else: f = fh f.write('# A+B\n') nij = len(self.fullkss) f.write('%d\n' % nij) for ij in range(nij): for kq in range(ij, nij): f.write(' %g' % self.ApB[ij, kq]) f.write('\n') f.write('# A-B\n') nij = len(self.fullkss) f.write('%d\n' % nij) for ij in range(nij): for kq in range(ij, nij): f.write(' %g' % self.AmB[ij, kq]) f.write('\n') if fh is None: f.close() def __str__(self): string = ' ' if hasattr(self, 'eigenvalues'): string += 'dimension ' + ('%d' % len(self.eigenvalues)) string += '\neigenvalues: ' for ev in self.eigenvalues: string += ' ' + ('%f' % (sqrt(ev) * Hartree)) return string gpaw-0.11.0.13004/gpaw/parallel.py0000664000175000017500000000115612553643472016565 0ustar jensjjensj00000000000000import threading import numpy as np def run(task, nthreads, *args): """Parallelize task over first index of args.""" N = len(args[0]) def target(*args): for x in zip(*args): task(*x) if nthreads == 1: target(*args) return [0, N] n = np.linspace(0, N, nthreads + 1).round().astype(int) threads = [] for n1, n2 in zip(n[:-1], n[1:]): thread = threading.Thread(target=target, args=[x[n1:n2] for x in args]) thread.start() threads.append(thread) for thread in threads: thread.join() return n gpaw-0.11.0.13004/gpaw/wannier90.py0000664000175000017500000002364412553643472016613 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np import datetime from gpaw.utilities.blas import gemmdot from ase.units import Bohr class Wannier90: def __init__(self, calc, seed=None, bands=None, orbitals_ai=None, spin=0): if seed is None: seed = calc.atoms.get_chemical_formula() self.seed = seed if bands is None: bands = range(calc.get_number_of_bands()) self.bands = bands Na = len(calc.atoms) if orbitals_ai is None: orbitals_ai = [] for ia in range(Na): ni = 0 setup = calc.wfs.setups[ia] for l, n in zip(setup.l_j, setup.n_j): if not n == -1: ni += 2 * l + 1 orbitals_ai.append(range(ni)) self.calc = calc self.bands = bands self.Nn = len(bands) self.Na = Na self.orbitals_ai = orbitals_ai self.Nw = np.sum([len(orbitals_ai[ai]) for ai in range(Na)]) self.kpts_kc = calc.get_ibz_k_points() self.Nk = len(self.kpts_kc) self.spin = spin def write_input(calc, seed=None, bands=None, orbitals_ai=None, mp=None): if seed is None: seed = calc.atoms.get_chemical_formula() if bands is None: bands = range(calc.get_number_of_bands()) Na = len(calc.atoms) if orbitals_ai is None: orbitals_ai = [] for ia in range(Na): ni = 0 setup = calc.wfs.setups[ia] for l, n in zip(setup.l_j, setup.n_j): if not n == -1: ni += 2 * l + 1 orbitals_ai.append(range(ni)) assert len(orbitals_ai) == Na Nw = np.sum([len(orbitals_ai[ai]) for ai in range(Na)]) f = open(seed + '.win', 'w') pos_ac = calc.atoms.get_scaled_positions() print('begin projections', file=f) for ia, orbitals_i in enumerate(orbitals_ai): setup = calc.wfs.setups[ia] l_i = [] n_i = [] for n, l in zip(setup.n_j, setup.l_j): if not n == -1: l_i += (2 * l + 1) * [l] n_i += (2 * l + 1) * [n] r_c = pos_ac[ia] for orb in orbitals_i: l = l_i[orb] n = n_i[orb] print('f=%1.2f, %1.2f, %1.2f : s ' % (r_c[0], r_c[1], r_c[2]), end='', file=f) print('# n = %s, l = %s' % (n, l), file=f) Nw = np.sum([len(orbitals_ai[ai]) for ai in range(Na)]) print('end projections', file=f) print(file=f) print('spinors = False', file=f) print('hr_plot = True', file=f) print(file=f) print('num_bands = %d' % len(bands), file=f) maxn = max(bands) if maxn + 1 != len(bands): diffn = maxn - len(bands) print('exclude_bands : ', end='', file=f) counter = 0 for n in range(maxn): if n not in bands: counter += 1 if counter != diffn + 1: print('%d,' % (n + 1), sep='', end='', file=f) else: print('%d' % (n + 1), file=f) print(file=f) print('guiding_centres = True', file=f) print('num_wann = %d' % Nw, file=f) print('num_iter = 100', file=f) print(file=f) if len(bands) > Nw: ef = calc.get_fermi_level() print('dis_froz_max = %2.1f # (ef + 0.1)' % (ef + 0.1), file=f) print('dis_num_iter = 200', file=f) print(file=f) print('begin unit_cell_cart', file=f) for cell_c in calc.atoms.cell: print('%14.10f %14.10f %14.10f' % (cell_c[0], cell_c[1], cell_c[2]), file=f) print('end unit_cell_cart', file=f) print(file=f) print('begin atoms_frac', file=f) for atom, pos_c in zip(calc.atoms, pos_ac): print(atom.symbol, end='', file=f) print('%14.10f %14.10f %14.10f' % (pos_c[0], pos_c[1], pos_c[2]), file=f) print('end atoms_frac', file=f) print(file=f) if mp is not None: N_c = mp else: N_c = calc.wfs.kd.N_c print('mp_grid =', N_c[0], N_c[1], N_c[2], file=f) print(file=f) print('begin kpoints', file=f) for kpt in calc.get_bz_k_points(): print('%14.10f %14.10f %14.10f' % (kpt[0], kpt[1], kpt[2]), file=f) print('end kpoints', file=f) f.close() def write_projections(calc, seed=None, spin=0, orbitals_ai=None): if seed is None: seed = calc.atoms.get_chemical_formula() bands = get_bands(seed) Nn = len(bands) win_file = open(seed + '.win') for line in win_file.readlines(): l_e = line.split() if len(l_e) > 0: if l_e[0] == 'num_wann': Nw = int(l_e[2]) if l_e[0] == 'mp_grid': Nk = int(l_e[2]) * int(l_e[3]) * int(l_e[4]) assert Nk == len(calc.get_bz_k_points()) Na = len(calc.atoms) if orbitals_ai is None: orbitals_ai = [] for ia in range(Na): ni = 0 setup = calc.wfs.setups[ia] for l, n in zip(setup.l_j, setup.n_j): if not n == -1: ni += 2 * l + 1 orbitals_ai.append(range(ni)) assert len(orbitals_ai) == Na Ni = 0 for orbitals_i in orbitals_ai: Ni += len(orbitals_i) assert Nw == Ni f = open(seed + '.amn', 'w') print('Kohn-Sham input generated from GPAW calculation', file=f) print('%10d %6d %6d' % (Nn, Nk, Nw), file=f) P_kni = np.zeros((Nk, Nn, Nw), complex) for k in range(Nk): for i in range(Nw): icount = 0 P_ani = calc.wfs.kpt_u[spin * Nk + k].P_ani for ai in range(Na): ni = len(orbitals_ai[ai]) P_ni = P_ani[ai][bands]#, self.orbitals_ai[ai]] P_ni = P_ni[:, orbitals_ai[ai]] P_kni[k, :, icount:ni + icount] = P_ni.conj() icount += ni for k in range(Nk): for i in range(Nw): for n in range(Nn): P = P_kni[k, n, i] data = (n + 1, i + 1, k + 1, P.real, P.imag) print('%4d %4d %4d %18.12f %20.12f' % data, file=f) f.close() def write_eigenvalues(calc, seed=None, spin=0): if seed is None: seed = calc.atoms.get_chemical_formula() bands = get_bands(seed) f = open(seed + '.eig', 'w') for ik in range(len(calc.get_bz_k_points())): e_n = calc.get_eigenvalues(kpt=ik, spin=spin) for i, n in enumerate(bands): data = (i + 1, ik + 1, e_n[n]) print('%5d %5d %14.6f' % data, file=f) f.close() def write_overlaps(calc, seed=None, spin=0): if seed is None: seed = calc.atoms.get_chemical_formula() bands = get_bands(seed) Nn = len(bands) kpts_kc = calc.get_bz_k_points() Nk = len(kpts_kc) nnkp = open(seed + '.nnkp', 'r') lines = nnkp.readlines() neighbor_kb = [] for il, line in enumerate(lines): if len(line.split()) > 1: if line.split()[0] == 'begin' and line.split()[1] == 'nnkpts': Nb = eval(lines[il + 1].split()[0]) i0 = il + 2 break f = open(seed + '.mmn', 'w') print('Kohn-Sham input generated from GPAW calculation', file=f) print('%10d %6d %6d' % (Nn, Nk, Nb), file=f) icell_cv = (2 * np.pi) * np.linalg.inv(calc.wfs.gd.cell_cv).T r_g = calc.wfs.gd.get_grid_point_coordinates() Ng = np.prod(np.shape(r_g)[1:]) wfs = calc.wfs Nk = Nk for ik1 in range(Nk): u1_nG = np.array([wfs.get_wave_function_array(n, ik1, spin) for n in bands]) for ib in range(Nb): line = lines[i0 + ik1 * Nb + ib].split() ik2 = int(line[1]) - 1 u2_nG = np.array([wfs.get_wave_function_array(n, ik2, spin) for n in bands]) G_c = np.array([int(line[i]) for i in range(2, 5)]) bG_c = kpts_kc[ik2] - kpts_kc[ik1] + G_c bG_v = np.dot(bG_c, icell_cv) u2_nG = u2_nG * np.exp(-1.0j * gemmdot(bG_v, r_g, beta=0.0)) isk1 = Nk * spin + ik1 isk2 = Nk * spin + ik2 M_mm = get_overlap(calc, bands, np.reshape(u1_nG, (Nn, Ng)), np.reshape(u2_nG, (Nn, Ng)), calc.wfs.kpt_u[isk1].P_ani, calc.wfs.kpt_u[isk2].P_ani, bG_v) indices = (ik1 + 1, ik2 + 1, G_c[0], G_c[1], G_c[2]) print('%3d %3d %4d %3d %3d' % indices, file=f) for m1 in range(len(M_mm)): for m2 in range(len(M_mm)): M = M_mm[m2, m1] print('%20.12f %20.12f' % (M.real, M.imag), file=f) f.close() def get_overlap(calc, bands, u1_nG, u2_nG, P1_ani, P2_ani, bG_v): Nn = len(u1_nG) M_nn = np.dot(u1_nG.conj(), u2_nG.T) * calc.wfs.gd.dv r_av = calc.atoms.positions / Bohr for ia in range(len(P1_ani.keys())): P1_ni = P1_ani[ia][bands] P2_ni = P2_ani[ia][bands] phase = np.exp(-1.0j * np.dot(bG_v, r_av[ia])) dO_ii = calc.wfs.setups[ia].dO_ii M_nn += P1_ni.conj().dot(dO_ii).dot(P2_ni.T) * phase return M_nn def get_bands(seed): win_file = open(seed + '.win') exclude_bands = None for line in win_file.readlines(): l_e = line.split() if len(l_e) > 0: if l_e[0] == 'num_bands': Nn = int(l_e[2]) if l_e[0] == 'exclude_bands': exclude_bands=line.split()[2] exclude_bands=[int(n) - 1 for n in exclude_bands.split(',')] if exclude_bands is None: bands = range(Nn) else: bands = range(Nn + len(exclude_bands)) bands = [n for n in bands if n not in exclude_bands] win_file.close() return bands gpaw-0.11.0.13004/gpaw/spherical_harmonics.py0000664000175000017500000002136012553643470021003 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. """ Real-valued spherical harmonics === === === ======= L l m === === === ======= 0 0 0 1 1 1 -1 y 2 1 0 z 3 1 1 x 4 2 -2 xy 5 2 -1 yz 6 2 0 3z2-r2 7 2 1 zx 8 2 2 x2-y2 === === === ======= For a more complete list, see trunk/c/bmgs/sharmonic.py Gaunt coefficients:: __ ^ ^ \ L ^ Y (r) Y (r) = ) G Y (r) L L /__ L L L 1 2 L 1 2 """ from math import pi, sqrt from gpaw import debug from _gpaw import spherical_harmonics as Yl # Computer generated tables - do not touch! YL = [# s: [(1, (0, 0, 0))], # p: [(1, (0, 1, 0))], [(1, (0, 0, 1))], [(1, (1, 0, 0))], # d: [(1, (1, 1, 0))], [(1, (0, 1, 1))], [(2, (0, 0, 2)), (-1, (0, 2, 0)), (-1, (2, 0, 0))], [(1, (1, 0, 1))], [(1, (2, 0, 0)), (-1, (0, 2, 0))], # f: [(-1, (0, 3, 0)), (3, (2, 1, 0))], [(1, (1, 1, 1))], [(-1, (0, 3, 0)), (4, (0, 1, 2)), (-1, (2, 1, 0))], [(2, (0, 0, 3)), (-3, (2, 0, 1)), (-3, (0, 2, 1))], [(4, (1, 0, 2)), (-1, (3, 0, 0)), (-1, (1, 2, 0))], [(1, (2, 0, 1)), (-1, (0, 2, 1))], [(1, (3, 0, 0)), (-3, (1, 2, 0))], # g: [(1, (3, 1, 0)), (-1, (1, 3, 0))], [(-1, (0, 3, 1)), (3, (2, 1, 1))], [(-1, (3, 1, 0)), (-1, (1, 3, 0)), (6, (1, 1, 2))], [(-3, (2, 1, 1)), (4, (0, 1, 3)), (-3, (0, 3, 1))], [(6, (2, 2, 0)), (-24, (2, 0, 2)), (3, (0, 4, 0)), (-24, (0, 2, 2)), (3, (4, 0, 0)), (8, (0, 0, 4))], [(4, (1, 0, 3)), (-3, (3, 0, 1)), (-3, (1, 2, 1))], [(6, (2, 0, 2)), (1, (0, 4, 0)), (-1, (4, 0, 0)), (-6, (0, 2, 2))], [(1, (3, 0, 1)), (-3, (1, 2, 1))], [(-6, (2, 2, 0)), (1, (0, 4, 0)), (1, (4, 0, 0))], # h: [(-10, (2, 3, 0)), (5, (4, 1, 0)), (1, (0, 5, 0))], [(1, (3, 1, 1)), (-1, (1, 3, 1))], [(-8, (0, 3, 2)), (1, (0, 5, 0)), (-3, (4, 1, 0)), (-2, (2, 3, 0)), (24, (2, 1, 2))], [(-1, (3, 1, 1)), (-1, (1, 3, 1)), (2, (1, 1, 3))], [(-12, (0, 3, 2)), (2, (2, 3, 0)), (-12, (2, 1, 2)), (8, (0, 1, 4)), (1, (4, 1, 0)), (1, (0, 5, 0))], [(30, (2, 2, 1)), (-40, (0, 2, 3)), (15, (0, 4, 1)), (-40, (2, 0, 3)), (15, (4, 0, 1)), (8, (0, 0, 5))], [(-12, (3, 0, 2)), (8, (1, 0, 4)), (1, (5, 0, 0)), (2, (3, 2, 0)), (-12, (1, 2, 2)), (1, (1, 4, 0))], [(-1, (4, 0, 1)), (1, (0, 4, 1)), (2, (2, 0, 3)), (-2, (0, 2, 3))], [(8, (3, 0, 2)), (-1, (5, 0, 0)), (2, (3, 2, 0)), (-24, (1, 2, 2)), (3, (1, 4, 0))], [(1, (4, 0, 1)), (-6, (2, 2, 1)), (1, (0, 4, 1))], [(-10, (3, 2, 0)), (1, (5, 0, 0)), (5, (1, 4, 0))], # i: [(3, (5, 1, 0)), (-10, (3, 3, 0)), (3, (1, 5, 0))], [(5, (4, 1, 1)), (-10, (2, 3, 1)), (1, (0, 5, 1))], [(10, (3, 1, 2)), (-1, (5, 1, 0)), (1, (1, 5, 0)), (-10, (1, 3, 2))], [(-8, (0, 3, 3)), (-6, (2, 3, 1)), (3, (0, 5, 1)), (24, (2, 1, 3)), (-9, (4, 1, 1))], [(-16, (3, 1, 2)), (16, (1, 1, 4)), (2, (3, 3, 0)), (1, (5, 1, 0)), (-16, (1, 3, 2)), (1, (1, 5, 0))], [(5, (0, 5, 1)), (-20, (0, 3, 3)), (10, (2, 3, 1)), (-20, (2, 1, 3)), (5, (4, 1, 1)), (8, (0, 1, 5))], [(90, (4, 0, 2)), (-120, (0, 2, 4)), (-15, (2, 4, 0)), (16, (0, 0, 6)), (-15, (4, 2, 0)), (90, (0, 4, 2)), (-5, (0, 6, 0)), (-120, (2, 0, 4)), (-5, (6, 0, 0)), (180, (2, 2, 2))], [(-20, (3, 0, 3)), (8, (1, 0, 5)), (5, (5, 0, 1)), (10, (3, 2, 1)), (-20, (1, 2, 3)), (5, (1, 4, 1))], [(16, (2, 0, 4)), (-16, (0, 2, 4)), (-1, (2, 4, 0)), (-16, (4, 0, 2)), (1, (4, 2, 0)), (-1, (0, 6, 0)), (1, (6, 0, 0)), (16, (0, 4, 2))], [(8, (3, 0, 3)), (-3, (5, 0, 1)), (6, (3, 2, 1)), (-24, (1, 2, 3)), (9, (1, 4, 1))], [(5, (4, 2, 0)), (10, (0, 4, 2)), (-60, (2, 2, 2)), (-1, (0, 6, 0)), (-1, (6, 0, 0)), (10, (4, 0, 2)), (5, (2, 4, 0))], [(1, (5, 0, 1)), (-10, (3, 2, 1)), (5, (1, 4, 1))], [(-15, (4, 2, 0)), (-1, (0, 6, 0)), (1, (6, 0, 0)), (15, (2, 4, 0))], # j: [(21, (2, 5, 0)), (7, (6, 1, 0)), (-35, (4, 3, 0)), (-1, (0, 7, 0))], [(-10, (3, 3, 1)), (3, (1, 5, 1)), (3, (5, 1, 1))], [(-5, (6, 1, 0)), (5, (4, 3, 0)), (-120, (2, 3, 2)), (9, (2, 5, 0)), (12, (0, 5, 2)), (60, (4, 1, 2)), (-1, (0, 7, 0))], [(10, (3, 1, 3)), (3, (1, 5, 1)), (-10, (1, 3, 3)), (-3, (5, 1, 1))], [(-120, (2, 3, 2)), (-3, (0, 7, 0)), (3, (2, 5, 0)), (15, (4, 3, 0)), (-80, (0, 3, 4)), (240, (2, 1, 4)), (9, (6, 1, 0)), (60, (0, 5, 2)), (-180, (4, 1, 2))], [(30, (3, 3, 1)), (15, (1, 5, 1)), (-80, (3, 1, 3)), (48, (1, 1, 5)), (-80, (1, 3, 3)), (15, (5, 1, 1))], [(-5, (0, 7, 0)), (120, (0, 5, 2)), (-15, (2, 5, 0)), (-15, (4, 3, 0)), (-240, (0, 3, 4)), (-240, (2, 1, 4)), (64, (0, 1, 6)), (-5, (6, 1, 0)), (240, (2, 3, 2)), (120, (4, 1, 2))], [(-168, (2, 0, 5)), (16, (0, 0, 7)), (-168, (0, 2, 5)), (420, (2, 2, 3)), (-35, (6, 0, 1)), (-105, (4, 2, 1)), (210, (4, 0, 3)), (-35, (0, 6, 1)), (-105, (2, 4, 1)), (210, (0, 4, 3))], [(120, (1, 4, 2)), (-5, (7, 0, 0)), (240, (3, 2, 2)), (-15, (5, 2, 0)), (-5, (1, 6, 0)), (-240, (3, 0, 4)), (-15, (3, 4, 0)), (64, (1, 0, 6)), (-240, (1, 2, 4)), (120, (5, 0, 2))], [(48, (2, 0, 5)), (-48, (0, 2, 5)), (15, (6, 0, 1)), (15, (4, 2, 1)), (-80, (4, 0, 3)), (-15, (0, 6, 1)), (-15, (2, 4, 1)), (80, (0, 4, 3))], [(-9, (1, 6, 0)), (3, (7, 0, 0)), (120, (3, 2, 2)), (-3, (5, 2, 0)), (80, (3, 0, 4)), (-15, (3, 4, 0)), (180, (1, 4, 2)), (-240, (1, 2, 4)), (-60, (5, 0, 2))], [(10, (4, 0, 3)), (-3, (0, 6, 1)), (15, (2, 4, 1)), (-60, (2, 2, 3)), (10, (0, 4, 3)), (-3, (6, 0, 1)), (15, (4, 2, 1))], [(-5, (1, 6, 0)), (-120, (3, 2, 2)), (-1, (7, 0, 0)), (60, (1, 4, 2)), (5, (3, 4, 0)), (12, (5, 0, 2)), (9, (5, 2, 0))], [(1, (6, 0, 1)), (-1, (0, 6, 1)), (-15, (4, 2, 1)), (15, (2, 4, 1))], [(1, (7, 0, 0)), (-21, (5, 2, 0)), (35, (3, 4, 0)), (-7, (1, 6, 0))] ] norms = ['sqrt(1./4/pi)', 'sqrt(3./4/pi)', 'sqrt(3./4/pi)', 'sqrt(3./4/pi)', 'sqrt(15./4/pi)', 'sqrt(15./4/pi)', 'sqrt(5./16/pi)', 'sqrt(15./4/pi)', 'sqrt(15./16/pi)', 'sqrt(35./32/pi)', 'sqrt(105./4/pi)', 'sqrt(21./32/pi)', 'sqrt(7./16/pi)', 'sqrt(21./32/pi)', 'sqrt(105./16/pi)', 'sqrt(35./32/pi)', 'sqrt(315./16/pi)', 'sqrt(315./32/pi)', 'sqrt(45./16/pi)', 'sqrt(45./32/pi)', 'sqrt(9./256/pi)', 'sqrt(45./32/pi)', 'sqrt(45./64/pi)', 'sqrt(315./32/pi)', 'sqrt(315./256/pi)', 'sqrt(693./512/pi)', 'sqrt(3465./16/pi)', 'sqrt(385./512/pi)', 'sqrt(1155./16/pi)', 'sqrt(165./256/pi)', 'sqrt(11./256/pi)', 'sqrt(165./256/pi)', 'sqrt(1155./64/pi)', 'sqrt(385./512/pi)', 'sqrt(3465./256/pi)', 'sqrt(693./512/pi)', 'sqrt(3003./512/pi)', 'sqrt(9009./512/pi)', 'sqrt(819./64/pi)', 'sqrt(1365./512/pi)', 'sqrt(1365./512/pi)', 'sqrt(273./256/pi)', 'sqrt(13./1024/pi)', 'sqrt(273./256/pi)', 'sqrt(1365./2048/pi)', 'sqrt(1365./512/pi)', 'sqrt(819./1024/pi)', 'sqrt(9009./512/pi)', 'sqrt(3003./2048/pi)', 'sqrt(6435./4096/pi)', 'sqrt(45045./512/pi)', 'sqrt(3465./4096/pi)', 'sqrt(3465./64/pi)', 'sqrt(315./4096/pi)', 'sqrt(315./512/pi)', 'sqrt(105./4096/pi)', 'sqrt(15./1024/pi)', 'sqrt(105./4096/pi)', 'sqrt(315./2048/pi)', 'sqrt(315./4096/pi)', 'sqrt(3465./1024/pi)', 'sqrt(3465./4096/pi)', 'sqrt(45045./2048/pi)', 'sqrt(6435./4096/pi)'] # End of computer generated code Lmax = len(norms) # Normalize for L in range(Lmax): YL[L] = [(eval(norms[L]) * c, n) for c, n in YL[L]] # Only used for debug, and Gaunt coeff. generation g = [1.0] for l in range(9): g.append(g[-1] * (l + 0.5)) def gam(n0, n1, n2): h0 = n0 // 2 h1 = n1 // 2 h2 = n2 // 2 if 2 * h0 != n0 or 2 * h1 != n1 or 2 * h2 != n2: return 0.0 return 2.0 * pi * g[h0] * g[h1] * g[h2] / g[1 + h0 + h1 + h2] def yLL(L1, L2): s = 0.0 for c1, n1 in YL[L1]: for c2, n2 in YL[L2]: s += c1 * c2 * gam(n1[0] + n2[0], n1[1] + n2[1], n1[2] + n2[2]) return s if debug: for L1 in range(Lmax): for L2 in range(Lmax): r = 0.0 if L1 == L2: r = 1.0 assert abs(yLL(L1, L2) - r) < 1e-14 def Y(L, x, y, z): result = 0.0 for c, n in YL[L]: result += c * x**n[0] * y**n[1] * z**n[2] return result def nablarlYL(L, R): """Calculate the gradient of a real solid spherical harmonic.""" x, y, z = R dYdx = dYdy = dYdz = 0.0 terms = YL[L] # The 'abs' avoids error in case powx == 0 for N, (powx, powy, powz) in terms: dYdx += N * powx * x**abs(powx - 1) * y**powy * z**powz dYdy += N * powy * x**powx * y**abs(powy - 1) * z**powz dYdz += N * powz * x**powx * y**powy * z**abs(powz - 1) return dYdx, dYdy, dYdz gpaw-0.11.0.13004/gpaw/band_descriptor.py0000664000175000017500000002141712553643470020133 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. """Band-descriptors for blocked/strided groups. This module contains classes defining two kinds of band groups: * Blocked groups with contiguous band indices. * Strided groups with evenly-spaced band indices. """ import numpy as np from gpaw.mpi import serial_comm NONBLOCKING = False class BandDescriptor: """Descriptor-class for ordered lists of bands A ``BandDescriptor`` object holds information on how functions, such as wave functions and corresponding occupation numbers, are divided into groups according to band indices. The main information here is how many bands are stored on each processor and who gets what. This is how a 12 band array is laid out in memory on 3 cpu's:: a) Blocked groups b) Strided groups 3 7 11 9 10 11 myn 2 \ 6 \ 10 myn 6 7 8 | 1 \ 5 \ 9 | 3 4 5 | 0 4 8 | 0 1 2 | | +----- band_rank +----- band_rank Example: >>> a = np.zeros((3, 4)) >>> a.ravel()[:] = range(12) >>> a array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) >>> b = np.zeros((4, 3)) >>> b.ravel()[:] = range(12) >>> b.T array([[ 0, 3, 6, 9], [ 1, 4, 7, 10], [ 2, 5, 8, 11]]) """ def __init__(self, nbands, comm=None, strided=False): """Construct band-descriptor object. Parameters: nbands: int Global number of bands. comm: MPI-communicator Communicator for band-groups. strided: bool Enable strided band distribution for better load balancing with many unoccupied bands. Note that if comm.size is 1, then all bands are contained on a single CPU and blocked/strided grouping loses its meaning. Attributes: ============ ====================================================== ``nbands`` Number of bands in total. ``mynbands`` Number of bands on this CPU. ``beg`` Beginning of band indices in group (inclusive). ``end`` End of band indices in group (exclusive). ``step`` Stride for band indices between ``beg`` and ``end``. ``comm`` MPI-communicator for band distribution. ============ ====================================================== """ if comm is None: comm = serial_comm self.comm = comm self.rank = self.comm.rank self.nbands = nbands if self.nbands % self.comm.size != 0: raise RuntimeError('Cannot distribute %d bands to %d processors' % (self.nbands, self.comm.size)) self.mynbands = self.nbands // self.comm.size self.strided = strided nslice = self.get_slice() self.beg, self.end, self.step = nslice.indices(self.nbands) def __len__(self): return self.mynbands def get_slice(self, band_rank=None): """Return the slice of global bands which belong to a given rank.""" if band_rank is None: band_rank = self.comm.rank assert band_rank in range(self.comm.size) if self.strided: nstride = self.comm.size nslice = slice(band_rank, None, nstride) else: n0 = band_rank * self.mynbands nslice = slice(n0, n0 + self.mynbands) return nslice def get_band_indices(self, band_rank=None): """Return the global band indices which belong to a given rank.""" nslice = self.get_slice(band_rank) return np.arange(*nslice.indices(self.nbands)) def get_band_ranks(self): """Return array of ranks as a function of global band indices.""" rank_n = np.empty(self.nbands, dtype=int) for band_rank in range(self.comm.size): nslice = self.get_slice(band_rank) rank_n[nslice] = band_rank assert (rank_n >= 0).all() and (rank_n < self.comm.size).all() return rank_n def who_has(self, n): """Convert global band index to rank information and local index.""" if self.strided: myn, band_rank = divmod(n, self.comm.size) else: band_rank, myn = divmod(n, self.mynbands) return band_rank, myn def global_index(self, myn, band_rank=None): """Convert rank information and local index to global index.""" if band_rank is None: band_rank = self.comm.rank if self.strided: n = band_rank + myn * self.comm.size else: n = band_rank * self.mynbands + myn return n def get_size_of_global_array(self): return (self.nbands,) def zeros(self, n=(), dtype=float, global_array=False): """Return new zeroed 3D array for this domain. The type can be set with the ``dtype`` keyword (default: ``float``). Extra dimensions can be added with ``n=dim``. A global array spanning all domains can be allocated with ``global_array=True``.""" # TODO XXX doc return self._new_array(n, dtype, True, global_array) def empty(self, n=(), dtype=float, global_array=False): """Return new uninitialized 3D array for this domain. The type can be set with the ``dtype`` keyword (default: ``float``). Extra dimensions can be added with ``n=dim``. A global array spanning all domains can be allocated with ``global_array=True``.""" # TODO XXX doc return self._new_array(n, dtype, False, global_array) def _new_array(self, n=(), dtype=float, zero=True, global_array=False): if global_array: shape = self.get_size_of_global_array() else: shape = (self.mynbands,) if isinstance(n, int): n = (n,) shape = tuple(shape) + n if zero: return np.zeros(shape, dtype) else: return np.empty(shape, dtype) def collect(self, a_nx, broadcast=False): """Collect distributed array to master-CPU or all CPU's.""" if self.comm.size == 1: return a_nx xshape = a_nx.shape[1:] # Optimization for blocked groups if not self.strided: if broadcast: A_nx = self.empty(xshape, a_nx.dtype, global_array=True) self.comm.all_gather(a_nx, A_nx) return A_nx if self.rank == 0: A_nx = self.empty(xshape, a_nx.dtype, global_array=True) else: A_nx = None self.comm.gather(a_nx, 0, A_nx) return A_nx # Collect all arrays on the master: if self.rank != 0: # There can be several sends before the corresponding receives # are posted, so use syncronous send here self.comm.ssend(a_nx, 0, 3011) if broadcast: A_nx = self.empty(xshape, a_nx.dtype, global_array=True) self.comm.broadcast(A_nx, 0) return A_nx else: return None # Put the band groups from the slaves into the big array # for the whole collection of bands: A_nx = self.empty(xshape, a_nx.dtype, global_array=True) for band_rank in range(self.comm.size): if band_rank != 0: a_nx = self.empty(xshape, a_nx.dtype, global_array=False) self.comm.receive(a_nx, band_rank, 3011) A_nx[self.get_slice(band_rank), ...] = a_nx if broadcast: self.comm.broadcast(A_nx, 0) return A_nx def distribute(self, B_nx, b_nx): """ distribute full array B_nx to band groups, result in b_nx. b_nx must be allocated.""" if self.comm.size == 1: b_nx[:] = B_nx return # Optimization for blocked groups if not self.strided: self.comm.scatter(B_nx, b_nx, 0) return if self.rank != 0: self.comm.receive(b_nx, 0, 421) return else: requests = [] for band_rank in range(self.comm.size): if band_rank != 0: a_nx = B_nx[self.get_slice(band_rank), ...].copy() request = self.comm.send(a_nx, band_rank, 421, NONBLOCKING) # Remember to store a reference to the # send buffer (a_nx) so that is isn't # deallocated: requests.append((request, a_nx)) else: b_nx[:] = B_nx[self.get_slice(), ...] for request, a_nx in requests: self.comm.wait(request) gpaw-0.11.0.13004/gpaw/svnversion.py0000664000175000017500000000002512553644062017173 0ustar jensjjensj00000000000000svnversion = "13004" gpaw-0.11.0.13004/gpaw/dscf.py0000664000175000017500000003107312553643471015710 0ustar jensjjensj00000000000000# Copyright (C) 2008 CAMd # Please see the accompanying LICENSE file for further information. """This module is used in delta self-consistent field (dSCF) calculations dSCF is a simple 'ad hoc' method to estimating excitation energies within DFT. The only difference to ordinary DFT is that one or more electrons(s) are forced to occupy one or more predefined orbitals. The only restriction on these orbitals is that they must be linear combinations of available Kohn-Sham orbitals. """ import sys import copy import numpy as np from ase.parallel import paropen from ase.units import Hartree from ase.utils import devnull from gpaw import mpi from gpaw.occupations import OccupationNumbers, FermiDirac def dscf_calculation(paw, orbitals, atoms): """Helper function to prepare a calculator for a dSCF calculation Parameters ========== orbitals: list of lists Orbitals which one wants to occupy. The format is orbitals = [[1.0,orb1,0],[1.0,orb2,1],...], where 1.0 is the no. of electrons, orb1 and orb2 are the orbitals (see MolecularOrbitals below for an example of an orbital class). 0 and 1 represents the spin (up and down). This number is ignored in a spin-paired calculation. Example ======= >>> atoms.set_calculator(calc) >>> e_gs = atoms.get_potential_energy() #ground state energy >>> sigma_star=MolecularOrbitals(calc, molecule=[0,1], >>> w=[[1.,0.,0.,0.],[-1.,0.,0.,0.]]) >>> dscf_calculation(calc, [[1.0,sigma_star,1]], atoms) >>> e_exc = atoms.get_potential_energy() #excitation energy """ # If the calculator has not been initialized the occupation object # is None if paw.occupations is None: paw.initialize(atoms) occ = paw.occupations if occ.width == 0: occ.width = 1e-6 if isinstance(occ, OccupationsDSCF): paw.occupations.orbitals = orbitals else: new_occ = OccupationsDSCF(occ.width * Hartree, orbitals) paw.occupations = new_occ # If the calculator has already converged (for the ground state), # reset self-consistency and let the density be updated right away if paw.scf.converged: paw.scf.niter_fixdensity = 0 paw.scf.reset() class OccupationsDSCF(FermiDirac): """Occupation class. Corresponds to the ordinary FermiDirac class in occupation.py. Only difference is that it forces some electrons in the supplied orbitals in stead of placing all the electrons by a Fermi-Dirac distribution. """ def __init__(self, width, orbitals): FermiDirac.__init__(self, width) self.orbitals = orbitals self.norbitals = len(self.orbitals) self.cnoe = 0.0 for orb in self.orbitals: self.cnoe += orb[0] def set_number_of_electrons(self, wfs): self.nvalence = wfs.nvalence - self.cnoe def calculate(self, wfs): FermiDirac.calculate(self, wfs) # Get the expansion coefficients c_un for each dscf-orbital # and incorporate their respective occupations into kpt.ne_o c_oun = [] for orb in self.orbitals: ef = self.fermilevel if self.fixmagmom: fermilevels = [ef + 0.5 * self.split, ef - 0.5 * self.split] else: fermilevels = ef c_oun.append(orb[1].expand(fermilevels, wfs)) for u, kpt in enumerate(wfs.kpt_u): kpt.ne_o = np.zeros(self.norbitals, dtype=float) kpt.c_on = np.zeros((self.norbitals, len(kpt.f_n)), dtype=complex) for o, orb in enumerate(self.orbitals): # TODO XXX false if orb[0]<0 since abs(c_n)**2>0 #kpt.c_on[o,:] = abs(orb[0])**0.5 * c_oun[o][u] kpt.ne_o[o] = orb[0] kpt.c_on[o, :] = c_oun[o][u] if wfs.nspins == 2: assert orb[2] in range(2), 'Invalid spin index' if orb[2] == kpt.s: kpt.ne_o[o] *= kpt.weight else: kpt.ne_o[o] = 0.0 else: kpt.ne_o[o] *= 0.5 * kpt.weight # Correct the magnetic moment for orb in self.orbitals: if orb[2] == 0: self.magmom += orb[0] elif orb[2] == 1: self.magmom -= orb[0] def calculate_band_energy(self, wfs): FermiDirac.calculate_band_energy(self, wfs) de_band = 0.0 for kpt in wfs.kpt_u: if hasattr(kpt, 'c_on'): for ne, c_n in zip(kpt.ne_o, kpt.c_on): de_band += ne * np.dot(np.abs(c_n)**2, kpt.eps_n) self.e_band += wfs.band_comm.sum(wfs.kd.comm.sum(de_band)) class MolecularOrbital: """Class defining the orbitals that should be filled in a dSCF calculation. An orbital is defined through a linear combination of the atomic partial waves. In each self-consistent cycle the method expand is called. This method take the Kohn-Sham orbitals fulfilling the criteria given by Estart, Eend and nos and return the best possible expansion of the orbital in this basis. The integral of the Kohn-Sham all-electron wavefunction ``|u,n>`` (u being local spin and kpoint index) and the partial wave ``|\phi_i^a>`` is approximated by:: wfs.kpt_u[u].P_ani = <\tilde p_i^a|\tilde\psi_{un}>. Parameters ---------- paw: gpaw calculator instance The calculator used in the dSCF calculation. Estart: float Kohn-Sham orbitals with an energy above Efermi+Estart are used in the linear expansion. Eend: float Kohn-Sham orbitals with an energy below Efermi+Eend are used in the linear expansion. nos: int The maximum Number Of States used in the linear expansion. weights: dictionary The keys represent atoms and have values which are lists of weights of the contributing partial waves. The default value thuis corresponds to an antibonding 2\sigma orbital of atoms 0 and 1. Format:: {1. atom: [weight of 1. projector function of the 1. atom, weight of 2. projector function of the 1. atom, ...], 2. atom: [weight of 1. projector function of the 2. atom, weight of 2. projector function of the 2. atom, ...], ...} """ def __init__(self, paw, Estart=0.0, Eend=1.e6, nos=None, weights={0: [1], 1: [-1]}): self.fixmom = paw.input_parameters.fixmom self.w = weights self.Estart = Estart self.Eend = Eend self.nos = nos def expand(self, epsF, wfs): if wfs.nspins == 1: epsF = [epsF] elif not self.fixmom: epsF = [epsF, epsF] if self.nos is None: self.nos = wfs.bd.nbands c_un = [] for u, kpt in enumerate(wfs.kpt_u): Porb_n = np.zeros(wfs.bd.nbands, dtype=complex) for a, P_ni in kpt.P_ani.items(): if a in self.w.keys(): for i in range(len(self.w[a])): Porb_n += self.w[a][i] * P_ni[:, i] wfs.gd.comm.sum(Porb_n) # Starting from KS orbitals with largest overlap, # fill in the expansion coeffients between Estart and Eend c_n = np.zeros(wfs.bd.nbands, dtype=complex) nos = 0 bandpriority = np.argsort(abs(Porb_n)**2)[::-1] for n in bandpriority: if (kpt.eps_n[n] > epsF[kpt.s] + self.Estart and kpt.eps_n[n] < epsF[kpt.s] + self.Eend): c_n[n] = Porb_n[n].conj() nos += 1 if nos == self.nos: break # Normalize expansion coefficients c_n /= np.sqrt(sum(abs(c_n)**2)) c_un.append(c_n) return c_un class AEOrbital: """Class defining the orbitals that should be filled in a dSCF calculation. An orbital is defined through a linear combination of KS orbitals which is determined by this class as follows: For each kpoint and spin we calculate the quantity ``c_n = `` where ``|n>`` is the all-electron KS states in the calculation and ``|a>`` is the all-electron resonant state to be kept occupied. We can then write ``|a> = Sum(c_n|n>)`` and in each self-consistent cycle the method expand is called. This method take the Kohn-Sham orbitals fulfilling the criteria given by Estart, Eend and nos (Number Of States) and return the best possible expansion of the orbital in this basis. Parameters ---------- paw: gpaw calculator instance The calculator used in the dSCF calculation. molecule: list of integers The atoms, which are a part of the molecule. Estart: float Kohn-Sham orbitals with an energy above Efermi+Estart are used in the linear expansion. Eend: float Kohn-Sham orbitals with an energy below Efermi+Eend are used in the linear expansion. nos: int The maximum Number Of States used in the linear expansion. wf_u: list of wavefunction arrays Wavefunction to be occupied on the kpts on this processor: wf_u = [kpt.psit_nG[n] for kpt in calc_mol.wfs.kpt_u] p_uai: list of dictionaries Projector overlaps with the wavefunction to be occupied for each kpoint. These are used when correcting to all-electron wavefunction overlaps: p_uai = [dict([(mol[a], P_ni[n]) for a, P_ni in kpt.P_ani.items()]) for kpt in paw.wfs.kpt_u] where mol is a list of atoms contributing to the state and n is the band. See examples in the dscf documentation on the gpaw webpage. """ def __init__(self, paw, wf_u, p_uai, Estart=0.0, Eend=1.e6, nos=None, txt='-'): self.fixmom = paw.input_parameters.fixmom self.wf_u = wf_u self.p_uai = p_uai self.Estart = Estart self.Eend = Eend self.nos = nos if txt is None: self.txt = devnull elif txt == '-': self.txt = sys.stdout elif isinstance(txt, str): self.txt = paropen(txt, 'w') else: self.txt = txt def expand(self, epsF, wfs): if wfs.nspins == 1: epsF = [epsF] elif not self.fixmom: epsF = [epsF, epsF] if self.nos is None: self.nos = wfs.bd.nbands # Check dimension of lists if len(self.wf_u) == len(wfs.kpt_u): wf_u = self.wf_u p_uai = self.p_uai else: raise RuntimeError('List of wavefunctions has wrong size') c_un = [] p_u = [] for u, kpt in enumerate(wfs.kpt_u): # Inner product of pseudowavefunctions wf = np.reshape(wf_u[u], -1) Wf_n = kpt.psit_nG Wf_n = np.reshape(Wf_n, (len(kpt.f_n), -1)) Porb_n = np.dot(Wf_n.conj(), wf) * wfs.gd.dv # Correction to obtain inner product of AE wavefunctions for a, p_i in p_uai[u].items(): for n in range(wfs.bd.nbands): for i in range(len(p_i)): for j in range(len(p_i)): Porb_n[n] += (kpt.P_ani[a][n][i].conj() * wfs.setups[a].dO_ii[i][j] * p_i[j]) wfs.gd.comm.sum(Porb_n) #print 'Kpt:', kpt.k, ' Spin:', kpt.s, \ # ' Sum_n||^2:', sum(abs(Porb_n)**2) p_u.append(np.array([sum(abs(Porb_n)**2)], dtype=float)) # Starting from KS orbitals with largest overlap, # fill in the expansion coeffients c_n = np.zeros(wfs.bd.nbands, dtype=complex) nos = 0 bandpriority = np.argsort(abs(Porb_n)**2)[::-1] for n in bandpriority: if (kpt.eps_n[n] > epsF[kpt.s] + self.Estart and kpt.eps_n[n] < epsF[kpt.s] + self.Eend): c_n[n] = Porb_n[n] nos += 1 if nos == self.nos: break # Normalize expansion coefficients c_n /= np.sqrt(sum(abs(c_n)**2)) c_un.append(c_n) for s in range(wfs.nspins): for k in range(wfs.kd.nibzkpts): p = wfs.collect_auxiliary(p_u, k, s) if wfs.world.rank == 0: self.txt.write('Kpt: %d, Spin: %d, ' 'Sum_n||^2: %f\n' % (k, s, p)) return c_un gpaw-0.11.0.13004/gpaw/test/0000775000175000017500000000000012553644063015370 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/aluminum_testcell.py0000664000175000017500000000422212553643471021472 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np import sys import os import time from ase import Atom, Atoms from ase.visualize import view from ase.units import Bohr from ase.lattice import bulk from ase.utils import devnull from gpaw import GPAW from gpaw.eigensolvers.rmm_diis_old import RMM_DIIS from gpaw.atom.basis import BasisMaker from gpaw.response.df0 import DF from gpaw.mixer import Mixer from gpaw.mpi import serial_comm, rank, size # Ground state calculation a = 4.043 atoms = bulk('Al', 'fcc', a=a) atoms.center() calc = GPAW(gpts=(12,12,12), eigensolver=RMM_DIIS(), mixer=Mixer(0.1,3), kpts=(4,4,4), xc='LDA') atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('Al1.gpw','all') # Excited state calculation q = np.array([1./4.,0.,0.]) w = np.linspace(0, 24, 241) df = DF(calc='Al1.gpw', q=q, w=w, eta=0.2, ecut=50) #df.write('Al.pckl') df.get_EELS_spectrum(filename='EELS_Al_1') atoms = Atoms('Al8',scaled_positions=[(0,0,0), (0.5,0,0), (0,0.5,0), (0,0,0.5), (0.5,0.5,0), (0.5,0,0.5), (0.,0.5,0.5), (0.5,0.5,0.5)], cell=[(0,a,a),(a,0,a),(a,a,0)], pbc=True) calc = GPAW(gpts=(24,24,24), eigensolver=RMM_DIIS(), mixer=Mixer(0.1,3), kpts=(2,2,2), xc='LDA') atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('Al2.gpw','all') # Excited state calculation q = np.array([1./2.,0.,0.]) w = np.linspace(0, 24, 241) df = DF(calc='Al2.gpw', q=q, w=w, eta=0.2, ecut=50) #df.write('Al.pckl') df.get_EELS_spectrum(filename='EELS_Al_2') d1 = np.loadtxt('EELS_Al_1') d2 = np.loadtxt('EELS_Al_2') error1 = (d1[1:,1] - d2[1:,1]) / d1[1:,1] * 100 error2 = (d1[1:,2] - d2[1:,2]) / d1[1:,2] * 100 if error1.max() > 0.2 or error2.max() > 0.2: # percent print(error1.max(), error2.max()) raise ValueError('Pls check spectrum !') #if rank == 0: # os.remove('Al1.gpw') # os.remove('Al2.gpw') gpaw-0.11.0.13004/gpaw/test/lf.py0000664000175000017500000000123112553643472016343 0ustar jensjjensj00000000000000from gpaw.test import equal from gpaw.grid_descriptor import GridDescriptor from gpaw.spline import Spline import gpaw.mpi as mpi from gpaw.lfc import LocalizedFunctionsCollection as LFC s = Spline(0, 1.0, [1.0, 0.5, 0.0]) n = 40 a = 8.0 gd = GridDescriptor((n, n, n), (a, a, a), comm=mpi.serial_comm) c = LFC(gd, [[s], [s], [s]]) c.set_positions([(0.5, 0.5, 0.25 + 0.25 * i) for i in [0, 1, 2]]) b = gd.zeros() c.add(b) x = gd.integrate(b) gd = GridDescriptor((n, n, n), (a, a, a), comm=mpi.serial_comm) c = LFC(gd, [[s], [s], [s]]) c.set_positions([(0.5, 0.5, 0.25 + 0.25 * i) for i in [0, 1, 2]]) b = gd.zeros() c.add(b) y = gd.integrate(b) equal(x, y, 1e-13) gpaw-0.11.0.13004/gpaw/test/noncollinear/0000775000175000017500000000000012553644063020053 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/noncollinear/h.py0000664000175000017500000000133312553643471020656 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW from gpaw.xc.noncollinear import NonCollinearFunctional, \ NonCollinearLCAOEigensolver, NonCollinearMixer from gpaw.xc import XC h = Atoms('H', magmoms=[1]) h.center(vacuum=2) h.calc = GPAW(txt='c.txt', mode='lcao', basis='dz(dzp)', h=0.25) e0 = h.get_potential_energy() h.set_initial_magnetic_moments() h.set_initial_magnetic_moments([(0.1, 0.2, 0.3)]) h.calc = GPAW(txt='nc.txt', mode='lcao', basis='dz(dzp)', h=0.25, xc=NonCollinearFunctional(XC('LDA')), mixer=NonCollinearMixer(), eigensolver=NonCollinearLCAOEigensolver()) e = h.get_potential_energy() assert abs(e - e0) < 2e-5, (e, e0) from ase.io import write write('h.traj', h) gpaw-0.11.0.13004/gpaw/test/noncollinear/xcgrid3d.py0000664000175000017500000000353312553643471022142 0ustar jensjjensj00000000000000from math import pi from gpaw.grid_descriptor import GridDescriptor from gpaw.xc import XC from gpaw.xc.noncollinear import NonCollinearLDAKernel, NonCollinearFunctional import numpy as np from gpaw.test import equal N = 20 a = 1.0 gd = GridDescriptor((N, N, N), (a, a, a)) for xc in [XC('LDA'), XC('PBE')]: n = gd.empty(2) n.fill(0.03) z = np.arange(gd.beg_c[2], gd.end_c[2]) * a / N n[:] += 0.01 * np.sin(2 * pi * z / a) n[1] += 0.02 + 0.01 * np.cos(2 * pi * z / a) n /= 2 v = 0.0 * n E = xc.calculate(gd, n, v) here = (gd.beg_c[0] <= 1 < gd.end_c[0] and gd.beg_c[1] <= 2 < gd.end_c[1] and gd.beg_c[2] <= 3 < gd.end_c[2]) if here: x = v[-1, 1, 2, 3] * gd.dv n[-1, 1, 2, 3] += 0.000001 Ep = xc.calculate(gd, n, v) if here: n[-1, 1, 2, 3] -= 0.000002 Em = xc.calculate(gd, n, v) x2 = (Ep - Em) / 0.000002 if here: print(xc.name, E, x, x2, x - x2) equal(x, x2, 1e-11) n[-1, 1, 2, 3] += 0.000001 if 0:#xc.type == 'LDA': xc = XC(NonCollinearLDAKernel()) else: xc = NonCollinearFunctional(xc) n2 = gd.zeros(4) n2[0] = n.sum(0) n2[3] = n[0] - n[1] E2 = xc.calculate(gd, n2) print(E, E2-E) assert abs(E2 - E) < 1e-11 n2[1] = 0.1 * n2[3] n2[2] = 0.2 * n2[3] n2[3] *= (1 - 0.1**2 - 0.2**2)**0.5 v = n2 * 0 E2 = xc.calculate(gd, n2, v) print(E, E2-E) assert abs(E2 - E) < 1e-11 for i in range(4): if here: x = v[i, 1, 2, 3] * gd.dv n2[i, 1, 2, 3] += 0.000001 Ep = xc.calculate(gd, n2) if here: n2[i, 1, 2, 3] -= 0.000002 Em = xc.calculate(gd, n2) x2 = (Ep - Em) / 0.000002 if here: print(i, x, x2, x - x2) equal(x, x2, 1e-11) n2[i, 1, 2, 3] += 0.000001 gpaw-0.11.0.13004/gpaw/test/noncollinear/__init__.py0000664000175000017500000000000012553643471022154 0ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/noncollinear/xccorr.py0000664000175000017500000000256012553643471021732 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np import numpy.random as ra from gpaw.setup import create_setup from gpaw.xc.noncollinear import NonCollinearFunctional from gpaw.xc import XC from gpaw.test import equal from gpaw.utilities import pack x = 0.0000001 ra.seed(8) for xc in ['LDA']:#, 'PBE']: print(xc) xc = XC(xc) s = create_setup('N', xc) ni = s.ni D_sp = np.array([pack(np.outer(P_i, P_i)) for P_i in 0.2 * ra.random((2, ni)) - 0.1]) D_sp[1] += D_sp[0] nii = ni * (ni + 1) // 2 E = xc.calculate_paw_correction(s, D_sp) xc = NonCollinearFunctional(xc) Dnc_sp = np.zeros((4, nii)) Dnc_sp[0] = D_sp.sum(0) Dnc_sp[3] = D_sp[0] - D_sp[1] Enc = xc.calculate_paw_correction(s, Dnc_sp) print(E, E-Enc) assert abs(E - Enc) < 1e-11 Dnc_sp[1] = 0.1 * Dnc_sp[3] Dnc_sp[2] = 0.2 * Dnc_sp[3] Dnc_sp[3] *= (1 - 0.1**2 - 0.2**2)**0.5 H_sp = 0 * Dnc_sp Enc = xc.calculate_paw_correction(s, Dnc_sp, H_sp) print(E, E-Enc) assert abs(E - Enc) < 1e-11 dD_sp = x * ra.random((4, nii)) dE = np.dot(H_sp.ravel(), dD_sp.ravel()) / x Dnc_sp += dD_sp Ep = xc.calculate_paw_correction(s, Dnc_sp) Dnc_sp -= 2 * dD_sp Em = xc.calculate_paw_correction(s, Dnc_sp) print(dE, dE - 0.5 * (Ep - Em) / x) assert abs(dE - 0.5 * (Ep - Em) / x) < 2e-8 gpaw-0.11.0.13004/gpaw/test/rpa_energy_Na.py0000664000175000017500000000156412553643471020523 0ustar jensjjensj00000000000000from ase.lattice import bulk from gpaw import GPAW, FermiDirac, PW from gpaw.mpi import serial_comm from gpaw.xc.rpa import RPACorrelation from gpaw.test import equal bulk = bulk('Na', 'bcc', a=4.23) ecut = 350 calc = GPAW(mode=PW(ecut), dtype=complex, basis='dzp', kpts={'size': (4, 4, 4), 'gamma': True}, parallel={'domain': 1}, txt='gs_occ_pw.txt', nbands=4, occupations=FermiDirac(0.01), setups={'Na': '1'}, ) bulk.set_calculator(calc) bulk.get_potential_energy() calc.write('gs_occ_pw.gpw') calc = GPAW('gs_occ_pw.gpw', txt='gs_pw.txt', parallel={'band': 1}) calc.diagonalize_full_hamiltonian(nbands=520) calc.write('gs_pw.gpw', 'all') ecut = 120 calc = GPAW('gs_pw.gpw', communicator=serial_comm, txt=None) rpa = RPACorrelation(calc, txt='rpa_%s.txt' % ecut) E = rpa.calculate(ecut=[ecut]) equal(E, -1.106, 0.005) gpaw-0.11.0.13004/gpaw/test/vdwradii.py0000664000175000017500000000141212553643472017554 0ustar jensjjensj00000000000000from ase.units import Bohr from gpaw.analyse.vdwradii import vdWradii # data from A. Bondi, J. Phys. Chem. 68 (1964) 441 data_Bondi = { # units Anstrom 'He' : 1.40, 'Ne' : 1.54, 'Ar' : 1.88, 'Kr' : 2.02, 'Xe' : 2.16 } # data from Felix Hanke (FHI-AIMS ?) data_Hanke = { # units Anstrom 'H' : 1.640449351, 'C' : 1.8997461838999998, 'N' : 1.7674518813999998, 'O' : 1.6880752998999997, 'Cu': 1.9897063095999996, } for symbol in ['He', 'Ne', 'Ar', 'Kr', 'H', 'C', 'N', 'O', 'Cu']: R = vdWradii([symbol], 'PBE')[0] if symbol in data_Bondi: Rref = data_Bondi[symbol] else: Rref = data_Hanke[symbol] error = abs(R - Rref) print("symbol, R, Rref, error:", symbol, R, Rref, error) assert(error < 0.05) gpaw-0.11.0.13004/gpaw/test/be_nltd_ip.py0000664000175000017500000000204312553643471020042 0ustar jensjjensj00000000000000import numpy as np from ase import Atoms from gpaw import GPAW from gpaw.tddft import TDDFT from gpaw.tddft.abc import LinearAbsorbingBoundary from gpaw.tddft.laser import CWField atoms = Atoms('Be',[(0,0,0)], pbc=False) atoms.center(vacuum=6) calc = GPAW(h=0.35) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('be_gs.gpw', 'all') td_calc = TDDFT('be_gs.gpw', td_potential = CWField(1e-3, 2.0*np.pi/50.0, 150.0)) td_calc.set_absorbing_boundary(LinearAbsorbingBoundary(5.0, 0.01, atoms.positions.copy())) td_calc.propagate(8.0, 5, 'be_nl_dmz_ipabs_1e-3.dat', 'be_nl_td.gpw') td_rest = TDDFT('be_nl_td.gpw', td_potential = CWField(1e-3, 2.0*np.pi/50.0, 150.0)) td_rest.set_absorbing_boundary(LinearAbsorbingBoundary(5.0, 0.01, atoms.positions.copy())) td_rest.propagate(8.0, 5, 'be_nl_dmz_ipabs_1e-3.dat', 'be_nl_td.gpw') gpaw-0.11.0.13004/gpaw/test/usesymm.py0000664000175000017500000000120412553643472017444 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atoms from gpaw import GPAW, FermiDirac a = 2.0 L = 5.0 a1 = Atoms('H', pbc=(1, 0, 0), cell=(a, L, L)) a1.center() atoms = a1.repeat((4, 1, 1)) def energy(symm={}): atoms.set_calculator(GPAW(h=0.3, occupations=FermiDirac(width=0.1), symmetry=symm, convergence=dict(energy=1e-6), kpts=(3, 1, 1), mode='lcao')) return atoms.get_potential_energy() e1 = energy() e2 = energy('off') print(e1) print(e2) assert abs(e2 - e1) < 1e-6 gpaw-0.11.0.13004/gpaw/test/eigh.py0000664000175000017500000000113612553643471016661 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np tol = 1e-8 a = np.eye(3, dtype=complex) a[1:, 0] = 0.01j w0 = [0.98585786, 1.0, 1.01414214] # NumPy's Diagonalize from numpy.linalg import eigh w = eigh(a)[0] print(w) assert abs(w - w0).max() < tol # LAPACK's QR Diagonalize from gpaw.utilities.lapack import diagonalize diagonalize(a.copy(), w) print(w) assert abs(w - w0).max() < tol # LAPACK's MR3 Diagonalize # Requires Netlib LAPACK 3.2.1 or later # from gpaw.utilities.lapack import diagonalize_mr3 # z = np.zeros_like(a) # diagonalize_mr3(a, w, z) # print w # assert abs(w - w0).max() < tol gpaw-0.11.0.13004/gpaw/test/numpy_core_multiarray_dot.py0000664000175000017500000000021512553643472023242 0ustar jensjjensj00000000000000# Segmentation fault with acml's _dotblas.so import numpy as np from numpy.core.multiarray import dot b = np.ones(13, np.complex); dot(b, b) gpaw-0.11.0.13004/gpaw/test/transport_non_sc.py0000664000175000017500000000234512553643471021343 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import FermiDirac, Mixer from gpaw.transport.calculator import Transport from gpaw.atom.basis import BasisMaker from gpaw.poisson import PoissonSolver import pickle a = 3.6 L = 7.00 basis = BasisMaker('Na').generate(1, 1, energysplit=0.3) atoms = Atoms('Na12', pbc=(0, 0, 1), cell=[L, L, 12 * a]) atoms.positions[:12, 2] = [i * a for i in range(12)] atoms.positions[:, :2] = L / 2. atoms.center() pl_atoms1 = range(4) pl_atoms2 = range(8, 12) pl_cell1 = (L, L, 4 * a) pl_cell2 = pl_cell1 t = Transport(h=0.3, xc='LDA', basis={'Na': basis}, kpts=(1,1,1), occupations=FermiDirac(0.1), mode='lcao', poissonsolver=PoissonSolver(nn=2, relax='GS'), txt='Na_lcao.txt', mixer=Mixer(0.1, 5, weight=100.0), guess_steps=10, pl_atoms=[pl_atoms1, pl_atoms2], pl_cells=[pl_cell1, pl_cell2], pl_kpts=(1,1,15), non_sc=True, analysis_data_list=['tc'], fixed_boundary=False, edge_atoms=[[0, 3], [0, 11]], mol_atoms=range(4, 8)) atoms.set_calculator(t) t.negf_prepare() t.non_sc_analysis() gpaw-0.11.0.13004/gpaw/test/lcao_force.py0000664000175000017500000000341612553643471020044 0ustar jensjjensj00000000000000from __future__ import print_function # This tests calculates the force on the atoms of a small molecule. # # If the test fails, set the fd boolean below to enable a (costly) finite # difference check. import numpy as np from ase.structure import molecule from gpaw import GPAW from gpaw.atom.basis import BasisMaker obasis = BasisMaker('O').generate(2, 1, energysplit=0.3, tailnorm=0.03**.5) hbasis = BasisMaker('H').generate(2, 1, energysplit=0.3, tailnorm=0.03**.5) basis = {'O' : obasis, 'H' : hbasis} system = molecule('H2O') system.center(vacuum=1.5) system.rattle(stdev=.2, seed=42) system.set_pbc(1) calc = GPAW(h=0.2, mode='lcao', basis=basis, kpts=[(0., 0., 0.), (.3, .1, .4)], convergence={'density':1e-5, 'energy': 1e-6} ) system.set_calculator(calc) F_ac = system.get_forces() # Previous FD result, generated by disabled code below F_ac_ref = np.array([[ 1.05200088, 1.64950565, -5.01149812], [-0.70775684, -0.89551937, 3.03218888], [-0.3330413, -0.70650306, 1.77179155]]) err_ac = np.abs(F_ac - F_ac_ref) err = err_ac.max() print('Force') print(F_ac) print() print('Reference result') print(F_ac_ref) print() print('Error') print(err_ac) print() print('Max error') print(err) # ASE uses dx = [+|-] 0.001 by default, # error should be around 2e-3. In fact 4e-3 would probably be acceptable assert err < 3e-3 # Set boolean to run new FD check fd = not not False if fd: from ase.calculators.test import numeric_forces F_ac_fd = numeric_forces(system) print('Self-consistent forces') print(F_ac) print('FD') print(F_ac_fd) print(repr(F_ac_fd)) print(F_ac - F_ac_fd, np.abs(F_ac - F_ac_fd).max()) assert np.abs(F_ac - F_ac_fd).max() < 4e-3 gpaw-0.11.0.13004/gpaw/test/mmm.py0000664000175000017500000000131512553643471016532 0ustar jensjjensj00000000000000"""Test BLAS matrix-matrix-multiplication interface.""" import numpy as np from gpaw.utilities.blas import mmm def op(o, m): if o == 'n': return m if o == 't': return m.T return m.T.conj() def matrix(shape, dtype): if dtype == float: return np.random.random(shape) return np.random.random(shape) + 1j * np.random.random(shape) for dtype in [float, complex]: a = matrix((2, 3), dtype) for opa in 'ntc': A = op(opa, a) B = matrix((A.shape[1], 4), dtype) for opb in 'ntc': b = op(opb, B).copy() C = np.dot(A, B) mmm(1, a, opa, b, opb, -1, C) assert abs(C).max() < 1e-14 gpaw-0.11.0.13004/gpaw/test/nonselfconsistentLDA.py0000664000175000017500000000212512553643471022043 0ustar jensjjensj00000000000000from __future__ import print_function import os from ase import Atom, Atoms from ase.units import Bohr from gpaw import GPAW from gpaw.test import equal a = 7.5 * Bohr n = 16 atoms = Atoms([Atom('He', (0.0, 0.0, 0.0))], cell=(a, a, a), pbc=True) calc = GPAW(gpts=(n, n, n), nbands=1, xc='LDA') atoms.set_calculator(calc) e1 = atoms.get_potential_energy() niter1 = calc.get_number_of_iterations() e1ref = calc.get_reference_energy() de12 = calc.get_xc_difference('PBE') calc.set(xc='PBE') e2 = atoms.get_potential_energy() niter2 = calc.get_number_of_iterations() e2ref = calc.get_reference_energy() de21 = calc.get_xc_difference('LDA') print(e1ref + e1 + de12, e2ref + e2) print(e1ref + e1, e2ref + e2 + de21) print(de12, de21) equal(e1ref + e1 + de12, e2ref + e2, 0.02) equal(e1ref + e1, e2ref + e2 + de21, 0.025) calc.write('PBE.gpw') de21b = GPAW('PBE.gpw').get_xc_difference('LDA') print(de21, de21b) equal(de21, de21b, 9e-8) energy_tolerance = 0.00007 niter_tolerance = 0 equal(e1, -0.0961003634812, energy_tolerance) # svnversion 5252 equal(e2, -0.0790249564625, energy_tolerance) # svnversion 5252 gpaw-0.11.0.13004/gpaw/test/xcatom.py0000664000175000017500000000244012553643471017237 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np import numpy.random as ra from gpaw.setup import create_setup from gpaw.xc import XC from gpaw.test import equal x = 0.000001 ra.seed(8) for xc in ['LDA', 'PBE']: print(xc) xc = XC(xc) s = create_setup('N', xc) ni = s.ni nii = ni * (ni + 1) // 2 D_p = 0.1 * ra.random(nii) + 0.2 H_p = np.zeros(nii) E = xc.calculate_paw_correction(s, D_p.reshape(1, -1), H_p.reshape(1, -1)) dD_p = x * ra.random(nii) dE = np.dot(H_p, dD_p) / x D_p += dD_p Ep = xc.calculate_paw_correction(s, D_p.reshape(1, -1)) D_p -= 2 * dD_p Em = xc.calculate_paw_correction(s, D_p.reshape(1, -1)) print(dE, dE - 0.5 * (Ep - Em) / x) equal(dE, 0.5 * (Ep - Em) / x, 1e-6) Ems = xc.calculate_paw_correction(s, np.array([0.5 * D_p, 0.5 * D_p])) print(Em - Ems) equal(Em, Ems, 1.0e-12) D_sp = 0.1 * ra.random((2, nii)) + 0.2 H_sp = np.zeros((2, nii)) E = xc.calculate_paw_correction(s, D_sp, H_sp) dD_sp = x * ra.random((2, nii)) dE = np.dot(H_sp.ravel(), dD_sp.ravel()) / x D_sp += dD_sp Ep = xc.calculate_paw_correction(s, D_sp) D_sp -= 2 * dD_sp Em = xc.calculate_paw_correction(s, D_sp) print(dE, dE - 0.5 * (Ep - Em) / x) equal(dE, 0.5 * (Ep - Em) / x, 1e-6) gpaw-0.11.0.13004/gpaw/test/setup_basis_spec.py0000664000175000017500000000207312553643471021301 0ustar jensjjensj00000000000000import numpy as np from ase import Atoms from gpaw import GPAW, setup_paths from gpaw.setup_data import SetupData # This test looks for differently named setups and basis sets to ascertain # that correct filenames are constructed. Generally speaking, the things # it looks for do not exist; we just verify the filenames. del setup_paths[:] system = Atoms('Na') system.center(vacuum=3.0) def check(setups, basis, refname): calc = GPAW(setups=setups, basis=basis) system.set_calculator(calc) try: calc.initialize(system) except RuntimeError as err: msg = str(err) fname = msg.split('"')[1] assert fname == refname, fname else: assert False check({}, 'hello', 'Na.hello.basis') check('hello', {}, 'Na.hello.LDA') check('hello', 'dzp', 'Na.hello.dzp.basis') check('hello', 'sz(dzp)', 'Na.hello.dzp.basis') check('hello', 'world.dzp', 'Na.hello.world.dzp.basis') check('hello', 'sz(world.dzp)', 'Na.hello.world.dzp.basis') check('paw', 'world.dzp', 'Na.world.dzp.basis') check('paw', 'sz(world.dzp)', 'Na.world.dzp.basis') gpaw-0.11.0.13004/gpaw/test/wfs_io.py0000664000175000017500000000276312553643471017242 0ustar jensjjensj00000000000000from __future__ import print_function """Test automatically write out of restart files""" import os import sys import time from gpaw import GPAW from ase import Atom, Atoms from gpaw.test import equal from ase.parallel import rank, barrier, size endings = ['gpw'] try: import Scientific.IO.NetCDFXXXX endings.append('nc') except ImportError: pass for ending in endings: restart = 'gpaw-restart-wfs_io.' + ending restart_wf = 'gpaw-restart-wfs_io-wf.' + ending # H2 H = Atoms([Atom('H', (0, 0, 0)), Atom('H', (0, 0, 1))]) H.center(vacuum=2.0) wfdir = 'wfs_tmp' mode = ending+':' + wfdir + '/psit_s%dk%dn%d' if 1: calc = GPAW(nbands=2, convergence={'eigenstates': 1e-3}) H.set_calculator(calc) H.get_potential_energy() barrier() calc.write(restart_wf, 'all') calc.write(restart, mode) barrier() # refine the restart file containing the wfs E1 = GPAW(restart_wf, convergence= {'eigenstates': 1.e-5}).get_atoms().get_potential_energy() # refine the restart file and separate wfs calc = GPAW(restart, convergence={'eigenstates': 1.e-5}) calc.read_wave_functions(mode) E2 = calc.get_atoms().get_potential_energy() print(E1, E2) equal(E1, E2, 1e-12) barrier() if rank == 0: os.remove(restart_wf) os.remove(restart) for f in os.listdir(wfdir): os.remove(wfdir + '/' + f) os.rmdir(wfdir) gpaw-0.11.0.13004/gpaw/test/si.py0000664000175000017500000000237212553643471016363 0ustar jensjjensj00000000000000from __future__ import print_function from gpaw import GPAW, restart, FermiDirac from ase import Atoms from ase.calculators.test import numeric_force from gpaw.test import equal import numpy as np a = 5.404 bulk = Atoms(symbols='Si8', scaled_positions=[(0, 0, 0), (0, 0.5, 0.5), (0.5, 0, 0.5), (0.5, 0.5, 0), (0.25, 0.25, 0.25), (0.25, 0.75, 0.75), (0.75, 0.25, 0.75), (0.75, 0.75, 0.25)], pbc=True, cell=(a, a, a)) n = 20 calc = GPAW(gpts=(n, n, n), nbands=8*3, occupations=FermiDirac(width=0.01), verbose=1, kpts=(1, 1, 1)) bulk.set_calculator(calc) e1 = bulk.get_potential_energy() niter1 = calc.get_number_of_iterations() eigs = calc.get_eigenvalues(kpt=0) calc.write('temp.gpw') bulk, calc = restart('temp.gpw', fixdensity=True) e2 = bulk.get_potential_energy() eigs2 = calc.get_eigenvalues(kpt=0) print('Orginal', eigs) print('Fixdensity', eigs2) print('Difference', eigs2-eigs) assert np.fabs(eigs2 - eigs)[:-1].max() < 3e-5 equal(e1, -36.7667, 0.001) equal(e1, e2, 1e-10) gpaw-0.11.0.13004/gpaw/test/beef.py0000664000175000017500000000257112553643471016652 0ustar jensjjensj00000000000000from ase import Atoms from ase.dft.bee import BEEFEnsemble, readbee from gpaw import GPAW from gpaw.test import equal, gen from gpaw.mpi import world import _gpaw newlibxc = _gpaw.lxcXCFuncNum('MGGA_X_MBEEF') is not None c = {'energy': 0.001, 'eigenstates': 1, 'density': 1} d = 0.75 gen('H', xcname='PBEsol') for xc, E0, dE0 in [('mBEEF', 4.86, 0.16), ('BEEF-vdW', 5.13, 0.20), ('mBEEF-vdW', 4.74, 0.36)]: print(xc) if not newlibxc and xc[0] == 'm': print('Skipped') continue # H2 molecule: h2 = Atoms('H2', [[0, 0, 0], [0, 0, d]]) h2.center(vacuum=2) h2.calc = GPAW(txt='H2-' + xc + '.txt', convergence=c) h2.get_potential_energy() h2.calc.set(xc=xc) h2.get_potential_energy() h2.get_forces() ens = BEEFEnsemble(h2.calc) e_h2 = ens.get_ensemble_energies() # H atom: h = Atoms('H', cell=h2.cell, magmoms=[1]) h.center() h.calc = GPAW(txt='H-' + xc + '.txt', convergence=c) h.get_potential_energy() h.calc.set(xc=xc) h.get_potential_energy() ens = BEEFEnsemble(h.calc) e_h = ens.get_ensemble_energies() # binding energy ae = 2 * e_h - e_h2 print(ae.mean(), ae.std()) equal(ae.mean(), E0, 0.015) equal(ae.std(), dE0, 0.015) ens.write('H') world.barrier() energies = readbee('H') equal(abs(energies - e_h).max(), 0, 1e-12) gpaw-0.11.0.13004/gpaw/test/response_symmetry.py0000664000175000017500000000361612553643471021561 0ustar jensjjensj00000000000000import numpy as np from ase import Atoms from ase.parallel import paropen from gpaw import GPAW, FermiDirac from gpaw.wavefunctions.pw import PW from gpaw.response.chi0 import Chi0 from gpaw.test import equal # This script asserts that the chi's obtained # from GS calculations using symmetries # and GS calculations not using symmetries return # the same results. Tests that the chi's are element-wise # equal to a tolerance of 1e-10. resultfile = paropen('results.txt', 'a') pwcutoff = 400.0 k = 4 a = 4.59 c = 2.96 u = 0.305 rutile_cell = [[a, 0, 0], [0, a, 0], [0, 0, c]] TiO2_basis = np.array([[0.0, 0.0, 0.0], [0.5, 0.5, 0.5], [u, u, 0.0], [-u, -u, 0.0], [0.5 + u, 0.5 - u, 0.5], [0.5 - u, 0.5 + u, 0.5]]) bulk_crystal = Atoms(symbols=['Ti', 'Ti', 'O', 'O', 'O', 'O'], scaled_positions=TiO2_basis, cell=rutile_cell, pbc=(1, 1, 1)) data_s = [] for symmetry in ['off', {}]: bulk_calc = GPAW(mode=PW(pwcutoff), kpts={'size': (k, k, k), 'gamma': True}, xc='PBE', occupations=FermiDirac(0.00001), parallel={'band': 1}, symmetry=symmetry, dtype=complex) bulk_crystal.set_calculator(bulk_calc) e0_bulk_pbe = bulk_crystal.get_potential_energy() bulk_calc.write('bulk.gpw', mode='all') X = Chi0('bulk.gpw') chi_t = X.calculate([1. / 4, 0, 0])[1:] data_s.append(list(chi_t)) msg = 'Difference in Chi when turning off symmetries!' while len(data_s): data1 = data_s.pop() for data2 in data_s: for dat1, dat2 in zip(data1, data2): if dat1 is not None: equal(np.abs(dat1 - dat2).max(), 0, 1e-5, msg=msg) gpaw-0.11.0.13004/gpaw/test/fsbt.py0000664000175000017500000000071412553643471016704 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from gpaw.atom.radialgd import fsbt N = 1024 L = 50.0 h = L / N alpha = 5.0 r = np.linspace(0, L, N, endpoint=False) G = np.linspace(0, np.pi / h, N // 2 + 1) n = np.exp(-alpha * r**2) for l in range(7): f = fsbt(l, n * r**l, r, G) f0 = (np.pi**0.5 / alpha**(l + 1.5) / 2**l * G**l / 4 * np.exp(-G**2 / (4 * alpha))) print(l, abs(f-f0).max()) assert abs(f-f0).max() < 1e-7 gpaw-0.11.0.13004/gpaw/test/hydrogen.py0000664000175000017500000000254112553643471017565 0ustar jensjjensj00000000000000from math import log from ase import Atoms from ase.io import read from ase.units import Bohr from gpaw import GPAW, FermiDirac from gpaw.test import equal a = 4.0 h = 0.2 hydrogen = Atoms('H', [(a / 2, a / 2, a / 2)], cell=(a, a, a)) hydrogen.calc = GPAW(h=h, nbands=1, convergence={'energy': 1e-7}, txt='h.txt') e1 = hydrogen.get_potential_energy() equal(e1, 0.526939, 0.001) dens = hydrogen.calc.density c = dens.gd.find_center(dens.nt_sG[0]) * Bohr equal(abs(c - a / 2).max(), 0, 1e-13) kT = 0.001 hydrogen.calc.set(occupations=FermiDirac(width=kT)) e2 = hydrogen.get_potential_energy() equal(e1, e2 + log(2) * kT, 3.0e-7) # Test ase.db a bit: from ase.db import connect # Note: This test will fail if run twice in same directory without # cleaning these files. for name in ['h.json', 'h.db']: con = connect(name) con.write(hydrogen) id = con.write(hydrogen, foo='bar', data={'abc': [1, 2, 3]}) assert id == 2 assert con.reserve(foo='bar') is None row = con.get(foo='bar') assert row.energy == e2 assert sum(row.data.abc) == 6 del con[1] assert con.reserve(x=42) == 3 # Test parsing of GPAW's text output: h = read('h.txt') error = abs(h.calc.get_eigenvalues() - hydrogen.calc.get_eigenvalues()).max() assert error < 1e-5, error gpaw-0.11.0.13004/gpaw/test/ds_beta.py0000664000175000017500000000336512553643471017354 0ustar jensjjensj00000000000000import os import sys import numpy as np from ase import Atom from ase.units import Ha from ase.parallel import parprint from gpaw import GPAW from gpaw.cluster import * from gpaw.pes.state import BoundState, H1s from gpaw.pes.ds_beta import CrossSectionBeta xc = 'PBE' ngauss=2 h=.3 box=3. gpwname='H1s.gpw' if 1: c = GPAW(xc='PBE', nbands=-1, h=h) s = Cluster([Atom('H')]) s.minimal_box(box, h=h) c.calculate(s) c.write(gpwname, 'all') else: c = GPAW(gpwname) s = c.get_atoms() c.converge_wave_functions() cm = s.get_center_of_mass() Ekin = 1. ekin = Ekin / Ha for form, title in [('L', 'length form'), ('V', 'velocity form')]: parprint('--', title) ds = [] for analytic in [True, False]: if analytic: initial = H1s(c.density.gd, cm) else: initial=BoundState(c, 0, 0) initial.set_energy(- Ha / 2.) csb = CrossSectionBeta(initial=initial, final=None, r0=cm, ngauss=ngauss, form=form) if analytic: ds.append(initial.get_ds(Ekin, form)) parprint('analytic 1s energy, beta, ds %5.3f' % (Ekin + Ha / 2.), end='') parprint('%8.4f %12.5f' %(2, ds[-1])) ds.append(csb.get_ds(Ekin)) parprint('numeric 1s energy, beta, ds %5.3f' % (Ekin + Ha / 2.), end='') parprint('%8.4f %12.5f' %(csb.get_beta(Ekin), ds[-1])) parprint('error analytic GS:', int(100 * abs(ds[1] / ds[0] - 1.) + .5), '%') assert(abs(ds[1] / ds[0] - 1.) < 0.31) parprint('error numeric GS:', int(100 * abs(ds[2] / ds[0] - 1.) + .5), '%') assert(abs(ds[2] / ds[0] - 1.) < 0.2) gpaw-0.11.0.13004/gpaw/test/dump_chi0.py0000664000175000017500000000064012553643471017614 0ustar jensjjensj00000000000000import numpy as np from gpaw.mpi import size, rank, world from gpaw.response.parallel import par_write, par_read Nw = 400 npw = 10 assert Nw % size == 0 Nw_local = Nw // size chi0_wGG = np.ones((Nw_local, npw, npw),dtype=complex) * rank filename = 'chi0' name = 'chi0_wGG' par_write(filename, name, world, chi0_wGG) chi0_wGG_new = par_read(filename, name) assert (np.abs(chi0_wGG - chi0_wGG_new) < 1e-10).all() gpaw-0.11.0.13004/gpaw/test/poisson.py0000664000175000017500000000234112553643471017436 0ustar jensjjensj00000000000000from __future__ import print_function from math import sqrt import numpy as np from gpaw.spline import Spline from gpaw.poisson import PoissonSolver, FFTPoissonSolver from gpaw.grid_descriptor import GridDescriptor from gpaw.lfc import LocalizedFunctionsCollection as LFC L = 2.87 / 0.529177 def f(n, p): N = 2 * n gd = GridDescriptor((N, N, N), (L, L, L)) a = gd.zeros() print(a.shape) #p = PoissonSolver(nn=1, relax=relax) p.set_grid_descriptor(gd) p.initialize() cut = N / 2.0 * 0.9 s = Spline(l=0, rmax=cut, f_g=np.array([1, 0.5, 0.0])) c = LFC(gd, [[s], [s]]) c.set_positions([(0, 0, 0), (0.5, 0.5, 0.5)]) c.add(a) I0 = gd.integrate(a) a -= gd.integrate(a) / L**3 I = gd.integrate(a) b = gd.zeros() p.solve(b, a, charge=0)#, eps=1e-20) return gd.collect(b, broadcast=1) b1 = f(8, PoissonSolver(nn=1, relax='J')) b2 = f(8, PoissonSolver(nn=1, relax='GS')) err1 = abs(b1[0,0,0]-b1[8,8,8]) err2 = abs(b2[0,0,0]-b2[8,8,8]) print(err1) print(err2) assert err1 < 6e-16 assert err2 < 3e-6 # XXX Shouldn't this be better? from gpaw.mpi import size if size == 1: b3 = f(8, FFTPoissonSolver()) err3 = abs(b3[0,0,0]-b3[8,8,8]) print(err3) assert err3 < 6e-16 gpaw-0.11.0.13004/gpaw/test/kssingles_Be.py0000664000175000017500000000357712553643471020370 0ustar jensjjensj00000000000000import os import numpy as np from ase import Atom, Atoms from ase.optimize import BFGS from ase.parallel import parprint from ase.units import Hartree import gpaw.mpi as mpi from gpaw import GPAW from gpaw.test import equal from gpaw.lrtddft.kssingle import KSSingles Be = Atoms('Be') Be.center(vacuum=6) if 1: # introduce a sligth non-orthgonality cell = Be.get_cell() cell[1] += 0.001 * cell[0] Be.set_cell(cell) txt = None #txt='-' eigensolver = None #eigensolver = 'rmm-diis' #modes = ['lcao', 'fd'] modes = ['fd'] for mode in modes: energy = {} osz = {} for pbc in [False, True]: Be.set_pbc(pbc) if pbc: name = 'periodic' calc = GPAW(h=0.25, nbands=4, kpts=(1,2,2), mode=mode, eigensolver=eigensolver, txt=txt) else: name = 'zero bc' calc = GPAW(h=0.25, nbands=4, mode=mode, eigensolver=eigensolver, txt=txt) Be.set_calculator(calc) Be.get_potential_energy() kss = KSSingles(calc) # all s->p transitions at the same energy [Ha] and # oscillator_strength for ks in kss: equal(ks.get_energy(), kss[0].get_energy(), 1.e-4) equal(ks.get_oscillator_strength()[0], kss[0].get_oscillator_strength()[0], 1.e-3) energy[name] = np.array( [ks.get_energy() * Hartree for ks in kss]).mean() osz[name] = np.array( [ks.get_oscillator_strength()[0] for ks in kss]).sum() parprint(kss) # I/O kss.write('kss.dat') mpi.world.barrier() kss = KSSingles('kss.dat') kss1 = KSSingles('kss.dat', jend=1) assert(len(kss1) == 1) # periodic and non-periodic should be roughly equal equal(energy['zero bc'], energy['periodic'], 1.e-2) equal(osz['zero bc'], osz['periodic'], 1.e-3) gpaw-0.11.0.13004/gpaw/test/fftw.py0000664000175000017500000000241612553643471016715 0ustar jensjjensj00000000000000from __future__ import print_function import time import numpy as np import gpaw.fftw as fftw def test(Plan, flags, input, output, sign): t0 = time.time() plan = Plan(input, output, sign, flags) t1 = time.time() t = 0.0 for i in range(100): input[:] = 1.3 t2 = time.time() plan.execute() t3 = time.time() t += t3 - t2 return t1 - t0, t / 100 if __name__ == '__main__': a1 = fftw.empty((32, 28, 128), complex) a2 = fftw.empty((32, 28, 128), complex) b = fftw.empty((32, 28, 65), complex) c1 = b.view(dtype=float)[:, :, :128] c2 = fftw.empty((32, 28, 64), complex).view(dtype=float) for input, output, sign in [ (a1, a1, -1), (a1, a2, -1), (b, c1, 1), (b, c2, 1), (c1, b, -1), (c2, b, -1)]: for Plan, flags in [(fftw.NumpyFFTPlan, 117), (fftw.FFTWPlan, fftw.ESTIMATE), (fftw.FFTWPlan, fftw.MEASURE), (fftw.FFTWPlan, fftw.PATIENT), (fftw.FFTWPlan, fftw.EXHAUSTIVE)]: tplan, tfft = test(Plan, flags, input, output, sign) print(('%-12s %3d %10.6f %10.6f' % (Plan.__name__, flags, tplan, tfft))) gpaw-0.11.0.13004/gpaw/test/lcao_largecellforce.py0000664000175000017500000000371512553643471021721 0ustar jensjjensj00000000000000from __future__ import print_function # This test calculates the force on the atoms in a hydrogen chain, comparing # the results to finite-difference values. # # The reference result is obtained from an FD calculation, which can be rerun # by setting the fd boolean below. # # The purpose is to test domain decomposition with large cells. The basis # functions of one atom are defined to not overlap the rightmost domain # for z-decompositions of two or more slices. This will change the set # of atomic indices stored in BasisFunctions objects and other things # # This test also ensures that lcao forces are tested with non-pbc. import numpy as np from numpy import array from ase import Atoms from ase.units import Bohr from gpaw import GPAW from gpaw.atom.basis import BasisMaker hbasis = BasisMaker('H').generate(1, 0, energysplit=1.8, tailnorm=0.03**.5) basis = {'H' : hbasis} atom = Atoms('H') atom.center(vacuum=.8) system = atom.repeat((1, 1, 4)) rc = hbasis.bf_j[0].rc system.center(vacuum=2.5) calc = GPAW(h=0.23, mode='lcao', basis=basis, convergence={'density':1e-4, 'energy': 1e-7}, ) system.set_calculator(calc) F_ac = system.get_forces() # Check that rightmost domain is in fact outside range of basis functions from gpaw.mpi import rank, size if rank == 0 and size > 1: assert len(calc.wfs.basis_functions.atom_indices) < len(system) fd = 0 # Values taken from FD calculation below # (Symmetry means only z-component may be nonzero) ref = array([[0.0, 0.0, 4.61734874], [0.0, 0.0, -2.74398046], [0.0, 0.0, 2.74398027], [0.0, 0.0, -4.61734856]]) if fd: from ase.calculators.test import numeric_forces ref = numeric_forces(system, axes=[2], d=0.002) print('Calced') print(F_ac) print('FD') print(ref) print(repr(ref)) err = np.abs(F_ac - ref).max() print('Ref') print(ref) print('Calculated') print(F_ac) print('Max error', err) assert err < 6e-4 gpaw-0.11.0.13004/gpaw/test/coreeig.py0000664000175000017500000000111712553643471017361 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW, restart from gpaw.test import equal from gpaw.utilities.kspot import CoreEigenvalues a = 7.0 calc = GPAW(h=0.1) system = Atoms('Ne', calculator=calc) system.center(vacuum=a / 2) e0 = system.get_potential_energy() niter0 = calc.get_number_of_iterations() calc.write('Ne.gpw') del calc, system atoms, calc = restart('Ne.gpw') calc.restore_state() e_j = CoreEigenvalues(calc).get_core_eigenvalues(0) assert abs(e_j[0] - (-30.344066)) * 27.21 < 0.1 # Error smaller than 0.1 eV energy_tolerance = 0.0004 equal(e0, -0.0107707223, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/dscf_lcao.py0000664000175000017500000000211012553643471017653 0ustar jensjjensj00000000000000from ase.structure import molecule from gpaw import GPAW from gpaw import dscf from gpaw.test import equal # Ground state calculation calc = GPAW(mode='lcao', basis='dzp', nbands=8, h=0.2, xc='PBE', spinpol=True, convergence={'energy': 100, 'density': 1e-3, 'bands': -1}) CO = molecule('CO') CO.center(vacuum=3) CO.set_calculator(calc) E_gs = CO.get_potential_energy() # Excited state calculation calc_es = GPAW(mode='lcao', basis='dzp', nbands=8, h=0.2, xc='PBE', spinpol=True, convergence={'energy': 100, 'density': 1e-3, 'bands': -1}) CO.set_calculator(calc_es) lumo = dscf.MolecularOrbital(calc, weights={0: [0, 0, 0, 1], 1: [0, 0, 0, -1]}) dscf.dscf_calculation(calc_es, [[1.0, lumo, 1]], CO) E_es = CO.get_potential_energy() dE = E_es - E_gs print(dE) equal(dE, 5.7595110076, 0.011) gpaw-0.11.0.13004/gpaw/test/lb94.py0000664000175000017500000000633312553643471016523 0ustar jensjjensj00000000000000from __future__ import print_function import os from ase import * from ase.parallel import rank, barrier from gpaw import GPAW from gpaw import setup_paths from gpaw.atom.all_electron import AllElectron from gpaw.atom.generator import Generator from gpaw.atom.configurations import parameters ref1 = 'R. v. Leeuwen PhysRevA 49, 2421 (1994)' ref2 = 'Gritsenko IntJQuanChem 76, 407 (2000)' # HOMO energy in mHa for closed shell atoms e_HOMO_cs = { 'He': 851, 'Be': 321, 'Ne': 788, 'Ar': 577, 'Kr': 529, 'Xe': 474, 'Mg' : 281 + 8 } #e_HOMO_cs = { 'Ne': 788 } txt=None print('--- Comparing LB94 with', ref1) print('and', ref2) print('**** all electron calculations') print('atom [refs] -e_homo diff all in mHa') if rank == 0: for atom in e_HOMO_cs.keys(): ae = AllElectron(atom, 'LB94', txt=txt) ae.run() e_homo = int( ae.e_j[-1] * 10000 + .5 ) / 10. diff = e_HOMO_cs[atom] + e_homo print('%2s %8g %6.1f %4.1g' % (atom, e_HOMO_cs[atom], -e_homo, diff)) assert abs(diff) < 6 barrier() setup_paths.insert(0, '.') setups = {} print('**** 3D calculations') print('atom [refs] -e_homo diff all in mHa') for atom in e_HOMO_cs.keys(): e_ref = e_HOMO_cs[atom] # generate setup for the atom if rank == 0 and atom not in setups: g = Generator(atom, 'LB94', nofiles=True, txt=txt) g.run(**parameters[atom]) setups[atom] = 1 barrier() SS = Atoms([Atom(atom)], cell=(7, 7, 7), pbc=False) SS.center() c = GPAW(h=.3, xc='LB94', nbands=-2, txt=txt) if atom in ['Mg']: c.set(eigensolver='cg') c.calculate(SS) # find HOMO energy eps_n = c.get_eigenvalues(kpt=0, spin=0) / 27.211 f_n = c.get_occupation_numbers(kpt=0, spin=0) for e, f in zip(eps_n, f_n): if f < 0.99: break e_homo = e e_homo = int( e_homo * 10000 + .5 ) / 10. diff = e_ref + e_homo print('%2s %8g %6.1f %4.1f' % (atom, e_ref, -e_homo, diff)) assert abs(diff) < 7 # HOMO energy in mHa and magn. mom. for open shell atoms e_HOMO_os = { 'He': [851, 0], # added for cross check 'H': [440, 1], 'N': [534-23, 3], 'Na':[189+17, 1], 'P': [385-16, 3] } #e_HOMO_os = { 'Ne': [788, 0], # added for cross check # 'H': [440, 1] } for atom in e_HOMO_os.keys(): e_ref = e_HOMO_os[atom][0] magmom = e_HOMO_os[atom][1] # generate setup for the atom if rank == 0 and atom not in setups: g = Generator(atom, 'LB94', nofiles=True, txt=txt) g.run(**parameters[atom]) setups[atom] = 1 barrier() SS = Atoms([Atom(atom, magmom=magmom)], cell=(7, 7, 7), pbc=False) SS.center() # fine grid needed for convergence! c = GPAW(h=.2, xc='LB94', nbands=-2, spinpol=True, hund=True, fixmom=True, txt=txt) c.calculate(SS) # find HOMO energy eps_n = c.get_eigenvalues(kpt=0, spin=0) / 27.211 f_n = c.get_occupation_numbers(kpt=0, spin=0) for e, f in zip(eps_n, f_n): if f < 0.99: break e_homo = e e_homo = int( e_homo * 10000 + .5 ) / 10. diff = e_ref + e_homo print('%2s %8g %6.1f %4.1f' % (atom, e_ref, -e_homo, diff)) assert abs(diff) < 15 gpaw-0.11.0.13004/gpaw/test/coulomb.py0000664000175000017500000000400012553643472017377 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from math import pi from gpaw.coulomb import Coulomb from gpaw.grid_descriptor import GridDescriptor from gpaw.mpi import world, parallel from gpaw.utilities.gauss import coordinates from gpaw.test import equal import time def test_coulomb(N=2**6, a=20): Nc = (N, N, N) # Number of grid point gd = GridDescriptor(Nc, (a, a, a), True) # grid-descriptor object xyz, r2 = coordinates(gd) # matrix with the square of the radial coordinate r = np.sqrt(r2) # matrix with the values of the radial coordinate nH = np.exp(-2 * r) / pi # density of the hydrogen atom C = Coulomb(gd) # coulomb calculator if parallel: C.load('real') t0 = time.time() print('Processor %s of %s: %s Ha in %s sec' % ( gd.comm.rank + 1, gd.comm.size, -0.5 * C.coulomb(nH, method='real'), time.time() - t0)) return else: C.load('recip_ewald') C.load('recip_gauss') C.load('real') test = {} t0 = time.time() test['dual density'] = (-0.5 * C.coulomb(nH, nH.copy()), time.time() - t0) for method in ('real', 'recip_gauss', 'recip_ewald'): t0 = time.time() test[method] = (-0.5 * C.coulomb(nH, method=method), time.time() - t0) return test analytic = -5 / 16.0 res = test_coulomb(N=48, a=15) if not parallel: print('Units: Bohr and Hartree') print('%12s %8s %8s' % ('Method', 'Energy', 'Time')) print('%12s %2.6f %6s' % ('analytic', analytic, '--')) for method, et in res.items(): print('%12s %2.6f %1.7f' % ((method,) + et)) equal(res['real'][0], analytic, 6e-3) equal(res['recip_gauss'][0], analytic, 6e-3) equal(res['recip_ewald'][0], analytic, 2e-2) equal(res['dual density'][0], res['recip_gauss'][0], 1e-9) # mpirun -np 2 python coulomb.py --gpaw-parallel --gpaw-debug gpaw-0.11.0.13004/gpaw/test/lcao_density.py0000664000175000017500000000334412553643471020425 0ustar jensjjensj00000000000000"""Test LCAO density calculation and conversion to grid. Test that the density generated by the following three procedures is the same: * basis_functions.construct_density as used in a normal calculation * axpy used on the psit_nG as constructed by lcao_to_grid * axpy used on the Phit_MG[i] * Phit_MG[j] * rho[j, i], where Phit_MG are the actual basis functions on the grid, constructed using lcao_to_grid TODO: non-gamma-point test """ from __future__ import print_function import numpy as np from ase.structure import molecule from gpaw import GPAW, ConvergenceError from gpaw.utilities.blas import axpy system = molecule('H2O') system.center(vacuum=2.5) calc = GPAW(mode='lcao', #basis='dzp', maxiter=1) system.set_calculator(calc) try: system.get_potential_energy() except ConvergenceError: pass wfs = calc.wfs kpt = wfs.kpt_u[0] nt_G = calc.density.gd.zeros() bfs = wfs.basis_functions nao = wfs.setups.nao f_n = kpt.f_n rho_MM = np.zeros((nao, nao)) wfs.calculate_density_matrix(kpt.f_n, kpt.C_nM, rho_MM) bfs.construct_density(rho_MM, nt_G, -1) nbands = wfs.bd.nbands psit_nG = wfs.gd.zeros(nbands) bfs.lcao_to_grid(kpt.C_nM, psit_nG, -1) nt2_G = calc.density.gd.zeros() for f, psit_G in zip(f_n, psit_nG): axpy(f, psit_G**2, nt2_G) identity_MM = np.identity(nao) Phit_MG = calc.wfs.gd.zeros(nao) bfs.lcao_to_grid(identity_MM, Phit_MG, -1) nt3_G = calc.density.gd.zeros() for M1, Phit1_G in enumerate(Phit_MG): for M2, Phit2_G in enumerate(Phit_MG): nt3_G += rho_MM[M1, M2] * Phit1_G * Phit2_G err1_G = nt2_G - nt_G err2_G = nt3_G - nt_G maxerr1 = np.abs(err1_G).max() maxerr2 = np.abs(err2_G).max() print('err1', maxerr1) print('err2', maxerr2) assert max(maxerr1, maxerr2) < 1e-15 gpaw-0.11.0.13004/gpaw/test/pseudopotential/0000775000175000017500000000000012553644063020607 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/pseudopotential/upf_h2o.py0000664000175000017500000000407512553643472022534 0ustar jensjjensj00000000000000from gpaw.upf import UPFSetupData, upfplot from gpaw.pseudopotential import pseudoplot, PseudoPotential from gpaw.eigensolvers.davidson import Davidson def get(fname): s = UPFSetupData(fname) return s s = get('O.pz-hgh.UPF') #upfplot(s.data, show=True) bfs = s.create_basis_functions() pp = PseudoPotential(s, bfs) import numpy as np x = np.linspace(0.0, 5.0, 1000) dr = x[1] - x[0] psi = pp.phit_j[0].map(x) p = pp.pt_j[0].map(x) from gpaw.atom.atompaw import AtomPAW if 0: f = 1.0 #1e-12 c = AtomPAW('H', [[[2.0], [4.0]]], #charge=1 - f, h=0.04, #setups='paw', #setups='hgh', setups={'H': s} ) import pylab as pl pl.plot(c.wfs.gd.r_g, c.hamiltonian.vt_sg[0]) pl.show() raise SystemExit #print 'test v201 Au.pz-d-hgh.UPF' #s = UPFSetupData('Au.pz-d-hgh.UPF') #print 'v201 ok' #print 'test horrible version O.pz-mt.UPF' #s = UPFSetupData('O.pz-mt.UPF') #print 'horrible version ok, relatively speaking' if 1: from ase import Atoms from gpaw import GPAW, PoissonSolver, FermiDirac, Mixer, MixerSum from gpaw.utilities import h2gpts from ase.structure import molecule #s = UPFSetupData('/home/askhl/parse-upf/h_lda_v1.uspp.F.UPF') upfsetups = {'H': UPFSetupData('H.pz-hgh.UPF'), 'O': UPFSetupData('O.pz-hgh.UPF')} system = molecule('H2O') system.center(vacuum=3.5) calc = GPAW(txt='-', nbands=6, setups=upfsetups, #setups='paw', #hund=True, #mixer=MixerSum(0.1, 5, 20.0), #eigensolver='cg', #occupations=FermiDirac(0.1), #charge=1-1e-12, eigensolver=Davidson(2), #eigensolver='rmm-diis', gpts=h2gpts(0.12, system.get_cell(), idiv=8), poissonsolver=PoissonSolver(relax='GS', eps=1e-7), xc='oldLDA', #nbands=4 ) system.set_calculator(calc) system.get_potential_energy() gpaw-0.11.0.13004/gpaw/test/pseudopotential/H_sg15.py0000664000175000017500000017660512553643472022231 0ustar jensjjensj00000000000000# This file contains data for the test sg15_hydrogen.py. pp_text = """ This pseudopotential file has been produced using the code ONCVPSP (Optimized Norm-Conservinng Vanderbilt PSeudopotential) scalar-relativistic version 2.1.1, 03/26/2014 by D. R. Hamann The code is available through a link at URL www.mat-simresearch.com. Documentation with the package provides a full discription of the input data below. While it is not required under the terms of the GNU GPL, it is suggested that you cite D. R. Hamann, Phys. Rev. B 88, 085117 (2013) in any publication using these pseudopotentials. Copyright 2015 The Regents of the University of California This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. This pseudopotential is part of the Schlipf-Gygi norm-conserving pseudopotential library. Its construction parameters were tuned to reproduce materials of a training set with very high accuracy and should be suitable as a general purpose pseudopotential to treat a variety of different compounds. For details of the construction and testing of the pseudopotential please refer to: [insert reference to paper here] We kindly ask that you include this reference in all publications associated to this pseudopotential. # ATOM AND REFERENCE CONFIGURATION # atsym z nc nv iexc psfile H 1.00 0 1 4 upf # # n l f energy (Ha) 1 0 1.00 # # PSEUDOPOTENTIAL AND OPTIMIZATION # lmax 0 # # l, rc, ep, ncon, nbas, qcut 0 1.13748 -0.23860 5 8 9.72141 # # LOCAL POTENTIAL # lloc, lpopt, rc(5), dvloc0 4 5 0.49352 0.00000 # # VANDERBILT-KLEINMAN-BYLANDER PROJECTORs # l, nproj, debl 0 2 1.27464 # # MODEL CORE CHARGE # icmod, fcfact 0 0.00000 # # LOG DERIVATIVE ANALYSIS # epsh1, epsh2, depsh -5.00 3.00 0.02 # # OUTPUT GRID # rlmax, drl 6.00 0.01 # # TEST CONFIGURATIONS # ncnf 0 # nvcnf # n l f 0.0000 0.0100 0.0200 0.0300 0.0400 0.0500 0.0600 0.0700 0.0800 0.0900 0.1000 0.1100 0.1200 0.1300 0.1400 0.1500 0.1600 0.1700 0.1800 0.1900 0.2000 0.2100 0.2200 0.2300 0.2400 0.2500 0.2600 0.2700 0.2800 0.2900 0.3000 0.3100 0.3200 0.3300 0.3400 0.3500 0.3600 0.3700 0.3800 0.3900 0.4000 0.4100 0.4200 0.4300 0.4400 0.4500 0.4600 0.4700 0.4800 0.4900 0.5000 0.5100 0.5200 0.5300 0.5400 0.5500 0.5600 0.5700 0.5800 0.5900 0.6000 0.6100 0.6200 0.6300 0.6400 0.6500 0.6600 0.6700 0.6800 0.6900 0.7000 0.7100 0.7200 0.7300 0.7400 0.7500 0.7600 0.7700 0.7800 0.7900 0.8000 0.8100 0.8200 0.8300 0.8400 0.8500 0.8600 0.8700 0.8800 0.8900 0.9000 0.9100 0.9200 0.9300 0.9400 0.9500 0.9600 0.9700 0.9800 0.9900 1.0000 1.0100 1.0200 1.0300 1.0400 1.0500 1.0600 1.0700 1.0800 1.0900 1.1000 1.1100 1.1200 1.1300 1.1400 1.1500 1.1600 1.1700 1.1800 1.1900 1.2000 1.2100 1.2200 1.2300 1.2400 1.2500 1.2600 1.2700 1.2800 1.2900 1.3000 1.3100 1.3200 1.3300 1.3400 1.3500 1.3600 1.3700 1.3800 1.3900 1.4000 1.4100 1.4200 1.4300 1.4400 1.4500 1.4600 1.4700 1.4800 1.4900 1.5000 1.5100 1.5200 1.5300 1.5400 1.5500 1.5600 1.5700 1.5800 1.5900 1.6000 1.6100 1.6200 1.6300 1.6400 1.6500 1.6600 1.6700 1.6800 1.6900 1.7000 1.7100 1.7200 1.7300 1.7400 1.7500 1.7600 1.7700 1.7800 1.7900 1.8000 1.8100 1.8200 1.8300 1.8400 1.8500 1.8600 1.8700 1.8800 1.8900 1.9000 1.9100 1.9200 1.9300 1.9400 1.9500 1.9600 1.9700 1.9800 1.9900 2.0000 2.0100 2.0200 2.0300 2.0400 2.0500 2.0600 2.0700 2.0800 2.0900 2.1000 2.1100 2.1200 2.1300 2.1400 2.1500 2.1600 2.1700 2.1800 2.1900 2.2000 2.2100 2.2200 2.2300 2.2400 2.2500 2.2600 2.2700 2.2800 2.2900 2.3000 2.3100 2.3200 2.3300 2.3400 2.3500 2.3600 2.3700 2.3800 2.3900 2.4000 2.4100 2.4200 2.4300 2.4400 2.4500 2.4600 2.4700 2.4800 2.4900 2.5000 2.5100 2.5200 2.5300 2.5400 2.5500 2.5600 2.5700 2.5800 2.5900 2.6000 2.6100 2.6200 2.6300 2.6400 2.6500 2.6600 2.6700 2.6800 2.6900 2.7000 2.7100 2.7200 2.7300 2.7400 2.7500 2.7600 2.7700 2.7800 2.7900 2.8000 2.8100 2.8200 2.8300 2.8400 2.8500 2.8600 2.8700 2.8800 2.8900 2.9000 2.9100 2.9200 2.9300 2.9400 2.9500 2.9600 2.9700 2.9800 2.9900 3.0000 3.0100 3.0200 3.0300 3.0400 3.0500 3.0600 3.0700 3.0800 3.0900 3.1000 3.1100 3.1200 3.1300 3.1400 3.1500 3.1600 3.1700 3.1800 3.1900 3.2000 3.2100 3.2200 3.2300 3.2400 3.2500 3.2600 3.2700 3.2800 3.2900 3.3000 3.3100 3.3200 3.3300 3.3400 3.3500 3.3600 3.3700 3.3800 3.3900 3.4000 3.4100 3.4200 3.4300 3.4400 3.4500 3.4600 3.4700 3.4800 3.4900 3.5000 3.5100 3.5200 3.5300 3.5400 3.5500 3.5600 3.5700 3.5800 3.5900 3.6000 3.6100 3.6200 3.6300 3.6400 3.6500 3.6600 3.6700 3.6800 3.6900 3.7000 3.7100 3.7200 3.7300 3.7400 3.7500 3.7600 3.7700 3.7800 3.7900 3.8000 3.8100 3.8200 3.8300 3.8400 3.8500 3.8600 3.8700 3.8800 3.8900 3.9000 3.9100 3.9200 3.9300 3.9400 3.9500 3.9600 3.9700 3.9800 3.9900 4.0000 4.0100 4.0200 4.0300 4.0400 4.0500 4.0600 4.0700 4.0800 4.0900 4.1000 4.1100 4.1200 4.1300 4.1400 4.1500 4.1600 4.1700 4.1800 4.1900 4.2000 4.2100 4.2200 4.2300 4.2400 4.2500 4.2600 4.2700 4.2800 4.2900 4.3000 4.3100 4.3200 4.3300 4.3400 4.3500 4.3600 4.3700 4.3800 4.3900 4.4000 4.4100 4.4200 4.4300 4.4400 4.4500 4.4600 4.4700 4.4800 4.4900 4.5000 4.5100 4.5200 4.5300 4.5400 4.5500 4.5600 4.5700 4.5800 4.5900 4.6000 4.6100 4.6200 4.6300 4.6400 4.6500 4.6600 4.6700 4.6800 4.6900 4.7000 4.7100 4.7200 4.7300 4.7400 4.7500 4.7600 4.7700 4.7800 4.7900 4.8000 4.8100 4.8200 4.8300 4.8400 4.8500 4.8600 4.8700 4.8800 4.8900 4.9000 4.9100 4.9200 4.9300 4.9400 4.9500 4.9600 4.9700 4.9800 4.9900 5.0000 5.0100 5.0200 5.0300 5.0400 5.0500 5.0600 5.0700 5.0800 5.0900 5.1000 5.1100 5.1200 5.1300 5.1400 5.1500 5.1600 5.1700 5.1800 5.1900 5.2000 5.2100 5.2200 5.2300 5.2400 5.2500 5.2600 5.2700 5.2800 5.2900 5.3000 5.3100 5.3200 5.3300 5.3400 5.3500 5.3600 5.3700 5.3800 5.3900 5.4000 5.4100 5.4200 5.4300 5.4400 5.4500 5.4600 5.4700 5.4800 5.4900 5.5000 5.5100 5.5200 5.5300 5.5400 5.5500 5.5600 5.5700 5.5800 5.5900 5.6000 5.6100 5.6200 5.6300 5.6400 5.6500 5.6600 5.6700 5.6800 5.6900 5.7000 5.7100 5.7200 5.7300 5.7400 5.7500 5.7600 5.7700 5.7800 5.7900 5.8000 5.8100 5.8200 5.8300 5.8400 5.8500 5.8600 5.8700 5.8800 5.8900 5.9000 5.9100 5.9200 5.9300 5.9400 5.9500 5.9600 5.9700 5.9800 5.9900 6.0000 6.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 0.0100 -9.0610437558E+00 -9.0568179440E+00 -9.0440368423E+00 -9.0228074240E+00 -8.9932366622E+00 -8.9554713856E+00 -8.9096955089E+00 -8.8561267684E+00 -8.7950131219E+00 -8.7266289853E+00 -8.6512714714E+00 -8.5692567717E+00 -8.4809167973E+00 -8.3865961577E+00 -8.2866495257E+00 -8.1814394040E+00 -8.0713342805E+00 -7.9567071423E+00 -7.8379342970E+00 -7.7153944473E+00 -7.5894679553E+00 -7.4605362378E+00 -7.3289812341E+00 -7.1951848958E+00 -7.0595286560E+00 -6.9223928378E+00 -6.7841559816E+00 -6.6451940571E+00 -6.5058795596E+00 -6.3665804704E+00 -6.2276590796E+00 -6.0894706704E+00 -5.9523620796E+00 -5.8166700798E+00 -5.6827196991E+00 -5.5508223633E+00 -5.4212739530E+00 -5.2943527007E+00 -5.1703170897E+00 -5.0494035400E+00 -4.9318240186E+00 -4.8177636487E+00 -4.7073781566E+00 -4.6007912591E+00 -4.4980919767E+00 -4.3993318735E+00 -4.3045222275E+00 -4.2136312137E+00 -4.1265808607E+00 -4.0432438377E+00 -3.9634411592E+00 -3.8869595066E+00 -3.8135916025E+00 -3.7431452942E+00 -3.6754419749E+00 -3.6103158908E+00 -3.5476125181E+00 -3.4871882092E+00 -3.4289088467E+00 -3.3726496295E+00 -3.3182938607E+00 -3.2657329154E+00 -3.2148652694E+00 -3.1655961918E+00 -3.1178374334E+00 -3.0715065944E+00 -3.0265268914E+00 -2.9828269546E+00 -2.9403403441E+00 -2.8990053187E+00 -2.8587646530E+00 -2.8195654255E+00 -2.7813586956E+00 -2.7440993328E+00 -2.7077458096E+00 -2.6722599695E+00 -2.6376068987E+00 -2.6037546665E+00 -2.5706741108E+00 -2.5383386428E+00 -2.5067240362E+00 -2.4758082142E+00 -2.4455710353E+00 -2.4159940785E+00 -2.3870604303E+00 -2.3587544755E+00 -2.3310616932E+00 -2.3039684604E+00 -2.2774618664E+00 -2.2515295388E+00 -2.2261594843E+00 -2.2013399461E+00 -2.1770592791E+00 -2.1533058441E+00 -2.1300679226E+00 -2.1073336580E+00 -2.0850909954E+00 -2.0633276674E+00 -2.0420311892E+00 -2.0211888715E+00 -2.0007878496E+00 -1.9808151272E+00 -1.9612576275E+00 -1.9421022557E+00 -1.9233359852E+00 -1.9049459279E+00 -1.8869194114E+00 -1.8692440280E+00 -1.8519077546E+00 -1.8348990301E+00 -1.8182067760E+00 -1.8018204402E+00 -1.7857300225E+00 -1.7699262307E+00 -1.7544003587E+00 -1.7391444068E+00 -1.7241513910E+00 -1.7094149041E+00 -1.6949283914E+00 -1.6806851418E+00 -1.6666793118E+00 -1.6529050288E+00 -1.6393565372E+00 -1.6260283354E+00 -1.6129151224E+00 -1.6000117236E+00 -1.5873131231E+00 -1.5748145186E+00 -1.5625112075E+00 -1.5503986290E+00 -1.5384724172E+00 -1.5267282808E+00 -1.5151620774E+00 -1.5037698221E+00 -1.4925475838E+00 -1.4814916063E+00 -1.4705982343E+00 -1.4598638619E+00 -1.4492850817E+00 -1.4388585096E+00 -1.4285808834E+00 -1.4184490612E+00 -1.4084599113E+00 -1.3986104920E+00 -1.3888978631E+00 -1.3793192008E+00 -1.3698717674E+00 -1.3605528496E+00 -1.3513598874E+00 -1.3422902990E+00 -1.3333416549E+00 -1.3245115294E+00 -1.3157975913E+00 -1.3071975681E+00 -1.2987092220E+00 -1.2903304217E+00 -1.2820590200E+00 -1.2738930123E+00 -1.2658303454E+00 -1.2578691201E+00 -1.2500073905E+00 -1.2422433402E+00 -1.2345751282E+00 -1.2270010179E+00 -1.2195192646E+00 -1.2121282090E+00 -1.2048261947E+00 -1.1976116375E+00 -1.1904829614E+00 -1.1834386556E+00 -1.1764772175E+00 -1.1695972076E+00 -1.1627971899E+00 -1.1560757951E+00 -1.1494316470E+00 -1.1428634453E+00 -1.1363698679E+00 -1.1299496816E+00 -1.1236016133E+00 -1.1173244954E+00 -1.1111170992E+00 -1.1049783153E+00 -1.0989069715E+00 -1.0929019971E+00 -1.0869622832E+00 -1.0810867896E+00 -1.0752744716E+00 -1.0695243151E+00 -1.0638353388E+00 -1.0582065507E+00 -1.0526370315E+00 -1.0471258093E+00 -1.0416720144E+00 -1.0362747227E+00 -1.0309330806E+00 -1.0256462248E+00 -1.0204133106E+00 -1.0152335359E+00 -1.0101060634E+00 -1.0050301401E+00 -1.0000049637E+00 -9.9502979509E-01 -9.9010388850E-01 -9.8522650356E-01 -9.8039695184E-01 -9.7561449875E-01 -9.7087848953E-01 -9.6618823633E-01 -9.6154307709E-01 -9.5694238357E-01 -9.5238548542E-01 -9.4787179443E-01 -9.4340068216E-01 -9.3897154786E-01 -9.3458382085E-01 -9.3023689119E-01 -9.2593022219E-01 -9.2166324612E-01 -9.1743540867E-01 -9.1324619440E-01 -9.0909505086E-01 -9.0498147929E-01 -9.0090497409E-01 -8.9686501466E-01 -8.9286113809E-01 -8.8889284780E-01 -8.8495967058E-01 -8.8106115837E-01 -8.7719683072E-01 -8.7336625731E-01 -8.6956900186E-01 -8.6580460671E-01 -8.6207267364E-01 -8.5837277569E-01 -8.5470449112E-01 -8.5106743638E-01 -8.4746119942E-01 -8.4388539099E-01 -8.4033964140E-01 -8.3682355391E-01 -8.3333676803E-01 -8.2987892766E-01 -8.2644965155E-01 -8.2304860442E-01 -8.1967544372E-01 -8.1632980376E-01 -8.1301137110E-01 -8.0971981657E-01 -8.0645479078E-01 -8.0321599828E-01 -8.0000312317E-01 -7.9681583368E-01 -7.9365384812E-01 -7.9051686526E-01 -7.8740456836E-01 -7.8431668932E-01 -7.8125294167E-01 -7.7821302127E-01 -7.7519667347E-01 -7.7220362543E-01 -7.6923358691E-01 -7.6628631304E-01 -7.6336154485E-01 -7.6045900684E-01 -7.5757846086E-01 -7.5471966218E-01 -7.5188235009E-01 -7.4906629106E-01 -7.4627125457E-01 -7.4349699489E-01 -7.4074328111E-01 -7.3800989688E-01 -7.3529661160E-01 -7.3260319525E-01 -7.2992944541E-01 -7.2727514676E-01 -7.2464006883E-01 -7.2202402266E-01 -7.1942680330E-01 -7.1684819373E-01 -7.1428800302E-01 -7.1174604062E-01 -7.0922210469E-01 -7.0671599945E-01 -7.0422754882E-01 -7.0175656648E-01 -6.9930285090E-01 -6.9686623967E-01 -6.9444655518E-01 -6.9204361057E-01 -6.8965723548E-01 -6.8728726731E-01 -6.8493353479E-01 -6.8259585830E-01 -6.8027408946E-01 -6.7796806685E-01 -6.7567761966E-01 -6.7340259451E-01 -6.7114284334E-01 -6.6889821110E-01 -6.6666853234E-01 -6.6445367341E-01 -6.6225348756E-01 -6.6006782094E-01 -6.5789652969E-01 -6.5573948134E-01 -6.5359653600E-01 -6.5146754198E-01 -6.4935237457E-01 -6.4725090244E-01 -6.4516298961E-01 -6.4308849538E-01 -6.4102730352E-01 -6.3897928686E-01 -6.3694431188E-01 -6.3492225321E-01 -6.3291299679E-01 -6.3091642140E-01 -6.2893239660E-01 -6.2696081023E-01 -6.2500155065E-01 -6.2305450228E-01 -6.2111953833E-01 -6.1919655775E-01 -6.1728545168E-01 -6.1538610939E-01 -6.1349840980E-01 -6.1162225937E-01 -6.0975755301E-01 -6.0790418385E-01 -6.0606203900E-01 -6.0423102850E-01 -6.0241105218E-01 -6.0060200743E-01 -5.9880378789E-01 -5.9701630748E-01 -5.9523947068E-01 -5.9347317955E-01 -5.9171733268E-01 -5.8997184815E-01 -5.8823663490E-01 -5.8651159997E-01 -5.8479664543E-01 -5.8309169382E-01 -5.8139665833E-01 -5.7971145131E-01 -5.7803597694E-01 -5.7637016247E-01 -5.7471392514E-01 -5.7306718215E-01 -5.7142984084E-01 -5.6980183110E-01 -5.6818307475E-01 -5.6657349289E-01 -5.6497299873E-01 -5.6338152110E-01 -5.6179898754E-01 -5.6022532279E-01 -5.5866044633E-01 -5.5710428471E-01 -5.5555677140E-01 -5.5401783464E-01 -5.5248740049E-01 -5.5096539222E-01 -5.4945174929E-01 -5.4794640331E-01 -5.4644928588E-01 -5.4496032010E-01 -5.4347944752E-01 -5.4200660421E-01 -5.4054172497E-01 -5.3908473990E-01 -5.3763558480E-01 -5.3619420258E-01 -5.3476053107E-01 -5.3333450778E-01 -5.3191606202E-01 -5.3050514339E-01 -5.2910169262E-01 -5.2770565043E-01 -5.2631695259E-01 -5.2493554186E-01 -5.2356136607E-01 -5.2219436872E-01 -5.2083449329E-01 -5.1948167463E-01 -5.1813586721E-01 -5.1679701734E-01 -5.1546507114E-01 -5.1413997141E-01 -5.1282166293E-01 -5.1151009987E-01 -5.1020523087E-01 -5.0890700456E-01 -5.0761536348E-01 -5.0633026144E-01 -5.0505165203E-01 -5.0377948626E-01 -5.0251371517E-01 -5.0125428164E-01 -5.0000114694E-01 -4.9875426449E-01 -4.9751358757E-01 -4.9627906774E-01 -4.9505065408E-01 -4.9382830847E-01 -4.9261198641E-01 -4.9140164337E-01 -4.9019723176E-01 -4.8899870589E-01 -4.8780602831E-01 -4.8661915658E-01 -4.8543804824E-01 -4.8426265702E-01 -4.8309294118E-01 -4.8192886432E-01 -4.8077038597E-01 -4.7961746566E-01 -4.7847005879E-01 -4.7732812642E-01 -4.7619163356E-01 -4.7506054163E-01 -4.7393481203E-01 -4.7281440223E-01 -4.7169927496E-01 -4.7058939701E-01 -4.6948473158E-01 -4.6838524190E-01 -4.6729088781E-01 -4.6620163267E-01 -4.6511744539E-01 -4.6403829091E-01 -4.6296413415E-01 -4.6189493768E-01 -4.6083066451E-01 -4.5977128600E-01 -4.5871676870E-01 -4.5766707919E-01 -4.5662218308E-01 -4.5558204211E-01 -4.5454663035E-01 -4.5351591594E-01 -4.5248986699E-01 -4.5146845163E-01 -4.5045163204E-01 -4.4943938274E-01 -4.4843167416E-01 -4.4742847591E-01 -4.4642975759E-01 -4.4543548505E-01 -4.4444562951E-01 -4.4346016491E-01 -4.4247906228E-01 -4.4150229265E-01 -4.4052982584E-01 -4.3956162903E-01 -4.3859767986E-01 -4.3763795070E-01 -4.3668241393E-01 -4.3573104192E-01 -4.3478380238E-01 -4.3384067158E-01 -4.3290162488E-01 -4.3196663593E-01 -4.3103567840E-01 -4.3010872454E-01 -4.2918574490E-01 -4.2826671914E-01 -4.2735162215E-01 -4.2644042882E-01 -4.2553311405E-01 -4.2462964878E-01 -4.2373001042E-01 -4.2283417718E-01 -4.2194212512E-01 -4.2105383031E-01 -4.2016926876E-01 -4.1928841078E-01 -4.1841123932E-01 -4.1753773154E-01 -4.1666786462E-01 -4.1580161574E-01 -4.1493896037E-01 -4.1407987359E-01 -4.1322433773E-01 -4.1237233102E-01 -4.1152383170E-01 -4.1067881801E-01 -4.0983726529E-01 -4.0899915239E-01 -4.0816446135E-01 -4.0733317141E-01 -4.0650526184E-01 -4.0568071187E-01 -4.0485949712E-01 -4.0404159922E-01 -4.0322700028E-01 -4.0241568050E-01 -4.0160762012E-01 -4.0080279935E-01 -4.0000119443E-01 -3.9920278882E-01 -3.9840756506E-01 -3.9761550429E-01 -3.9682658765E-01 -3.9604079630E-01 -3.9525810742E-01 -3.9447850542E-01 -3.9370197363E-01 -3.9292849408E-01 -3.9215804879E-01 -3.9139061977E-01 -3.9062618552E-01 -3.8986473052E-01 -3.8910623925E-01 -3.8835069457E-01 -3.8759807933E-01 -3.8684837639E-01 -3.8610156584E-01 -3.8535763147E-01 -3.8461655919E-01 -3.8387833266E-01 -3.8314293554E-01 -3.8241035148E-01 -3.8168056246E-01 -3.8095355083E-01 -3.8022930425E-01 -3.7950780711E-01 -3.7878904385E-01 -3.7807299889E-01 -3.7735965635E-01 -3.7664899651E-01 -3.7594100897E-01 -3.7523567887E-01 -3.7453299135E-01 -3.7383293156E-01 -3.7313548465E-01 -3.7244063248E-01 -3.7174836252E-01 -3.7105866202E-01 -3.7037151682E-01 -3.6968691275E-01 -3.6900483566E-01 -3.6832527016E-01 -3.6764820011E-01 -3.6697361536E-01 -3.6630150240E-01 -3.6563184773E-01 -3.6496463784E-01 -3.6429985924E-01 -3.6363749507E-01 -3.6297753451E-01 -3.6231996581E-01 -3.6166477608E-01 -3.6101195247E-01 -3.6036148208E-01 -3.5971335135E-01 -3.5906754455E-01 -3.5842405304E-01 -3.5778286454E-01 -3.5714396678E-01 -3.5650734748E-01 -3.5587299437E-01 -3.5524089309E-01 -3.5461103153E-01 -3.5398340017E-01 -3.5335798731E-01 -3.5273478124E-01 -3.5211377027E-01 -3.5149494269E-01 -3.5087828373E-01 -3.5026378405E-01 -3.4965143359E-01 -3.4904122118E-01 -3.4843313568E-01 -3.4782716591E-01 -3.4722330074E-01 -3.4662152533E-01 -3.4602183228E-01 -3.4542421132E-01 -3.4482865181E-01 -3.4423514312E-01 -3.4364367460E-01 -3.4305423563E-01 -3.4246681166E-01 -3.4188139641E-01 -3.4129797977E-01 -3.4071655158E-01 -3.4013710172E-01 -3.3955962003E-01 -3.3898409638E-01 -3.3841051679E-01 -3.3783887542E-01 -3.3726916258E-01 -3.3670136861E-01 -3.3613548384E-01 -3.3557149861E-01 -3.3500940324E-01 -3.3444918462E-01 -3.3389083661E-01 -3.3333435031E-01 -3.3277971650E-01 0.0000000000E+00 -2.6088547982E-01 -5.1833275472E-01 -7.6895641941E-01 -1.0094757748E+00 -1.2367649640E+00 -1.4479004921E+00 -1.6402053307E+00 -1.8112888675E+00 -1.9590820386E+00 -2.0818670611E+00 -2.1783012866E+00 -2.2474347945E+00 -2.2887214604E+00 -2.3020233440E+00 -2.2876083718E+00 -2.2461413919E+00 -2.1786688108E+00 -2.0865971283E+00 -1.9716657861E+00 -1.8359148921E+00 -1.6816483354E+00 -1.5113931252E+00 -1.3278555788E+00 -1.1338753152E+00 -9.3237750193E-01 -7.2632508798E-01 -5.1867053707E-01 -3.1230935470E-01 -1.1003518382E-01 8.5502335005E-02 2.7183628053E-01 4.4671684037E-01 6.0814212888E-01 7.5438240005E-01 8.8400019998E-01 9.9586420814E-01 1.0891579569E+00 1.1633817902E+00 1.2183503968E+00 1.2541845008E+00 1.2712971870E+00 1.2703761390E+00 1.2523616859E+00 1.2184214326E+00 1.1699221627E+00 1.1083997635E+00 1.0355281365E+00 9.5308744579E-01 8.6293235820E-01 7.6696227219E-01 6.6708583573E-01 5.6517138232E-01 4.6301269339E-01 3.6230358110E-01 2.6460354791E-01 1.7132725391E-01 8.3714876259E-02 2.8300950036E-03 -7.0461868736E-02 -1.3548566127E-01 -1.9177104351E-01 -2.3903864371E-01 -2.7719764878E-01 -3.0633813688E-01 -3.2671240755E-01 -3.3872209753E-01 -3.4290134301E-01 -3.3989414704E-01 -3.3043492034E-01 -3.1532726713E-01 -2.9542143883E-01 -2.7159339422E-01 -2.4472437166E-01 -2.1568159041E-01 -1.8530141020E-01 -1.5437121547E-01 -1.2361699029E-01 -9.3692510618E-02 -6.5170103885E-02 -3.8534327148E-02 -1.4178178357E-02 7.5982219585E-03 2.6586599843E-02 4.2667321458E-02 5.5804230200E-02 6.6037784474E-02 7.3476782950E-02 7.8288985480E-02 8.0690950459E-02 8.0937413388E-02 7.9310526716E-02 7.6109267813E-02 7.1639300505E-02 6.6203546315E-02 6.0094670030E-02 5.3585181276E-02 4.6922886516E-02 4.0325965406E-02 3.3979459512E-02 2.8033278554E-02 2.2601546887E-02 1.7764693923E-02 1.3566271071E-02 1.0019934924E-02 7.1127553803E-03 4.8089618584E-03 3.0547066732E-03 1.7812642827E-03 9.1198278094E-04 3.6682674818E-04 6.5692263071E-05 -6.8632527182E-05 -1.1027997757E-04 -8.4781932173E-05 -7.5466225625E-06 5.5046813283E-06 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 -6.6230384280E-02 -1.3227044522E-01 -1.9793408785E-01 -2.6304354775E-01 -3.2743324392E-01 -3.9095326529E-01 -4.5347238282E-01 -5.1488049086E-01 -5.7509039536E-01 -6.3403888294E-01 -6.9168702295E-01 -7.4801967384E-01 -8.0304418574E-01 -8.5678831251E-01 -9.0929736637E-01 -9.6063067143E-01 -1.0108573877E+00 -1.0600518025E+00 -1.1082881938E+00 -1.1556354004E+00 -1.2021512134E+00 -1.2478767659E+00 -1.2928310462E+00 -1.3370057140E+00 -1.3803603227E+00 -1.4228182118E+00 -1.4642630461E+00 -1.5045363102E+00 -1.5434357567E+00 -1.5807149649E+00 -1.6160840886E+00 -1.6492118605E+00 -1.6797288707E+00 -1.7072322005E+00 -1.7312913303E+00 -1.7514553443E+00 -1.7672614056E+00 -1.7782442660E+00 -1.7839469588E+00 -1.7839324513E+00 -1.7777959450E+00 -1.7651779669E+00 -1.7457779317E+00 -1.7193680413E+00 -1.6858073499E+00 -1.6450558238E+00 -1.5971880652E+00 -1.5424070527E+00 -1.4810575934E+00 -1.4136370872E+00 -1.3407629725E+00 -1.2630862948E+00 -1.1812692944E+00 -1.0959852410E+00 -1.0079152517E+00 -9.1774784801E-01 -8.2617381277E-01 -7.3388443997E-01 -6.4156480522E-01 -5.4989159388E-01 -4.5952456379E-01 -3.7110347095E-01 -2.8524119151E-01 -2.0251655480E-01 -1.2347058174E-01 -4.8599831493E-02 2.1650489647E-02 8.6889253952E-02 1.4678399897E-01 2.0106542651E-01 2.4953062217E-01 2.9204347185E-01 3.2853617819E-01 3.5900919836E-01 3.8352979134E-01 4.0223095680E-01 4.1530746441E-01 4.2301167574E-01 4.2564876217E-01 4.2357093422E-01 4.1717097424E-01 4.0687519421E-01 3.9313595295E-01 3.7642387716E-01 3.5721993688E-01 3.3600752955E-01 3.1326472631E-01 2.8945683082E-01 2.6502939400E-01 2.4040181789E-01 2.1596166863E-01 1.9205980225E-01 1.6900638782E-01 1.4706789081E-01 1.2646640479E-01 1.0737471459E-01 8.9919605583E-02 7.4182301027E-02 6.0200233461E-02 4.7969874788E-02 3.7450322138E-02 2.8568294126E-02 2.1219868525E-02 1.5278963151E-02 1.0602331228E-02 7.0348351713E-03 4.4142517848E-03 2.5774088544E-03 1.3667064349E-03 6.3345563442E-04 2.4137577893E-04 6.9281378302E-05 2.0772501814E-05 1.5017397331E-05 1.0881212294E-06 -1.0503836267E-06 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 0.0000000000E+00 -2.4016441487E+01 0.0000000000E+00 0.0000000000E+00 -1.0336462913E+00 0.0000000000E+00 2.4794341471E-04 9.9091894057E-04 2.2263680628E-03 3.9500456984E-03 6.1560486329E-03 8.8368548808E-03 1.1983373531E-02 1.5585004525E-02 1.9629707710E-02 2.4104080427E-02 2.8993442803E-02 3.4281929867E-02 3.9952589544E-02 4.5987485557E-02 5.2367804247E-02 5.9073964300E-02 6.6085728409E-02 7.3382315882E-02 8.0942515274E-02 8.8744796138E-02 9.6767419086E-02 1.0498854333E-01 1.1338633103E-01 1.2193904783E-01 1.3062515893E-01 1.3942342031E-01 1.4831296458E-01 1.5727338117E-01 1.6628479066E-01 1.7532791282E-01 1.8438412840E-01 1.9343553473E-01 2.0246499428E-01 2.1145617765E-01 2.2039359948E-01 2.2926264851E-01 2.3804961085E-01 2.4674168841E-01 2.5532701021E-01 2.6379463827E-01 2.7213456885E-01 2.8033772768E-01 2.8839596035E-01 2.9630201805E-01 3.0404953869E-01 3.1163302393E-01 3.1904781286E-01 3.2629005077E-01 3.3335665407E-01 3.4024527527E-01 3.4695426557E-01 3.5348262690E-01 3.5982997159E-01 3.6599648316E-01 3.7198285339E-01 3.7779025613E-01 3.8342027746E-01 3.8887488964E-01 3.9415637933E-01 3.9926732777E-01 4.0421053528E-01 4.0898900016E-01 4.1360586662E-01 4.1806437563E-01 4.2236784139E-01 4.2651960765E-01 4.3052300623E-01 4.3438133902E-01 4.3809784793E-01 4.4167568640E-01 4.4511789734E-01 4.4842740211E-01 4.5160698378E-01 4.5465927654E-01 4.5758675943E-01 4.6039174939E-01 4.6307640307E-01 4.6564271888E-01 4.6809254111E-01 4.7042756695E-01 4.7264935579E-01 4.7475934017E-01 4.7675883847E-01 4.7864906862E-01 4.8043116285E-01 4.8210618286E-01 4.8367513530E-01 4.8513898716E-01 4.8649868075E-01 4.8775514807E-01 4.8890932424E-01 4.8996215983E-01 4.9091463191E-01 4.9176775358E-01 4.9252257613E-01 4.9318021185E-01 4.9374182540E-01 4.9420863911E-01 4.9458193531E-01 4.9486305613E-01 4.9505340201E-01 4.9515442062E-01 4.9516762730E-01 4.9509458085E-01 4.9493687901E-01 4.9469615451E-01 4.9437406196E-01 4.9397228868E-01 4.9349254046E-01 4.9293652709E-01 4.9230595866E-01 4.9160253929E-01 4.9082798382E-01 4.8998398626E-01 4.8907222166E-01 4.8809434735E-01 4.8705202061E-01 4.8594687199E-01 4.8478050140E-01 4.8355451132E-01 4.8227048421E-01 4.8092996944E-01 4.7953450212E-01 4.7808561574E-01 4.7658480457E-01 4.7503353906E-01 4.7343329913E-01 4.7178551873E-01 4.7009160857E-01 4.6835299066E-01 4.6657103314E-01 4.6474709403E-01 4.6288253276E-01 4.6097864623E-01 4.5903674889E-01 4.5705812988E-01 4.5504401645E-01 4.5299568348E-01 4.5091433129E-01 4.4880115759E-01 4.4665736345E-01 4.4448406520E-01 4.4228244437E-01 4.4005359528E-01 4.3779862199E-01 4.3551861800E-01 4.3321460984E-01 4.3088768122E-01 4.2853880795E-01 4.2616903012E-01 4.2377930732E-01 4.2137061147E-01 4.1894389471E-01 4.1650006236E-01 4.1404005773E-01 4.1156472312E-01 4.0907498816E-01 4.0657164288E-01 4.0405558773E-01 4.0152758537E-01 3.9898848719E-01 3.9643903481E-01 3.9388003353E-01 3.9131220208E-01 3.8873630343E-01 3.8615303095E-01 3.8356310956E-01 3.8096720441E-01 3.7836600704E-01 3.7576015114E-01 3.7315029989E-01 3.7053705201E-01 3.6792104757E-01 3.6530284664E-01 3.6268307155E-01 3.6006223998E-01 3.5744096187E-01 3.5481970890E-01 3.5219908368E-01 3.4957950873E-01 3.4696157326E-01 3.4434567985E-01 3.4173237209E-01 3.3912205408E-01 3.3651521191E-01 3.3391226115E-01 3.3131362397E-01 3.2871973492E-01 3.2613094713E-01 3.2354771963E-01 3.2097033407E-01 3.1839925340E-01 3.1583475732E-01 3.1327723928E-01 3.1072701520E-01 3.0818439374E-01 3.0564973754E-01 3.0312326636E-01 3.0060536753E-01 2.9809624731E-01 2.9559622996E-01 2.9310557269E-01 2.9062449750E-01 2.8815332279E-01 2.8569218837E-01 2.8324141465E-01 2.8080118028E-01 2.7837169267E-01 2.7595321500E-01 2.7354583751E-01 2.7114985674E-01 2.6876540189E-01 2.6639264465E-01 2.6403181011E-01 2.6168295407E-01 2.5934632864E-01 2.5702204381E-01 2.5471021239E-01 2.5241103884E-01 2.5012456127E-01 2.4785096372E-01 2.4559036883E-01 2.4334280687E-01 2.4110847696E-01 2.3888742000E-01 2.3667972467E-01 2.3448553732E-01 2.3230484695E-01 2.3013779622E-01 2.2798447164E-01 2.2584484162E-01 2.2371907224E-01 2.2160718423E-01 2.1950918491E-01 2.1742520274E-01 2.1535521910E-01 2.1329927590E-01 2.1125746569E-01 2.0922973692E-01 2.0721615973E-01 2.0521679417E-01 2.0323156191E-01 2.0126055392E-01 1.9930380230E-01 1.9736120736E-01 1.9543287344E-01 1.9351880846E-01 1.9161889992E-01 1.8973325450E-01 1.8786185993E-01 1.8600460254E-01 1.8416157699E-01 1.8233276208E-01 1.8051803620E-01 1.7871748583E-01 1.7693108606E-01 1.7515870043E-01 1.7340041110E-01 1.7165618863E-01 1.6992589269E-01 1.6820958701E-01 1.6650724345E-01 1.6481872662E-01 1.6314406985E-01 1.6148325248E-01 1.5983614921E-01 1.5820275480E-01 1.5658306061E-01 1.5497695691E-01 1.5338439180E-01 1.5180537259E-01 1.5023981072E-01 1.4868760030E-01 1.4714876754E-01 1.4562325032E-01 1.4411088316E-01 1.4261171261E-01 1.4112567980E-01 1.3965263949E-01 1.3819257554E-01 1.3674545831E-01 1.3531117665E-01 1.3388963650E-01 1.3248084168E-01 1.3108472136E-01 1.2970109889E-01 1.2833001076E-01 1.2697139008E-01 1.2562509939E-01 1.2429108335E-01 1.2296931894E-01 1.2165971717E-01 1.2036212317E-01 1.1907655698E-01 1.1780294648E-01 1.1654114810E-01 1.1529111045E-01 1.1405280258E-01 1.1282613765E-01 1.1161095024E-01 1.1040725990E-01 1.0921499300E-01 1.0803401854E-01 1.0686425527E-01 1.0570568262E-01 1.0455822148E-01 1.0342170539E-01 1.0229612790E-01 1.0118143008E-01 1.0007751189E-01 9.8984230691E-02 9.7901591614E-02 9.6829518883E-02 9.5767884597E-02 9.4716602554E-02 9.3675651345E-02 9.2644952595E-02 9.1624357062E-02 9.0613825474E-02 8.9613313452E-02 8.8622740963E-02 8.7641943554E-02 8.6670918562E-02 8.5709603256E-02 8.4757913158E-02 8.3815684928E-02 8.2882931486E-02 8.1959580376E-02 8.1045538566E-02 8.0140663081E-02 7.9244958367E-02 7.8358352085E-02 7.7480747512E-02 7.6612013484E-02 7.5752149816E-02 7.4901084880E-02 7.4058722878E-02 7.3224935982E-02 7.2399723308E-02 7.1583014448E-02 7.0774718909E-02 6.9974704043E-02 6.9182972050E-02 6.8399454182E-02 6.7624069401E-02 6.6856672591E-02 6.6097272493E-02 6.5345802386E-02 6.4602189287E-02 6.3866284591E-02 6.3138090627E-02 6.2417548303E-02 6.1704587356E-02 6.0999076474E-02 6.0300987164E-02 5.9610277067E-02 5.8926878874E-02 5.8250682553E-02 5.7581621736E-02 5.6919673704E-02 5.6264774278E-02 5.5616838504E-02 5.4975756187E-02 5.4341526243E-02 5.3714087760E-02 5.3093374958E-02 5.2479257060E-02 5.1871728058E-02 5.1270739451E-02 5.0676229134E-02 5.0088097362E-02 4.9506279485E-02 4.8930756928E-02 4.8361471290E-02 4.7798357672E-02 4.7241288817E-02 4.6690276084E-02 4.6145264773E-02 4.5606196203E-02 4.5072972721E-02 4.4545541444E-02 4.4023881815E-02 4.3507939101E-02 4.2997654834E-02 4.2492905991E-02 4.1993703269E-02 4.1499997132E-02 4.1011733250E-02 4.0528830544E-02 4.0051217904E-02 3.9578886841E-02 3.9111787057E-02 3.8649865000E-02 3.8193021326E-02 3.7741231625E-02 3.7294467263E-02 3.6852678829E-02 3.6415813870E-02 3.5983760247E-02 3.5556530198E-02 3.5134078994E-02 3.4716358396E-02 3.4303305080E-02 3.3894835682E-02 3.3490952616E-02 3.3091611670E-02 3.2696766006E-02 3.2306344980E-02 3.1920288091E-02 3.1538589081E-02 3.1161205154E-02 3.0788091067E-02 3.0419172782E-02 3.0054404780E-02 2.9693775584E-02 2.9337243976E-02 2.8984766463E-02 2.8636269166E-02 2.8291714111E-02 2.7951087999E-02 2.7614351317E-02 2.7281462438E-02 2.6952350866E-02 2.6626979290E-02 2.6305335782E-02 2.5987382630E-02 2.5673080163E-02 2.5362364216E-02 2.5055191839E-02 2.4751555386E-02 2.4451419017E-02 2.4154745071E-02 2.3861478444E-02 2.3571564847E-02 2.3285003479E-02 2.3001760410E-02 2.2721800031E-02 2.2445078789E-02 2.2171526061E-02 2.1901150013E-02 2.1633918647E-02 2.1369798413E-02 2.1108754197E-02 2.0850710883E-02 2.0595671221E-02 2.0343610458E-02 2.0094497098E-02 1.9848298202E-02 1.9604955310E-02 1.9364442566E-02 1.9126750436E-02 1.8891849457E-02 1.8659708833E-02 1.8430288872E-02 1.8203531688E-02 1.7979444001E-02 1.7757998342E-02 1.7539166017E-02 1.7322917097E-02 1.7109191383E-02 1.6897980399E-02 1.6689269114E-02 1.6483030879E-02 1.6279237912E-02 1.6077852629E-02 1.5878825755E-02 1.5682162720E-02 1.5487838857E-02 1.5295828455E-02 1.5106104755E-02 1.4918616206E-02 1.4733348857E-02 1.4550292886E-02 1.4369424576E-02 1.4190719249E-02 1.4014151128E-02 1.3839659221E-02 1.3667256683E-02 1.3496921706E-02 1.3328631601E-02 1.3162362793E-02 1.2998080875E-02 1.2835748138E-02 1.2675368275E-02 1.2516920489E-02 1.2360383178E-02 1.2205733920E-02 1.2052932833E-02 1.1901959252E-02 1.1752810004E-02 1.1605465350E-02 1.1459904808E-02 1.1316107146E-02 1.1174029833E-02 1.1033663349E-02 1.0895000275E-02 1.0758021954E-02 1.0622709048E-02 1.0489041530E-02 1.0356976695E-02 1.0226510813E-02 1.0097634680E-02 9.9703307378E-03 9.8445807986E-03 9.7203660474E-03 9.5976457522E-03 9.4764172062E-03 9.3566716576E-03 9.2383926415E-03 9.1215631207E-03 9.0061654822E-03 8.8921628626E-03 8.7795493594E-03 8.6683186485E-03 8.5584553503E-03 8.4499435627E-03 8.3427668572E-03 8.2368939208E-03 8.1323119604E-03 8.0290187790E-03 7.9270000634E-03 7.8262410234E-03 7.7267263895E-03 7.6284318873E-03 7.5313346684E-03 7.4354380585E-03 7.3407287840E-03 7.2471931373E-03 7.1548169739E-03 7.0635843287E-03 6.9734597403E-03 6.8844530956E-03 6.7965521281E-03 6.7097441767E-03 6.6240161831E-03 6.5393546899E-03 6.4557301699E-03 6.3731393266E-03 6.2915776433E-03 6.2110334645E-03 6.1314947748E-03 6.0529491959E-03 5.9753783320E-03 5.8987597471E-03 5.8230986296E-03 5.7483842858E-03 5.6746056953E-03 5.6017515092E-03 5.5298100485E-03 5.4587541386E-03 5.3885834526E-03 5.3192932870E-03 5.2508735670E-03 5.1833139204E-03 5.1166036764E-03 5.0507287806E-03 4.9856653379E-03 4.9214203547E-03 4.8579846503E-03 4.7953487751E-03 4.7335030098E-03 4.6724373639E-03 4.6121326368E-03 4.5525789599E-03 4.4937772672E-03 4.4357189771E-03 4.3783952646E-03 4.3217970601E-03 4.2659150477E-03 4.2107269600E-03 4.1562326781E-03 4.1024289394E-03 4.0493077557E-03 3.9968609188E-03 3.9450799988E-03 3.8939563432E-03 3.8434664007E-03 3.7936159723E-03 3.7443993547E-03 3.6958091420E-03 3.6478377293E-03 3.6004773117E-03 3.5537198828E-03 3.5075421006E-03 3.4619523711E-03 3.4169441116E-03 3.3725104825E-03 3.3286444647E-03 3.2853388583E-03 3.2425862821E-03 3.2003648485E-03 3.1586827452E-03 3.1175338565E-03 3.0769118893E-03 3.0368103888E-03 2.9972227375E-03 2.9581421546E-03 2.9195492532E-03 2.8814496160E-03 2.8438387299E-03 2.8067108257E-03 """ gpaw-0.11.0.13004/gpaw/test/pseudopotential/ah.py0000664000175000017500000000034212553643472021553 0ustar jensjjensj00000000000000from ase.lattice import bulk from gpaw import GPAW si = bulk('Si', 'diamond', a=5.5, cubic=not True) si.set_calculator(GPAW(setups='ah', kpts=(2, 2, 2))) si.get_potential_energy() si.calc.write('Si.gpw', 'all') GPAW('Si.gpw') gpaw-0.11.0.13004/gpaw/test/pseudopotential/hgh_h2o.py0000664000175000017500000000556412553643472022514 0ustar jensjjensj00000000000000from __future__ import print_function """Test of HGH pseudopotential implementation. This is the canonical makes-sure-nothing-breaks test, which checks that the numbers do not change from whatever they were before. The test runs an HGH calculation on a misconfigured H2O molecule, such that the forces are nonzero. Energy is compared to a previous calculation; if it differs significantly, that is considered an error. Forces are compared to a previous finite-difference result. """ import numpy as np from ase.structure import molecule from gpaw import GPAW from gpaw.utilities import unpack from gpaw.atom.basis import BasisMaker from gpaw.test import equal mol = molecule('H2O') mol.rattle(0.2) mol.center(vacuum=2.0) calc = GPAW(nbands=6, gpts=(32, 40, 40), setups='hgh', convergence=dict(eigenstates=1e-9, density=1e-5, energy=0.3e-5), txt='-') mol.set_calculator(calc) e = mol.get_potential_energy() niter = calc.get_number_of_iterations() F_ac = mol.get_forces() F_ac_ref = np.array([[ 7.33077718, 3.81069249, -6.07405156], [-0.9079617 , -1.18203514, 3.43777589], [-0.61642527, -0.41889306, 2.332415 ]]) eref = 724.479830538 eerr = abs(e - eref) print('energy', e) print('ref energy', eref) print('energy error', eerr) print('forces') print(F_ac) print('ref forces') print(F_ac_ref) ferr = np.abs(F_ac - F_ac_ref).max() print('max force error', ferr) fdcheck = False if fdcheck: from ase.calculators.test import numeric_forces F_ac_fd = numeric_forces(mol) print('Self-consistent forces') print(F_ac) print('FD forces') print(F_ac_fd) print() print(repr(F_ac_fd)) print() err = np.abs(F_ac - F_ac_fd).max() print('max err', err) wfs = calc.wfs gd = wfs.gd psit_nG = wfs.kpt_u[0].psit_nG dH_asp = calc.hamiltonian.dH_asp assert eerr < 1e-3, 'energy changed from reference' assert ferr < 0.015, 'forces do not match FD check' # Sanity check. In HGH, the atomic Hamiltonian is constant. # Also the projectors should be normalized for a, dH_sp in dH_asp.items(): dH_p = dH_sp[0] K_p = wfs.setups[a].K_p #B_ii = wfs.setups[a].B_ii #assert np.abs(B_ii.diagonal() - 1).max() < 1e-3 #print 'B_ii' #print wfs.setups[a].B_ii # Actually, H2O might not be such a good test, since there'll only # be one element in the atomic Hamiltonian for O and zero for H. #print 'dH_p', dH_p #print 'K_p', K_p assert np.abs(dH_p - K_p).max() < 1e-10, 'atomic Hamiltonian changed' #h_ii = setup.data.h_ii #print 'h_ii', h_ii #print 'dH_ii', dH_ii # Sanity check: HGH is normconserving for psit_G in psit_nG: norm = gd.integrate(psit_G**2) # Around 1e-15 ! Surprisingly good. assert abs(1 - norm) < 1e-10, 'Not normconserving' energy_tolerance = 0.00002 niter_tolerance = 0 equal(e, eref, energy_tolerance) # svnversion 5252 gpaw-0.11.0.13004/gpaw/test/pseudopotential/sg15_hydrogen.py0000664000175000017500000000270212553643472023643 0ustar jensjjensj00000000000000# Test loading of sg15 setups as setups='sg15' and that the calculation # agrees with PAW for the H2 eigenvalue. from __future__ import print_function from ase.structure import molecule from gpaw import GPAW, PoissonSolver from gpaw.utilities import h2gpts from gpaw.test.pseudopotential.H_sg15 import pp_text from gpaw import setup_paths setup_paths.insert(0, '.') # We can't easily load a non-python file from the test suite. # Therefore we load the pseudopotential from a Python file. # But we want to test the pseudopotential search mechanism, therefore # we immediately write it to a file: fd = open('H_ONCV_PBE-1.0.upf', 'w') fd.write(pp_text) fd.close() # All right... system = molecule('H2') system.center(vacuum=2.5) def getkwargs(): return dict(eigensolver='cg', xc='oldPBE', poissonsolver=PoissonSolver(relax='GS', eps=1e-8)) calc1 = GPAW(setups='sg15', gpts=h2gpts(0.16, system.get_cell(), idiv=8), **getkwargs()) system.set_calculator(calc1) system.get_potential_energy() eps1 = calc1.get_eigenvalues() calc2 = GPAW(gpts=h2gpts(0.22, system.get_cell(), idiv=8), **getkwargs()) system.set_calculator(calc2) system.get_potential_energy() eps2 = calc2.get_eigenvalues() err = eps2[0] - eps1[0] # It is not the most accurate calculation ever, let's just make sure things # are not completely messed up. print('Error', err) assert abs(err) < 0.008 # 0.0055.... as of current test. gpaw-0.11.0.13004/gpaw/test/pseudopotential/__init__.py0000664000175000017500000000000012553643472022711 0ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/pseudopotential/atompaw.py0000664000175000017500000000266512553643472022645 0ustar jensjjensj00000000000000from gpaw.atom.atompaw import AtomPAW from gpaw.upf import UPFSetupData def check(title, calc, epsref_n, threshold): eps_n = calc.wfs.kpt_u[0].eps_n print(title) for i, epsref in enumerate(epsref_n): err = abs(epsref - eps_n[i]) ok = (err <= threshold) status = 'ok' if ok else 'FAILED' print('state %d | eps=%f | ref=%f | err=%f | tol=%s | %s' % (i, eps_n[i], epsref, err, threshold, status)) assert ok kwargs = dict(txt=None) for setup in ['paw', 'hgh', UPFSetupData('H.pz-hgh.UPF')]: calc = AtomPAW('H', [[[1]]], rcut=12.0, h=0.05, setups={'H': setup}, **kwargs) tol = 5e-4 if setup in ['paw', 'hgh'] else 1e-3 # horrible UPF right now check('H %s' % setup, calc, [-0.233471], tol) for setup in ['paw', 'hgh', UPFSetupData('O.pz-hgh.UPF')]: calc = AtomPAW('O', [[[2], [4]]], rcut=10.0, h=0.035, setups={'O': setup}, **kwargs) tol = 1e-3 if setup in ['paw', 'hgh'] else 5e-3 # horrible UPF right now check('O %s' % setup, calc, [-0.871362, -0.338381], tol) gpaw-0.11.0.13004/gpaw/test/gemm_complex.py0000664000175000017500000000121112553643471020413 0ustar jensjjensj00000000000000# for n > 4 (?) # when run with gpaw-python built with MKL matrices b and c have ~zero elements # running with python (uses _gpaw.so) gives right (non-zero) results! import numpy as np n = 5 # works for n = 4 a1 = np.eye(n) + 1.j a2 = a1 + 1.j from gpaw.utilities.blas import gemm b = np.zeros((n, n), dtype=complex) c = np.dot(a2, a1) gemm(1.0, a1, a2, 0.0, b) thresh = 1.0e-7 ref_max_value = -9.0 #print b #print c numpy_dot = np.max(b).real gpaw_gemm = np.max(c).real #print gpaw_gemm assert abs(gpaw_gemm-numpy_dot) < thresh, (gpaw_gemm, numpy_dot, thresh) assert abs(gpaw_gemm-ref_max_value) < thresh, (gpaw_gemm, ref_max_value, thresh) gpaw-0.11.0.13004/gpaw/test/MgO_exx_fd_vs_pw.py0000664000175000017500000000252212553643471021202 0ustar jensjjensj00000000000000from __future__ import print_function from ase.dft.kpoints import monkhorst_pack from ase.lattice import bulk from gpaw import GPAW, FermiDirac from gpaw.wavefunctions.pw import PW nk = 4 for mode in ('pw', 'fd'): kpts = monkhorst_pack((nk, nk, nk)) kshift = 1.0 / (2 * nk) kpts += kshift atoms = bulk('MgO', 'rocksalt', a=4.212) if mode == 'pw': calc = GPAW(mode=PW(800), basis='dzp', xc='PBE', maxiter=300, kpts=kpts, parallel={'band': 1, 'domain': 1}, setups={'Mg': '2'}, occupations=FermiDirac(0.01)) atoms.set_calculator(calc) E1 = atoms.get_potential_energy() from gpaw.xc.hybridg import HybridXC exx = HybridXC('EXX', method='acdf') E_hf1 = E1 + calc.get_xc_difference(exx) else: calc = GPAW(h=0.12, basis='dzp', kpts=kpts, xc='PBE', setups={'Mg': '2'}, parallel={'domain': 1, 'band': 1}, occupations=FermiDirac(0.01)) atoms.set_calculator(calc) E2 = atoms.get_potential_energy() from gpaw.xc.hybridk import HybridXC exx = HybridXC('EXX', acdf=True) E_hf2 = E2 + calc.get_xc_difference(exx) print((E1, E2, E_hf1, E_hf2)) assert abs(E1 - E2) < 0.05 assert abs(E_hf1 - E_hf2) < 0.05 gpaw-0.11.0.13004/gpaw/test/ewald.py0000664000175000017500000001212412553643471017040 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from gpaw.utilities.ewald import Ewald verbose = True # References for Madelung constants with homogenous background charges: # M.P. Marder, "Condensed Matter Physics", J. Wiley, (2000), # scaled to the Wigner-Seitz radius. # References for Madelung constants of ionic crystals: # Y. Sakamoto, The J. of Chem. Phys., vol. 28, (1958), p. 164, # scaled to the nearest neighbor distance. if 1: #fcc cell = np.array([[0., .5, .5], [.5, .0, .5], [.5, .5, .0]]) basis = np.array([[0.,0.,0.]]) charges = np.array([1.]) r = np.array([0.0,0.0,0.0]) charges = np.array([1]) ewald = Ewald(cell) e = ewald.get_electrostatic_potential(r, basis, charges, excludefroml0=0) a_this = -e * ewald.get_wigner_seitz_radius(sum(charges)) a_ref = 1.79175 if verbose: print('Madelung energy, fcc:', a_this, a_this-a_ref) assert abs(a_this-a_ref) < 1e-5 if 1: #hcp a = 1. c = np.sqrt(8./3.)*a cell = np.array([[.5*a, -0.5*np.sqrt(3)*a,0], [.5*a, 0.5*np.sqrt(3)*a,0], [0., 0., c]]) basis = np.array([[.5*a, .5/np.sqrt(3)*a, 0.], [.5*a, -.5/np.sqrt(3)*a, 0.5*c]]) r = np.array([.5*a, .5/np.sqrt(3)*a, 0.]) charges = np.array([1.,1.]) ewald = Ewald(cell) e = ewald.get_electrostatic_potential(r, basis, charges, excludefroml0=0) a_this = -e * ewald.get_wigner_seitz_radius(sum(charges)) a_ref = 1.79168 if verbose: print('Madelung energy, hcp:', a_this, a_this-a_ref) assert abs(a_this-a_ref) < 1e-5 if 1: #Simple Cubic cell = np.diag([1.,1.,1.]) basis = np.array([[0.,0.,0.]]) charges = np.array([1.]) r = np.array([0.0,0.0,0.0]) charges = np.array([1]) ewald = Ewald(cell) e = ewald.get_electrostatic_potential(r, basis, charges, excludefroml0=0) a_this = -e*ewald.get_wigner_seitz_radius(1) a_ref = 1.76012 if verbose: print('Madelung energy, sc:', a_this, a_this-a_ref) assert abs(a_this-a_ref) < 1e-5 if 1: # NaCl cell = np.array([[0., .5, .5], [.5, .0, .5], [.5, .5, .0]]) basis = np.array([[0.,0.,0.], [.5,.5,.5]]) r = np.array([0.0,0.0,0.0]) charges = np.array([1,-1]) ewald = Ewald(cell) e = ewald.get_electrostatic_potential(r, basis, charges, excludefroml0=0) a_this = - 0.5 * e a_ref = 1.7475645946331822 if verbose: print('Madelung constant, NaCl (B1):', a_this, a_this-a_ref) assert abs(a_this-a_ref) < 1e-13 if 0: # NaCl cell =np.diag((1.,1.,1.)) basis = np.array([[0.,0.,0.], [.5,.5,.0], [.5,.0,.5], [.0,.5,.5], [.5,0.,0.], [.0,.5,.0], [.0,.0,.5], [.5,.5,.5]] ) r = np.array([0.0,0.0,0.0]) charges = np.array([1,1,1,1,-1,-1,-1,-1]) ewald = Ewald(cell) e = ewald.get_electrostatic_potential(r, basis, charges, excludefroml0=0) a_this = - 0.5 * e a_ref = 1.7475645946331822 if verbose: print('Madelung constant, NaCl (B1):', a_this, a_this-a_ref) assert abs(a_this-a_ref) < 1e-13 if 1: # CsCl cell = np.diag((1.,1.,1.)) basis = np.array([[0.,0.,0.], [.5, .5, .5]]) r = np.array([0.0,0.0,0.0]) charges = np.array([1,-1]) ewald = Ewald(cell) e = ewald.get_electrostatic_potential(r, basis, charges, excludefroml0=0) a_this = - .5 * np.sqrt(3.) * e a_ref = 1.76267477307099 if verbose: print('Madelung constant, CsCl (B2):', a_this, a_this-a_ref) assert abs(a_this-a_ref) < 1e-13 if 1: # Zincblende, cubic ZnS cell = np.array([[.0,.5,.5], [.5,.0,.5], [.5,.5,.0]]) basis = np.array([[0.,0.,0.], [.25,.25,.25]]) r = np.array([0.0,0.0,0.0]) charges = np.array([1,-1]) ewald = Ewald(cell) e = ewald.get_electrostatic_potential(r, basis, charges, excludefroml0=0) a_this = - 0.25 * np.sqrt(3) * e a_ref = 1.63805505338879 if verbose: print('Madelung constant, Zincblende (B3):', a_this, a_this-a_ref) assert abs(a_this-a_ref) < 1e-13 if 1: # Ideal Wurtzite, ZnS, (B4) a = 1. c = np.sqrt(8./3.)*a u = 3./8. cell = np.array([[.5*a, -0.5*np.sqrt(3)*a,0], [.5*a, 0.5*np.sqrt(3)*a,0], [0., 0., c]]) basis = np.array([[.5*a, .5/np.sqrt(3)*a, 0.], [.5*a, -.5/np.sqrt(3)*a, 0.5*c], [.5*a, .5/np.sqrt(3)*a, u*c], [.5*a, -.5/np.sqrt(3)*a, (.5+u)*c]]) r = np.array([.5*a, .5/np.sqrt(3)*a, 0.]) charges = np.array([1.,1.,-1,-1]) ewald = Ewald(cell) e = ewald.get_electrostatic_potential(r, basis, charges, excludefroml0=0) a_this = - 1. * u * c * e a_ref = 1.64132162737 if verbose: print('Madelung constant, Ideal Wurtzite (B4):', a_this, a_this-a_ref) assert abs(a_this-a_ref) < 1e-11 gpaw-0.11.0.13004/gpaw/test/response_na_plasmon.py0000664000175000017500000001057412553643471022020 0ustar jensjjensj00000000000000import os import numpy as np from ase import Atoms from gpaw import GPAW, PW from gpaw.mpi import world from gpaw.test import equal, findpeak from gpaw.utilities import compiled_with_sl from gpaw.response.df import DielectricFunction # Comparing the plasmon peaks found in bulk sodium for two different # atomic structures. Testing for idential plasmon peaks. Not using # physical sodium cell. a = 4.23 / 2.0 a1 = Atoms('Na', scaled_positions=[[0, 0.1, 0]], cell=(a, a, a), pbc=True) # Expanding along x-direction a2 = Atoms('Na2', scaled_positions=[[0, 0.1, 0], [0.5, 0.1, 0]], cell=(2 * a, a, a), pbc=True) a1.calc = GPAW(gpts=(10, 10, 10), mode=PW(300), kpts={'size': (8, 8, 8), 'gamma': True}, parallel={'band': 1}, #txt='small.txt', ) # Kpoint sampling should be halved in the expanded direction. a2.calc = GPAW(gpts=(20, 10, 10), mode=PW(300), kpts={'size': (4, 8, 8), 'gamma': True}, parallel={'band': 1}, #txt='large.txt', ) a1.get_potential_energy() a2.get_potential_energy() # Use twice as many bands for expanded structure a1.calc.diagonalize_full_hamiltonian(nbands=20) a2.calc.diagonalize_full_hamiltonian(nbands=40) a1.calc.write('gs_Na_small.gpw', 'all') a2.calc.write('gs_Na_large.gpw', 'all') # Settings that should yeild the same result settings = [{'disable_point_group': True, 'disable_time_reversal': True, 'use_more_memory': 0}, {'disable_point_group': False, 'disable_time_reversal': True, 'use_more_memory': 0}, {'disable_point_group': True, 'disable_time_reversal': False, 'use_more_memory': 0}, {'disable_point_group': False, 'disable_time_reversal': False, 'use_more_memory': 0}, {'disable_point_group': False, 'disable_time_reversal': False, 'use_more_memory': 1}] # Test block parallelization (needs scalapack) if world.size > 1 and compiled_with_sl(): settings.append({'disable_point_group': False, 'disable_time_reversal': False, 'use_more_memory': 1, 'nblocks': 2}) # Calculate the dielectric functions dfs0 = [] # Arrays to check for self-consistency dfs1 = [] dfs2 = [] dfs3 = [] dfs4 = [] dfs5 = [] for kwargs in settings: try: os.remove('chi0+0+0+0.pckl') except OSError: pass df1 = DielectricFunction('gs_Na_small.gpw', domega0=0.03, ecut=150, name='chi0', **kwargs) df1NLFCx, df1LFCx = df1.get_dielectric_function(direction='x') df1NLFCy, df1LFCy = df1.get_dielectric_function(direction='y') df1NLFCz, df1LFCz = df1.get_dielectric_function(direction='z') try: os.remove('chi1+0+0+0.pckl') except OSError: pass df2 = DielectricFunction('gs_Na_large.gpw', domega0=0.03, ecut=150, name='chi1', **kwargs) df2NLFCx, df2LFCx = df2.get_dielectric_function(direction='x') df2NLFCy, df2LFCy = df2.get_dielectric_function(direction='y') df2NLFCz, df2LFCz = df2.get_dielectric_function(direction='z') dfs0.append(df1NLFCx) dfs1.append(df1LFCx) dfs2.append(df1NLFCy) dfs3.append(df1LFCy) dfs4.append(df1NLFCz) dfs5.append(df1LFCz) # Compare plasmon frequencies and intensities w_w = df1.chi0.omega_w w1, I1 = findpeak(w_w, -(1. / df1LFCx).imag) w2, I2 = findpeak(w_w, -(1. / df2LFCx).imag) equal(w1, w2, 1e-2) equal(I1, I2, 1e-3) w1, I1 = findpeak(w_w, -(1. / df1LFCy).imag) w2, I2 = findpeak(w_w, -(1. / df2LFCy).imag) equal(w1, w2, 1e-2) equal(I1, I2, 1e-3) w1, I1 = findpeak(w_w, -(1. / df1LFCz).imag) w2, I2 = findpeak(w_w, -(1. / df2LFCz).imag) equal(w1, w2, 1e-2) equal(I1, I2, 1e-3) # Check for self-consistency for i, dfs in enumerate([dfs0, dfs1, dfs2, dfs3, dfs4, dfs5]): while len(dfs): df = dfs.pop() for df2 in dfs: try: assert np.max(np.abs((df - df2) / df)) < 1e-3 except AssertionError: print(np.max(np.abs((df - df2) / df))) raise AssertionError gpaw-0.11.0.13004/gpaw/test/wfs_auto.py0000664000175000017500000000127212553643471017575 0ustar jensjjensj00000000000000"""Test automagical calculation of wfs""" import os import sys import time from gpaw import GPAW from ase import Atom, Atoms from gpaw.test import equal from ase.parallel import rank, barrier, size txt=None ending = 'gpw' restart = 'gpaw-restart-wfs_auto.' + ending # H2 H = Atoms([Atom('H', (0, 0, 0)), Atom('H', (0, 0, 1))]) H.center(vacuum=2.0) calc = GPAW(nbands=2, convergence={'eigenstates': 1e-3}, txt=txt) H.set_calculator(calc) H.get_potential_energy() calc.write(restart) calc = GPAW(restart) calc.set(fixdensity=False) # provoke deletion of calc.scf calc.converge_wave_functions() calc.set(nbands=5) calc.converge_wave_functions() if rank == 0: os.remove(restart) gpaw-0.11.0.13004/gpaw/test/nsc_MGGA.py0000664000175000017500000000360312553643471017324 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atoms from gpaw import GPAW from gpaw.test import equal, gen # ??? g = Generator('H', 'TPSS', scalarrel=True, nofiles=True) atoms = Atoms('H', magmoms=[1], pbc=True) atoms.center(vacuum=3) calc = GPAW(gpts=(32, 32, 32), nbands=1, xc='PBE', txt='Hnsc.txt') atoms.set_calculator(calc) e1 = atoms.get_potential_energy() niter1 = calc.get_number_of_iterations() e1ref = calc.get_reference_energy() de12t = calc.get_xc_difference('TPSS') de12m = calc.get_xc_difference('M06L') de12r = calc.get_xc_difference('revTPSS') print('================') print('e1 = ', e1) print('de12t = ', de12t) print('de12m = ', de12m) print('de12r = ', de12r) print('tpss = ', e1 + de12t) print('m06l = ', e1 + de12m) print('revtpss = ', e1 + de12r) print('================') equal(e1 + de12t, -1.11723235592, 0.005) equal(e1 + de12m, -1.18207312133, 0.005) equal(e1 + de12r, -1.10093196353, 0.005) # ??? g = Generator('He', 'TPSS', scalarrel=True, nofiles=True) atomsHe = Atoms('He', pbc=True) atomsHe.center(vacuum=3) calc = GPAW(gpts=(32, 32, 32), nbands=1, xc='PBE', txt='Hensc.txt') atomsHe.set_calculator(calc) e1He = atomsHe.get_potential_energy() niter_1He = calc.get_number_of_iterations() e1refHe = calc.get_reference_energy() de12tHe = calc.get_xc_difference('TPSS') de12mHe = calc.get_xc_difference('M06L') de12rHe = calc.get_xc_difference('revTPSS') print('================') print('e1He = ', e1He) print('de12tHe = ', de12tHe) print('de12mHe = ', de12mHe) print('de12rHe = ', de12rHe) print('tpss = ', e1He + de12tHe) print('m06l = ', e1He + de12mHe) print('revtpss = ', e1He + de12rHe) print('================') equal(e1He+de12tHe, -0.409972893501, 0.005) equal(e1He+de12mHe, -0.487249688866, 0.005) equal(e1He+de12rHe, -0.447232286813, 0.005) energy_tolerance = 0.0005 niter_tolerance = 0 equal(e1, -1.123322, energy_tolerance) equal(e1He, 0.0100192, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/constant_electric_field.py0000664000175000017500000000353012553643471022613 0ustar jensjjensj00000000000000from __future__ import print_function import sys from math import sqrt, pi import numpy as np from ase import Atoms from ase.units import Bohr, Hartree from ase.parallel import rank from gpaw import GPAW from gpaw.external_potential import ConstantElectricField ### field = 0.01 dx = 2.0 vac = 3.0 nsteps = 3 nbands = 4 a0 = dx+2*vac b0 = 2*vac debug = False if debug: txt = 'gpaw.out' else: txt = None ### a = Atoms('Be', positions=[ [ b0/2, b0/2, a0/2 ] ], cell=[ b0, b0, a0 ]) z_list = np.linspace(a0/2-dx/2, a0/2+dx/2, nsteps) if True: c = GPAW( h = 0.30, width = 0.0, nbands = nbands, spinpol = False, xc = 'LDA', txt = txt, ) a.set_calculator(c) ### e_no_field = [ ] for z in z_list: if rank == 0 and debug: print(z) a[0].z = z e_no_field += [ a.get_potential_energy() ] e_no_field = np.array(e_no_field) ### if True: c = GPAW( h = 0.30, width = 0.0, nbands = nbands, spinpol = False, xc = 'LDA', txt = txt, external = ConstantElectricField(field * Bohr/Hartree) ) a.set_calculator(c) e_with_field = [ ] for z in z_list: if rank == 0 and debug: print(z) a[0].z = z e_with_field += [ a.get_potential_energy() ] e_with_field = np.array(e_with_field) ### np.savetxt("e.out", np.transpose( [ z_list, e_with_field-e_no_field, e_no_field, e_with_field ] )) c1, c2 = np.polyfit(z_list, e_with_field-e_no_field, 1) # 4*field because the charge of the nuclei is not considered # in ExternalPotential err = abs(c1-a[0].number*field) if rank == 0 and debug: print(c1) print(err) assert err < 0.001 gpaw-0.11.0.13004/gpaw/test/pplda.py0000664000175000017500000000221712553643471017046 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atoms from gpaw import GPAW import numpy as np # spin paired H2 d = 0.75 h2 = Atoms('H2', [[0, 0, 0], [0, 0, d]]) h2.center(vacuum=2.) e = np.array([]) f = np.array([]) for xc in ['LDA', 'PPLDA']: calc = GPAW(nbands=-1, xc=xc, convergence={'eigenstates': 1.e-9}, txt=None) h2.set_calculator(calc) e = np.append(e, h2.get_potential_energy()) f = np.append(f, h2.get_forces()) del calc print(e[0], e[1], np.abs(e[0] - e[1])) print(f[0], f[1], np.sum(np.abs(f[0] - f[1]))) assert np.abs(e[0] - e[1]) < 1.e-8 assert np.sum(np.abs(f[0] - f[1])) < 1.e-8 # spin polarized O2 d = 1.2 o2 = Atoms('O2', [[0, 0, 0], [0, 0, d]], magmoms=[1., 1.]) o2.center(vacuum=2.) e = np.array([]) f = np.array([]) for xc in ['LDA', 'PPLDA']: calc = GPAW(nbands=-2, xc=xc, convergence={'energy': 1.e-9}, txt=None) o2.set_calculator(calc) e = np.append(e, o2.get_potential_energy()) f = np.append(f, o2.get_forces()) del calc print(e[0], e[1], np.abs(e[0] - e[1])) print(f[0], f[1], np.sum(np.abs(f[0] - f[1]))) assert np.abs(e[0] - e[1]) < 1.e-8 assert np.sum(np.abs(f[0] - f[1])) < 1.e-4 gpaw-0.11.0.13004/gpaw/test/scfsic_h2.py0000664000175000017500000000136212553643472017612 0ustar jensjjensj00000000000000import numpy as np from ase import Atoms from gpaw import GPAW, restart from gpaw.xc.sic import SIC from gpaw.test import equal a = 6.0 atom = Atoms('H', magmoms=[1.0], cell=(a, a, a)) molecule = Atoms('H2', positions=[(0, 0, 0), (0, 0, 0.737)], cell=(a, a, a)) atom.center() molecule.center() calc = GPAW(xc='LDA-PZ-SIC', eigensolver='rmm-diis', txt='h2.sic.txt', setups='hgh') atom.set_calculator(calc) e1 = atom.get_potential_energy() molecule.set_calculator(calc) e2 = molecule.get_potential_energy() F_ac = molecule.get_forces() de = 2 * e1 - e2 #equal(de, 4.5, 0.1) # Test forces ... calc.write('H2.gpw', mode='all') atoms, calc = restart('H2.gpw') e2b = atoms.get_potential_energy() equal(e2, e2b, 0.0001) gpaw-0.11.0.13004/gpaw/test/nabla.py0000664000175000017500000000210612553643471017020 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from gpaw.lfc import LocalizedFunctionsCollection as LFC from gpaw.grid_descriptor import GridDescriptor from gpaw.atom.radialgd import EquidistantRadialGridDescriptor from gpaw.spline import Spline from gpaw.setup import Setup rc = 2.0 a = 2.5 * rc n = 64 lmax = 2 b = 8.0 m = (lmax + 1)**2 gd = GridDescriptor([n, n, n], [a, a, a]) r = np.linspace(0, rc, 200) g = np.exp(-(r / rc * b)**2) splines = [Spline(l=l, rmax=rc, f_g=g) for l in range(lmax + 1)] c = LFC(gd, [splines]) c.set_positions([(0, 0, 0)]) psi = gd.zeros(m) d0 = c.dict(m) if 0 in d0: d0[0] = np.identity(m) c.add(psi, d0) d1 = c.dict(m, derivative=True) c.derivative(psi, d1) class TestSetup(Setup): l_j = range(lmax + 1) nj = lmax + 1 ni = m def __init__(self): pass rgd = EquidistantRadialGridDescriptor(r[1], len(r)) g = [np.exp(-(r / rc * b)**2) * r**l for l in range(lmax + 1)] d2 = TestSetup().get_derivative_integrals(rgd, g, np.zeros_like(g)) if 0 in d1: print(abs(d1[0] - d2).max()) assert abs(d1[0] - d2).max() < 2e-6 gpaw-0.11.0.13004/gpaw/test/fractional_translations_big.py0000664000175000017500000000224012553643471023506 0ustar jensjjensj00000000000000from ase.lattice.spacegroup import crystal from gpaw import GPAW from gpaw import PW from gpaw.test import equal name = 'cristobalite' # no. 92 - tetragonal a = 5.0833674 c = 7.0984738 p0 = (0.2939118, 0.2939118, 0.0) p1 = (0.2412656, 0.0931314, 0.1739217) atoms = crystal(['Si', 'O'], basis=[p0, p1], spacegroup=92, cellpar=[a, a, c, 90, 90, 90]) ## with fractional translations calc = GPAW(mode=PW(), xc='LDA', kpts=(3, 3, 2), nbands=40, symmetry={'symmorphic': False}, gpts=(24, 24, 32), eigensolver='rmm-diis') atoms.set_calculator(calc) energy_fractrans = atoms.get_potential_energy() assert(len(calc.wfs.kd.ibzk_kc) == 3) assert(len(calc.wfs.kd.symmetry.op_scc) == 8) ## without fractional translations calc = GPAW(mode=PW(), xc='LDA', kpts=(3, 3, 2), nbands=40, gpts=(24, 24, 32), eigensolver='rmm-diis') atoms.set_calculator(calc) energy_no_fractrans = atoms.get_potential_energy() assert(len(calc.wfs.kd.ibzk_kc) == 6) assert(len(calc.wfs.kd.symmetry.op_scc) == 2) equal(energy_fractrans, energy_no_fractrans, 1e-7) gpaw-0.11.0.13004/gpaw/test/fractional_translations.py0000664000175000017500000000220212553643471022663 0ustar jensjjensj00000000000000from ase.lattice.spacegroup import crystal from gpaw import GPAW from gpaw import PW from gpaw.test import equal name = 'sishovite' # no 136 - tetragonal a = 4.233944 c = 2.693264 p0 = (0, 0, 0) p1 = (0.306866, 0.306866, 0.0) atoms = crystal(['Si', 'O'], basis=[p0, p1], spacegroup=136, cellpar=[a, a, c, 90, 90, 90]) ## with fractional translation calc = GPAW(mode=PW(), xc='LDA', kpts=(3, 3, 3), nbands=28, symmetry={'symmorphic': False}, gpts=(18, 18, 12), eigensolver='rmm-diis') atoms.set_calculator(calc) energy_fractrans = atoms.get_potential_energy() assert(len(calc.wfs.kd.ibzk_kc) == 6) assert(len(calc.wfs.kd.symmetry.op_scc) == 16) ## without fractional translations calc = GPAW(mode=PW(), xc='LDA', kpts=(3, 3, 3), nbands=28, gpts=(18, 18, 12), eigensolver='rmm-diis') atoms.set_calculator(calc) energy_no_fractrans = atoms.get_potential_energy() assert(len(calc.wfs.kd.ibzk_kc) == 8) assert(len(calc.wfs.kd.symmetry.op_scc) == 8) equal(energy_fractrans, energy_no_fractrans, 1e-7) gpaw-0.11.0.13004/gpaw/test/multipoleH2O.py0000664000175000017500000000206212553643472020270 0ustar jensjjensj00000000000000from __future__ import print_function import sys import numpy as np from ase.structure import molecule from ase.parallel import parprint from gpaw import GPAW, PW from gpaw.analyse.multipole import Multipole from gpaw.cluster import Cluster from gpaw.test import equal h = 0.3 s = Cluster(molecule('H2O')) s.minimal_box(3., h) gpwname = 'H2O_h' + str(h) + '.gpw' try: # XXX check why this fails in parallel calc = GPAW(gpwname + 'failsinparallel', txt=None) atoms = calc.get_atoms() calc.density.set_positions(atoms.get_scaled_positions() % 1.0) calc.density.interpolate_pseudo_density() calc.density.calculate_pseudo_charge() except IOError: calc = GPAW(h=h, charge=0, txt=None) calc.calculate(s) calc.write(gpwname) dipole_c = calc.get_dipole_moment() parprint('Dipole', dipole_c) center = np.array([1,1,1]) * 50. mp = Multipole(center, calc, lmax=2) q_L = mp.expand(-calc.density.rhot_g) parprint('Multipole', q_L) # The dipole moment is independent of the center equal(dipole_c[2], q_L[2], 1e-10) mp.to_file(calc, mode='w') gpaw-0.11.0.13004/gpaw/test/spin_contamination.py0000664000175000017500000000213512553643471021641 0ustar jensjjensj00000000000000import os import sys from gpaw.test import equal from ase import Atom from gpaw import GPAW, MixerDif from gpaw.cluster import Cluster h = .25 q = 0 box = 3. spin=True # B should not have spin contamination s = Cluster([Atom('B')]) s.minimal_box(box, h=h) s.set_initial_magnetic_moments([-1]) c = GPAW(xc='LDA', nbands=-3, charge=q, spinpol=spin, h=h, mixer=MixerDif(beta=0.05, nmaxold=5, weight=50.0), convergence={'eigenstates': 0.078, 'density': 1e-2, 'energy': 0.1}, ) c.calculate(s) equal(c.density.get_spin_contamination(s, 1), 0., 0.01) # setup H2 at large distance with different spins for the atoms s = Cluster([Atom('H'), Atom('H',[0,0,3.0])]) s.minimal_box(box, h=h) s.set_initial_magnetic_moments([-1,1]) c = GPAW(xc='LDA', nbands=-3, charge=q, spinpol=spin, h=h, convergence={'eigenstates': 0.078, 'density': 1e-2, 'energy': 0.1}, ) c.calculate(s) scont_s = [c.density.get_spin_contamination(s), c.density.get_spin_contamination(s, 1)] equal(scont_s[0], scont_s[1], 2.e-4) # symmetry equal(scont_s[0], 0.9655, 1.5e-3) gpaw-0.11.0.13004/gpaw/test/atoms_mismatch.py0000664000175000017500000000125212553643471020754 0ustar jensjjensj00000000000000# Check that atoms object mismatches are detected properly across CPUs. from ase.structure import molecule from gpaw.mpi import world, synchronize_atoms system = molecule('H2O') synchronize_atoms(system, world) if world.rank == 1: system.positions[1, 1] += 1e-8 # fail (above tolerance) if world.rank == 2: system.cell[0, 0] += 1e-15 # fail (zero tolerance) if world.rank == 3: system.positions[1, 1] += 1e-10 # pass (below tolerance) expected_err_ranks = {1: [], 2: [1]}.get(world.size, [1, 2]) try: synchronize_atoms(system, world, tolerance=1e-9) except ValueError as e: assert (expected_err_ranks == e.args[1]).all() else: assert world.size == 1 gpaw-0.11.0.13004/gpaw/test/simple_stm.py0000664000175000017500000000514112553643471020121 0ustar jensjjensj00000000000000from __future__ import print_function import os from ase import Atom, Atoms from ase.parallel import size, rank from gpaw import GPAW, FermiDirac from gpaw.analyse.simple_stm import SimpleStm from gpaw.test import equal load=True load=False txt = '/dev/null' txt='-' me = '' if size > 1: me += 'rank ' + str(rank) + ': ' BH = Atoms([Atom('B', [.0, .0, .41]), Atom('H', [.0, .0, -1.23]), ], cell=[5, 6, 6.5]) BH.center() f3dname = 'stm3d.plt' def testSTM(calc): stm = SimpleStm(calc) stm.write_3D([1,0,0], f3dname) # single wf wf = stm.gd.integrate(stm.ldos) ## print "wf=", wf if size == 1: # XXXX we have problem with reading plt in parallel stm2 = SimpleStm(f3dname) wf2 = stm2.gd.integrate(stm2.ldos) print('Integrals: written, read=', wf, wf2) equal(wf, wf2, 2.e-7) stm.scan_const_current(0.02, 5) ## print eigenvalue_string(calc) stm.write_3D(3.1, f3dname) wf2 = stm.gd.integrate(stm.ldos) ## print "wf2=", wf2 equal(wf2, 2, 0.12) return wf # finite system without spin and width fname='BH-nospin_wfs.gpw' if not load: BH.set_pbc(False) cf = GPAW(nbands=3, h=.3, txt=txt) BH.set_calculator(cf) e1 = BH.get_potential_energy() niter1 = cf.get_number_of_iterations() cf.write(fname, 'all') else: cf = GPAW(fname, txt=txt) wf = testSTM(cf) # finite system with spin fname='BH-spin_Sz2_wfs.gpw' BH.set_initial_magnetic_moments([1, 1]) if not load: BH.set_pbc(False) cf = GPAW(occupations=FermiDirac(0.1, fixmagmom=True), nbands=5, h=0.3, txt=txt) BH.set_calculator(cf) e2 = BH.get_potential_energy() niter2 = cf.get_number_of_iterations() cf.write(fname, 'all') else: cf = GPAW(fname, txt=txt) testSTM(cf) # periodic system if not load: BH.set_pbc(True) cp = GPAW(spinpol=True, nbands=3, h=.3, kpts=(2,1,1), txt=txt) BH.set_calculator(cp) e3 = BH.get_potential_energy() niter3 = cp.get_number_of_iterations() cp.write('BH-8kpts_wfs.gpw', 'all') else: cp = GPAW('BH-8kpts_wfs.gpw', txt=txt) stmp = SimpleStm(cp) stmp.write_3D(-4., f3dname) print(me + 'Integrals(occ): 2 * wf, bias=', 2 * wf, stmp.gd.integrate(stmp.ldos)) equal(2 * wf, stmp.gd.integrate(stmp.ldos), 0.02) stmp.write_3D(+4., f3dname) print(me + 'Integrals(unocc): 2 * wf, bias=', end=' ') print(2 * wf, stmp.gd.integrate(stmp.ldos)) equal(2 * wf, stmp.gd.integrate(stmp.ldos), 0.02) energy_tolerance = 0.0007 niter_tolerance = 0 equal(e1, -2.54026, energy_tolerance) equal(e2, -1.51101, energy_tolerance) equal(e3, -2.83573, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/solvation/0000775000175000017500000000000012553644063017406 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/solvation/adm12.py0000664000175000017500000000370312553643471020671 0ustar jensjjensj00000000000000""" tests solvation parameters as in O. Andreussi, I. Dabo, and N. Marzari, The Journal of Chemical Physics, vol. 136, no. 6, p. 064102, 2012 """ from gpaw import GPAW from gpaw.cluster import Cluster from gpaw.test import equal from ase.structure import molecule from ase.units import mol, kcal, Pascal, m, Bohr from gpaw.solvation import ( SolvationGPAW, ADM12SmoothStepCavity, LinearDielectric, GradientSurface, SurfaceInteraction, KB51Volume, VolumeInteraction, ElDensity ) from gpaw.solvation.poisson import ADM12PoissonSolver import warnings SKIP_VAC_CALC = True h = 0.24 vac = 4.0 epsinf = 78.36 rhomin = 0.0001 / Bohr ** 3 rhomax = 0.0050 / Bohr ** 3 st = 50. * 1e-3 * Pascal * m p = -0.35 * 1e9 * Pascal convergence = { 'energy': 0.05 / 8., 'density': 10., 'eigenstates': 10., } atoms = Cluster(molecule('H2O')) atoms.minimal_box(vac, h) if not SKIP_VAC_CALC: atoms.calc = GPAW(xc='PBE', h=h, convergence=convergence) Evac = atoms.get_potential_energy() print(Evac) else: # h=0.24, vac=4.0, setups: 0.9.11271, convergence: only energy 0.05 / 8 Evac = -14.857414548 with warnings.catch_warnings(): # ignore production code warning for ADM12PoissonSolver warnings.simplefilter("ignore") psolver = ADM12PoissonSolver() atoms.calc = SolvationGPAW( xc='PBE', h=h, poissonsolver=psolver, convergence=convergence, cavity=ADM12SmoothStepCavity( rhomin=rhomin, rhomax=rhomax, epsinf=epsinf, density=ElDensity(), surface_calculator=GradientSurface(), volume_calculator=KB51Volume() ), dielectric=LinearDielectric(epsinf=epsinf), interactions=[ SurfaceInteraction(surface_tension=st), VolumeInteraction(pressure=p) ] ) Ewater = atoms.get_potential_energy() assert atoms.calc.get_number_of_iterations() < 40 atoms.get_forces() DGSol = (Ewater - Evac) / (kcal / mol) print('Delta Gsol: %s kcal / mol' % DGSol) equal(DGSol, -6.3, 2.) gpaw-0.11.0.13004/gpaw/test/solvation/poisson.py0000664000175000017500000001032312553643471021453 0ustar jensjjensj00000000000000from gpaw.solvation.poisson import ( WeightedFDPoissonSolver, ADM12PoissonSolver, PolarizationPoissonSolver ) from gpaw.solvation.dielectric import FDGradientDielectric from gpaw.grid_descriptor import GridDescriptor from gpaw.utilities.gauss import Gaussian from gpaw.fd_operators import Gradient from ase.units import Bohr from gpaw.test import equal from gpaw.utilities import erf from ase.parallel import parprint import numpy as np import warnings nn = 3 accuracy = 2e-10 def gradient(gd, x, nn): out = gd.empty(3) for i in (0, 1, 2): Gradient(gd, i, 1.0, nn).apply(x, out[i]) return out def make_gd(h, box, pbc): diag = np.array([box] * 3) cell = np.diag(diag) grid_shape = tuple((diag / h * 2).astype(int)) return GridDescriptor(grid_shape, cell / Bohr, pbc) class MockDielectric(FDGradientDielectric): def update(self, cavity): self.update_gradient() box = 12. gd = make_gd(h=.4, box=box, pbc=False) def solve(ps, eps, rho): phi = gd.zeros() dielectric = MockDielectric(epsinf=eps.max(), nn=nn) dielectric.set_grid_descriptor(gd) dielectric.allocate() dielectric.eps_gradeps[0][...] = eps dielectric.update(None) with warnings.catch_warnings(): # ignore production code warning for alternative psolvers warnings.simplefilter("ignore") solver = ps(nn=nn, relax='J', eps=accuracy) solver.set_dielectric(dielectric) solver.set_grid_descriptor(gd) solver.initialize() solver.solve(phi, rho) return phi psolvers = ( WeightedFDPoissonSolver, ADM12PoissonSolver, PolarizationPoissonSolver ) # test neutral system with constant permittivity parprint('neutral, constant permittivity') epsinf = 80. eps = gd.zeros() eps.fill(epsinf) qs = (-1., 1.) shifts = (-1., 1.) rho = gd.zeros() phi_expected = gd.zeros() for q, shift in zip(qs, shifts): gauss_norm = q / np.sqrt(4 * np.pi) gauss = Gaussian(gd, center=(box / 2. + shift) * np.ones(3.) / Bohr) rho += gauss_norm * gauss.get_gauss(0) phi_expected += gauss_norm * gauss.get_gauss_pot(0) / epsinf for ps in psolvers: phi = solve(ps, eps, rho) parprint(ps, np.abs(phi - phi_expected).max()) equal(phi, phi_expected, 1e-3) # test charged system with constant permittivity parprint('charged, constant permittivity') epsinf = 80. eps = gd.zeros() eps.fill(epsinf) q = -2. gauss_norm = q / np.sqrt(4 * np.pi) gauss = Gaussian(gd, center=(box / 2. + 1.) * np.ones(3.) / Bohr) rho_gauss = gauss_norm * gauss.get_gauss(0) phi_gauss = gauss_norm * gauss.get_gauss_pot(0) phi_expected = phi_gauss / epsinf for ps in psolvers: phi = solve(ps, eps, rho_gauss) parprint(ps, np.abs(phi - phi_expected).max()) equal(phi, phi_expected, 1e-3) # test non-constant permittivity msgs = ( 'neutral, non-constant permittivity', 'charged, non-constant permittivity' ) qss = ((-1., 1.), (2., )) shiftss = ((-.4, .4), (-1., )) epsshifts = (.0, -1.) for msg, qs, shifts, epsshift in zip(msgs, qss, shiftss, epsshifts): parprint(msg) epsinf = 80. gauss = Gaussian(gd, center=(box / 2. + epsshift) * np.ones(3.) / Bohr) eps = gauss.get_gauss(0) eps = epsinf - eps / eps.max() * (epsinf - 1.) rho = gd.zeros() phi_expected = gd.zeros() grad_eps = gradient(gd, eps - epsinf, nn) for q, shift in zip(qs, shifts): gauss = Gaussian(gd, center=(box / 2. + shift) * np.ones(3.) / Bohr) phi_tmp = gauss.get_gauss_pot(0) xyz = gauss.xyz fac = 2. * np.sqrt(gauss.a) * np.exp(-gauss.a * gauss.r2) fac /= np.sqrt(np.pi) * gauss.r2 fac -= erf(np.sqrt(gauss.a) * gauss.r) / (gauss.r2 * gauss.r) fac *= 2.0 * 1.7724538509055159 grad_phi = fac * xyz laplace_phi = -4. * np.pi * gauss.get_gauss(0) rho_tmp = -1. / (4. * np.pi) * ( (grad_eps * grad_phi).sum(0) + eps * laplace_phi ) norm = gd.integrate(rho_tmp) rho_tmp /= norm * q phi_tmp /= norm * q rho += rho_tmp phi_expected += phi_tmp # PolarizationPoissonSolver does not pass this test for ps in psolvers[:-1]: phi = solve(ps, eps, rho) parprint(ps, np.abs(phi - phi_expected).max()) equal(phi, phi_expected, 1e-3) gpaw-0.11.0.13004/gpaw/test/solvation/sss09.py0000664000175000017500000000310612553643471020743 0ustar jensjjensj00000000000000""" tests solvation parameters as in V. M. Sanchez, M. Sued, and D. A. Scherlis, The Journal of Chemical Physics, vol. 131, no. 17, p. 174108, 2009 """ from gpaw import GPAW from gpaw.cluster import Cluster from gpaw.test import equal from ase import Atoms from ase.units import mol, kcal, Pascal, m, Bohr from gpaw.solvation import ( SolvationGPAW, FG02SmoothStepCavity, LinearDielectric, GradientSurface, SurfaceInteraction, SSS09Density) SKIP_VAC_CALC = True h = 0.24 vac = 4.0 epsinf = 78.36 rho0 = 1.0 / Bohr ** 3 beta = 2.4 st = 72. * 1e-3 * Pascal * m atomic_radii = lambda atoms: [2.059] convergence = { 'energy': 0.05 / 8., 'density': 10., 'eigenstates': 10., } atoms = Cluster(Atoms('Cl')) atoms.minimal_box(vac, h) if not SKIP_VAC_CALC: atoms.calc = GPAW(xc='PBE', h=h, charge=-1, convergence=convergence) Evac = atoms.get_potential_energy() print(Evac) else: # h=0.24, vac=4.0, setups: 0.9.11271, convergence: only energy 0.05 / 8 Evac = -3.83245253419 atoms.calc = SolvationGPAW( xc='PBE', h=h, charge=-1, convergence=convergence, cavity=FG02SmoothStepCavity( rho0=rho0, beta=beta, density=SSS09Density(atomic_radii=atomic_radii), surface_calculator=GradientSurface() ), dielectric=LinearDielectric(epsinf=epsinf), interactions=[SurfaceInteraction(surface_tension=st)] ) Ewater = atoms.get_potential_energy() assert atoms.calc.get_number_of_iterations() < 40 atoms.get_forces() DGSol = (Ewater - Evac) / (kcal / mol) print('Delta Gsol: %s kcal / mol' % DGSol) equal(DGSol, -75., 10.) gpaw-0.11.0.13004/gpaw/test/solvation/sfgcm06.py0000664000175000017500000000302012553643471021222 0ustar jensjjensj00000000000000""" tests solvation parameters as in Damian A. Scherlis, Jean-Luc Fattebert, Francois Gygi, Matteo Cococcioni and Nicola Marzari, J. Chem. Phys. 124, 074103, 2006 """ from gpaw import GPAW from gpaw.cluster import Cluster from gpaw.test import equal from ase import Atoms from ase.units import mol, kcal, Pascal, m, Bohr from gpaw.solvation import ( SolvationGPAW, FG02SmoothStepCavity, LinearDielectric, GradientSurface, SurfaceInteraction, ElDensity ) SKIP_VAC_CALC = True h = 0.24 vac = 4.0 epsinf = 78.36 rho0 = 0.00078 / Bohr ** 3 beta = 1.3 st = 72. * 1e-3 * Pascal * m convergence = { 'energy': 0.05 / 8., 'density': 10., 'eigenstates': 10., } atoms = Cluster(Atoms('Cl')) atoms.minimal_box(vac, h) if not SKIP_VAC_CALC: atoms.calc = GPAW(xc='PBE', h=h, charge=-1, convergence=convergence) Evac = atoms.get_potential_energy() print(Evac) else: # h=0.24, vac=4.0, setups: 0.9.11271, convergence: only energy 0.05 / 8 Evac = -3.83245253419 atoms.calc = SolvationGPAW( xc='PBE', h=h, charge=-1, convergence=convergence, cavity=FG02SmoothStepCavity( rho0=rho0, beta=beta, density=ElDensity(), surface_calculator=GradientSurface()), dielectric=LinearDielectric(epsinf=epsinf), interactions=[SurfaceInteraction(surface_tension=st)]) Ewater = atoms.get_potential_energy() assert atoms.calc.get_number_of_iterations() < 40 atoms.get_forces() DGSol = (Ewater - Evac) / (kcal / mol) print('Delta Gsol: %s kcal / mol' % DGSol) equal(DGSol, -75., 10.) gpaw-0.11.0.13004/gpaw/test/solvation/forces_symmetry.py0000664000175000017500000000311412553643471023213 0ustar jensjjensj00000000000000from ase import Atoms from ase.data.vdw import vdw_radii from gpaw.test import equal from ase.units import Pascal, m from gpaw.solvation import ( SolvationGPAW, EffectivePotentialCavity, Power12Potential, LinearDielectric, KB51Volume, GradientSurface, VolumeInteraction, SurfaceInteraction, LeakedDensityInteraction ) import numpy as np h = 0.2 d = 2.5 min_vac = 4.0 u0 = .180 epsinf = 80. T = 298.15 atomic_radii = lambda atoms: [vdw_radii[n] for n in atoms.numbers] xy_cell = np.ceil((min_vac * 2.) / h / 8.) * 8. * h z_cell = np.ceil((min_vac * 2. + d) / h / 8.) * 8. * h atoms = Atoms( 'NaCl', positions=( (xy_cell / 2., xy_cell / 2., z_cell / 2. - d / 2.), (xy_cell / 2., xy_cell / 2., z_cell / 2. + d / 2.) ) ) atoms.set_cell((xy_cell, xy_cell, z_cell)) atoms.calc = SolvationGPAW( xc='PBE', h=h, setups={'Na': '1'}, cavity=EffectivePotentialCavity( effective_potential=Power12Potential(atomic_radii, u0), temperature=T, volume_calculator=KB51Volume(), surface_calculator=GradientSurface() ), dielectric=LinearDielectric(epsinf=epsinf), # parameters chosen to give ~ 1eV for each interaction interactions=[ VolumeInteraction(pressure=-1e9 * Pascal), SurfaceInteraction(surface_tension=100. * 1e-3 * Pascal * m), LeakedDensityInteraction(voltage=10.) ] ) F = atoms.calc.get_forces(atoms) difference = F[0][2] + F[1][2] equal(difference, .0, .02) # gas phase is ~.007 eV / Ang F[0][2] = F[1][2] = .0 equal(np.abs(F), .0, 1e-9) # gas phase is ~1e-11 eV / Ang gpaw-0.11.0.13004/gpaw/test/solvation/vacuum.py0000664000175000017500000000321312553643471021261 0ustar jensjjensj00000000000000from gpaw import GPAW from gpaw.cluster import Cluster from gpaw.test import equal from ase.structure import molecule from ase.data.vdw import vdw_radii from gpaw.solvation import ( SolvationGPAW, EffectivePotentialCavity, Power12Potential, LinearDielectric) import numpy as np SKIP_REF_CALC = True dE = 1e-9 # XXX: check: why is there a difference at all? dF = 1e-7 # -- " -- h = 0.3 vac = 3.0 u0 = .180 T = 298.15 vdw_radii = vdw_radii.copy() vdw_radii[1] = 1.09 atomic_radii = lambda atoms: [vdw_radii[n] for n in atoms.numbers] atoms = Cluster(molecule('H2O')) atoms.minimal_box(vac, h) convergence = { 'energy': 0.05 / 8., 'density': 10., 'eigenstates': 10., } if not SKIP_REF_CALC: atoms.calc = GPAW(xc='LDA', h=h, convergence=convergence) Eref = atoms.get_potential_energy() print(Eref) Fref = atoms.get_forces() print(Fref) else: # h=0.3, vac=3.0, setups: 0.9.11271, convergence: only energy 0.05 / 8 Eref = -11.9838020445 Fref = np.array( [ [9.68634537e-13, -6.74234034e-13, -3.39987211e+00], [4.93976820e-14, 1.75606065e+00, 1.68012920e-02], [1.07907651e-13, -1.75606065e+00, 1.68012920e-02] ] ) atoms.calc = SolvationGPAW( xc='LDA', h=h, convergence=convergence, cavity=EffectivePotentialCavity( effective_potential=Power12Potential(atomic_radii=atomic_radii, u0=u0), temperature=T ), dielectric=LinearDielectric(epsinf=1.0), ) Etest = atoms.get_potential_energy() Eeltest = atoms.calc.get_electrostatic_energy() Ftest = atoms.get_forces() equal(Etest, Eref, dE) equal(Ftest, Fref, dF) equal(Eeltest, Etest) gpaw-0.11.0.13004/gpaw/test/solvation/swap_atoms.py0000664000175000017500000000407012553643471022140 0ustar jensjjensj00000000000000from gpaw.cluster import Cluster from ase.structure import molecule from ase.units import Pascal, m from ase.data.vdw import vdw_radii from gpaw.solvation import ( SolvationGPAW, EffectivePotentialCavity, Power12Potential, LinearDielectric, GradientSurface, SurfaceInteraction, ) h = 0.3 vac = 3.0 u0 = 0.180 epsinf = 80. st = 18.4 * 1e-3 * Pascal * m T = 298.15 vdw_radii = vdw_radii.copy() vdw_radii[1] = 1.09 atomic_radii = lambda atoms: [vdw_radii[n] for n in atoms.numbers] convergence = { 'energy': 0.1 / 8., 'density': 10., 'eigenstates': 10., } atoms = Cluster(molecule('H2O')) atoms.minimal_box(vac, h) calc = SolvationGPAW( xc='LDA', h=h, convergence=convergence, cavity=EffectivePotentialCavity( effective_potential=Power12Potential(atomic_radii, u0), temperature=T, surface_calculator=GradientSurface() ), dielectric=LinearDielectric(epsinf=epsinf), interactions=[SurfaceInteraction(surface_tension=st)] ) atoms.calc = calc atoms.get_potential_energy() atoms.get_forces() eps_gradeps = calc.hamiltonian.dielectric.eps_gradeps # same molecules, different cell, reallocate atoms = Cluster(molecule('H2O')) atoms.positions[0][0] = atoms.positions[0][0] - 1. atoms.minimal_box(vac, h) atoms.calc = calc atoms.get_potential_energy() atoms.get_forces() assert calc.hamiltonian.dielectric.eps_gradeps is not eps_gradeps eps_gradeps = calc.hamiltonian.dielectric.eps_gradeps # small position change, no reallocate atoms.positions[0][0] = atoms.positions[0][0] + 1e-2 atoms.get_potential_energy() atoms.get_forces() assert calc.hamiltonian.dielectric.eps_gradeps is eps_gradeps eps_gradeps = calc.hamiltonian.dielectric.eps_gradeps radii = calc.hamiltonian.cavity.effective_potential.r12_a # completely different atoms object, reallocate, read new radii atoms = Cluster(molecule('NH3')) atoms.minimal_box(vac, h) atoms.calc = calc atoms.get_potential_energy() atoms.get_forces() assert calc.hamiltonian.dielectric.eps_gradeps is not eps_gradeps assert calc.hamiltonian.cavity.effective_potential.r12_a is not radii gpaw-0.11.0.13004/gpaw/test/solvation/spinpol.py0000664000175000017500000000337712553643471021460 0ustar jensjjensj00000000000000from gpaw.test import equal from gpaw.cluster import Cluster from ase.structure import molecule from ase.units import Pascal, m from ase.data.vdw import vdw_radii from gpaw.solvation import ( SolvationGPAW, EffectivePotentialCavity, Power12Potential, LinearDielectric, SurfaceInteraction, VolumeInteraction, LeakedDensityInteraction, GradientSurface, KB51Volume, ) import numpy as np h = 0.3 vac = 3.0 u0 = .180 epsinf = 80. T = 298.15 vdw_radii = vdw_radii.copy() vdw_radii[1] = 1.09 atomic_radii = lambda atoms: [vdw_radii[n] for n in atoms.numbers] atoms = Cluster(molecule('CN')) atoms.minimal_box(vac, h) atoms2 = atoms.copy() atoms2.set_initial_magnetic_moments(None) atomss = (atoms, atoms2) Es = [] Fs = [] for atoms in atomss: atoms.calc = SolvationGPAW( xc='LDA', h=h, charge=-1, cavity=EffectivePotentialCavity( effective_potential=Power12Potential(atomic_radii, u0), temperature=T, surface_calculator=GradientSurface(), volume_calculator=KB51Volume() ), dielectric=LinearDielectric(epsinf=epsinf), interactions=[ SurfaceInteraction( surface_tension=100. * 1e-3 * Pascal * m ), VolumeInteraction( pressure=-1.0 * 1e9 * Pascal ), LeakedDensityInteraction( voltage=1.0 ) ] ) Es.append(atoms.get_potential_energy()) Fs.append(atoms.get_forces()) # compare to expected difference of a gas phase calc print('difference E: ', Es[0] - Es[1]) equal(Es[0], Es[1], 0.0002) print('difference F: ', np.abs(Fs[0] - Fs[1]).max()) equal(Fs[0], Fs[1], 0.003) # XXX add test case where spin matters, e.g. charge=0 for CN? gpaw-0.11.0.13004/gpaw/test/solvation/water_water.py0000664000175000017500000000317112553643471022310 0ustar jensjjensj00000000000000from gpaw import GPAW from gpaw.cluster import Cluster from gpaw.test import equal from ase.structure import molecule from ase.units import mol, kcal, Pascal, m from ase.data.vdw import vdw_radii from gpaw.solvation import ( SolvationGPAW, EffectivePotentialCavity, Power12Potential, LinearDielectric, GradientSurface, SurfaceInteraction, ) SKIP_VAC_CALC = True h = 0.24 vac = 4.0 u0 = 0.180 epsinf = 78.36 st = 18.4 * 1e-3 * Pascal * m T = 298.15 vdw_radii = vdw_radii.copy() vdw_radii[1] = 1.09 atomic_radii = lambda atoms: [vdw_radii[n] for n in atoms.numbers] convergence = { 'energy': 0.05 / 8., 'density': 10., 'eigenstates': 10., } atoms = Cluster(molecule('H2O')) atoms.minimal_box(vac, h) if not SKIP_VAC_CALC: atoms.calc = GPAW(xc='PBE', h=h, convergence=convergence) Evac = atoms.get_potential_energy() print(Evac) else: # h=0.24, vac=4.0, setups: 0.9.11271, convergence: only energy 0.05 / 8 Evac = -14.857414548 atoms.calc = SolvationGPAW( xc='PBE', h=h, convergence=convergence, cavity=EffectivePotentialCavity( effective_potential=Power12Potential(atomic_radii, u0), temperature=T, surface_calculator=GradientSurface()), dielectric=LinearDielectric(epsinf=epsinf), interactions=[SurfaceInteraction(surface_tension=st)]) Ewater = atoms.get_potential_energy() Eelwater = atoms.calc.get_electrostatic_energy() Esurfwater = atoms.calc.get_solvation_interaction_energy('surf') atoms.get_forces() DGSol = (Ewater - Evac) / (kcal / mol) print('Delta Gsol: %s kcal / mol' % DGSol) equal(DGSol, -6.3, 2.) equal(Ewater, Eelwater + Esurfwater, 1e-14) gpaw-0.11.0.13004/gpaw/test/solvation/solvation_api.py0000664000175000017500000001223112553643471022630 0ustar jensjjensj00000000000000# XXX This test is a use case/acceptance test to help rewrite the api # XXX and not included in the test suite. # XXX TODO: make an example/documentation out of this test # XXX when the api has changed and the test passes from ase.structure import molecule from ase.units import Pascal, m, Bohr from ase.data.vdw import vdw_radii from ase.parallel import parprint from gpaw.solvation import ( # calculator SolvationGPAW, # cavities EffectivePotentialCavity, ADM12SmoothStepCavity, FG02SmoothStepCavity, # custom classes for the cavities Power12Potential, ElDensity, SSS09Density, # dielectric LinearDielectric, CMDielectric, # not used any more # non-el interactions SurfaceInteraction, VolumeInteraction, LeakedDensityInteraction, # surface and volume calculators GradientSurface, KB51Volume, ) # poisson solver from gpaw.solvation.poisson import ADM12PoissonSolver # references for custom classes: # KB51 = J. G. Kirkwood and F. P. Buff, # The Journal of Chemical Physics, vol. 19, no. 6, pp. 774--777, 1951 # FG02 = J.-L. Fattebert and F. Gygi, # Journal of Computational Chemistry, vol. 23, no. 6, pp. 662--666, 2002 # SSS09 = V. M. Sanchez, M. Sued, and D. A. Scherlis, # The Journal of Chemical Physics, vol. 131, no. 17, p. 174108, 2009 # ADM12 = O. Andreussi, I. Dabo, and N. Marzari, # The Journal of Chemical Physics, vol. 136, no. 6, p. 064102, 2012 # define some useful units (all api user units are ASE units!) dyn_per_cm = 1e-3 * Pascal * m Giga_Pascal = 1e9 * Pascal # GPAW params (examples) # ---------------------- xc = 'PBE' h = 0.24 vac = 4.0 # general solvation params (examples) # ----------------------------------- # electrostatic epsinf = 78.36 # other interactions gamma = 72. * dyn_per_cm # surface tension p = -0.1 * Giga_Pascal # pressure V_leak = 1.0 # V (interaction energy E = V_leak * [charge outside cavity]) # only for volume calculations respecting compressibility T = 298.15 # K (also used for Boltzmann distribution) kappa_T = 4.53e-10 / Pascal # effective potential cavity params (examples) # -------------------------------------------- u0 = 0.180 # eV vdw_radii = vdw_radii.copy() vdw_radii[1] = 1.09 atomic_radii = lambda atoms: [vdw_radii[n] for n in atoms.numbers] # density cavity params (examples) # -------------------------------- # ADM12 rhomin = 0.0001 / Bohr ** 3 rhomax = 0.0050 / Bohr ** 3 # FG02, SSS09 rho0 = 0.0004 / Bohr ** 3 beta = 1.3 rho0_fake = 1.0 / Bohr ** 3 beta_fake = 2.4 atoms = molecule('H2O') atoms.center(vacuum=vac) def print_results(atoms): parprint('E = %.3f eV' % (atoms.get_potential_energy(), )) parprint('V = %.3f Ang ** 3' % (atoms.calc.get_cavity_volume(), )) parprint('A = %.3f Ang ** 2' % (atoms.calc.get_cavity_surface(), )) parprint('Forces:') parprint(atoms.get_forces()) parprint('') # Cavity from 1 / r ** 12 effective potential atoms.calc = SolvationGPAW( xc=xc, h=h, cavity=EffectivePotentialCavity( effective_potential=Power12Potential(atomic_radii=atomic_radii, u0=u0), temperature=T, surface_calculator=GradientSurface(), volume_calculator=KB51Volume(compressibility=kappa_T, temperature=T) ), dielectric=LinearDielectric(epsinf=epsinf), interactions=[ SurfaceInteraction(surface_tension=gamma), VolumeInteraction(pressure=p), LeakedDensityInteraction(voltage=V_leak) ] ) print_results(atoms) # Cavity from electron density a la ADM12 atoms.calc = SolvationGPAW( xc=xc, h=h, poissonsolver=ADM12PoissonSolver(), cavity=ADM12SmoothStepCavity( rhomin, rhomax, epsinf, density=ElDensity(), surface_calculator=GradientSurface(), volume_calculator=KB51Volume(compressibility=kappa_T, temperature=T) ), dielectric=LinearDielectric(epsinf=epsinf), interactions=[ SurfaceInteraction(surface_tension=gamma), VolumeInteraction(pressure=p), LeakedDensityInteraction(voltage=V_leak) ] ) print_results(atoms) # Cavity from electron density a la FG02 atoms.calc = SolvationGPAW( xc=xc, h=h, cavity=FG02SmoothStepCavity( rho0, beta, density=ElDensity(), surface_calculator=GradientSurface(), volume_calculator=KB51Volume(compressibility=kappa_T, temperature=T) ), dielectric=LinearDielectric(epsinf=epsinf), interactions=[ SurfaceInteraction(surface_tension=gamma), VolumeInteraction(pressure=p), LeakedDensityInteraction(voltage=V_leak) ] ) print_results(atoms) # Cavity from fake electron density a la SSS09 atoms.calc = SolvationGPAW( xc=xc, h=h, cavity=FG02SmoothStepCavity( rho0_fake, beta_fake, density=SSS09Density(atomic_radii=atomic_radii), surface_calculator=GradientSurface(), volume_calculator=KB51Volume(compressibility=kappa_T, temperature=T) ), dielectric=LinearDielectric(epsinf=epsinf), interactions=[ SurfaceInteraction(surface_tension=gamma), VolumeInteraction(pressure=p), LeakedDensityInteraction(voltage=V_leak) ] ) print_results(atoms) gpaw-0.11.0.13004/gpaw/test/solvation/forces.py0000664000175000017500000002147112553643471021250 0ustar jensjjensj00000000000000from gpaw.test import equal from ase import Atoms from ase.units import Pascal, m from ase.data.vdw import vdw_radii from ase.parallel import rank from gpaw.solvation import ( SolvationGPAW, EffectivePotentialCavity, Power12Potential, LinearDielectric, KB51Volume, GradientSurface, VolumeInteraction, SurfaceInteraction, LeakedDensityInteraction) import numpy as np SKIP_ENERGY_CALCULATION = True F_max_err = 0.01 h = 0.2 u0 = 0.180 epsinf = 80. T = 298.15 atomic_radii = lambda atoms: [vdw_radii[n] for n in atoms.numbers] atoms = Atoms('NaCl', positions=((5.6, 5.6, 6.8), (5.6, 5.6, 8.8))) atoms.set_cell((11.2, 11.2, 14.4)) atoms.calc = SolvationGPAW( xc='PBE', h=h, setups={'Na': '1'}, cavity=EffectivePotentialCavity( effective_potential=Power12Potential(atomic_radii, u0), temperature=T, volume_calculator=KB51Volume(), surface_calculator=GradientSurface()), dielectric=LinearDielectric(epsinf=epsinf), # parameters chosen to give ~ 1eV for each interaction interactions=[ VolumeInteraction(pressure=-1e9 * Pascal), SurfaceInteraction(surface_tension=100. * 1e-3 * Pascal * m), LeakedDensityInteraction(voltage=10.) ] ) def vac(atoms): return min( atoms.positions[0][2], 14.4 - atoms.positions[1][2] ) step = .05 if not SKIP_ENERGY_CALCULATION: d = [] E = [] F = [] while vac(atoms) >= 5.6: d.append(abs(atoms.positions[0][2] - atoms.positions[1][2])) E.append(atoms.calc.get_potential_energy(atoms, force_consistent=True)) F.append(atoms.calc.get_forces(atoms)) atoms.positions[0][2] -= step d = np.array(d) E = np.array(E) F = np.array(F) if rank == 0: np.save('d.npy', d) np.save('E.npy', E) np.save('F.npy', F) from pprint import pprint print('d') pprint(list(d)) print() print('E') pprint(list(E)) print() print('F') pprint([list([list(l2) for l2 in l1]) for l1 in F]) else: # h=0.2, setups: 0.9.11271 d = [ 2.0000000000000009, 2.0500000000000007, 2.1000000000000005, 2.1500000000000004, 2.2000000000000002, 2.25, 2.2999999999999998, 2.3499999999999996, 2.3999999999999995, 2.4499999999999993, 2.4999999999999991, 2.5499999999999989, 2.5999999999999988, 2.6499999999999986, 2.6999999999999984, 2.7499999999999982, 2.799999999999998, 2.8499999999999979, 2.8999999999999977, 2.9499999999999975, 2.9999999999999973, 3.0499999999999972, 3.099999999999997, 3.1499999999999968, 3.1999999999999966 ] E = [ -3.562275095496517, -3.8473139097013753, -4.0700170404316216, -4.2411280906015847, -4.3696230053988998, -4.4631058774925938, -4.5278419352994277, -4.5689533655049273, -4.5909074791427535, -4.5973242956988001, -4.5911955771799642, -4.5750005750743217, -4.5508272583082476, -4.5204998569534682, -4.4853536276501051, -4.446576387818217, -4.4051492970094319, -4.3619637256674846, -4.3175923355729191, -4.2725810250114824, -4.2273623203404105, -4.1823745422113907, -4.1378435049679414, -4.0939327053888253, -4.0509012515430012 ] F = [ [[-6.8649267934919038e-12, -6.8285488255163915e-12, -6.4013896254399594], [-2.6300729419344384e-10, -2.6383434154270953e-10, 6.4024961288370834]], [[-6.7067934676926484e-12, -6.7827710411030432e-12, -5.035806576943255], [-2.6265003631465652e-10, -2.6358273430409411e-10, 5.0363219577200393]], [[-6.6452522782472319e-12, -6.7350652481746713e-12, -3.9024047426211013], [-2.599941690725449e-10, -2.6427151466339217e-10, 3.9041962651946549]], [[-6.6678787127007239e-12, -6.7240667463184095e-12, -2.9653099919755648], [-2.6301398163741478e-10, -2.6378537086737464e-10, 2.9677010135504456]], [[-6.7321644245704045e-12, -6.7023538748183105e-12, -2.1941739883216349], [-2.6323640189803985e-10, -2.6502975875270664e-10, 2.1956072044985082]], [[-6.6744556469137517e-12, -6.7342571167849082e-12, -1.5603845691279461], [-2.6150037805716431e-10, -2.6494203401997128e-10, 1.5617242524244506]], [[-6.6740115916431383e-12, -6.7067692706129593e-12, -1.0394646874434972], [-2.657058970775486e-10, -2.6486463588998541e-10, 1.0411305520365366]], [[-6.6978937133664486e-12, -6.7559118414194535e-12, -0.6139233210960644], [-2.6177850433079895e-10, -2.6417622580023846e-10, 0.61622349293177647]], [[-6.6211500466746826e-12, -6.6910274310038701e-12, -0.26943737156761505], [-2.6257887811625044e-10, -2.6408833568511208e-10, 0.27225705595193372]], [[-6.6850010873431177e-12, -6.7442884174800231e-12, 0.0089081295524152775], [-2.6124062311671723e-10, -2.6382235955634513e-10, -0.0076515998408599566]], [[-6.7390588871677577e-12, -6.7034381182837725e-12, 0.23393233473731392], [-2.6379960167644507e-10, -2.6460665237784466e-10, -0.23162254793656473]], [[-6.7478611985265237e-12, -6.7270688826163367e-12, 0.41344114500688628], [-2.6307072030825134e-10, -2.6499582985996902e-10, -0.41090256849768725]], [[-6.8089864119330214e-12, -6.7665673210298178e-12, 0.55336685925410833], [-2.6654711238076438e-10, -2.6500969566112445e-10, -0.5513277496947222]], [[-6.724371042066641e-12, -6.8046040813353111e-12, 0.66191904264557422], [-2.6690771291888572e-10, -2.6553224854951662e-10, -0.66116131240092779]], [[-6.8278815770331904e-12, -6.8044619806595946e-12, 0.74595045809588023], [-2.5978727053971925e-10, -2.6560989627796548e-10, -0.74446609663056418]], [[-6.7783638939157041e-12, -6.8133286336204628e-12, 0.80852902621501777], [-2.6244275687456016e-10, -2.6512375201569421e-10, -0.806217471185949]], [[-6.8446384858991989e-12, -6.8432091478293385e-12, 0.85168825894226086], [-2.6407844819045985e-10, -2.649684928296529e-10, -0.85040178985847581]], [[-6.7066299199700351e-12, -6.8496098228765492e-12, 0.88042067677910474], [-2.6392062693018424e-10, -2.6369080594848279e-10, -0.87999233344200489]], [[-6.8489522669943444e-12, -6.8984993318559013e-12, 0.89869231350992573], [-2.6765853049315407e-10, -2.652701718256956e-10, -0.8971875269274393]], [[-6.8160721183558111e-12, -6.8960086592369432e-12, 0.90729473426351359], [-2.632560888207301e-10, -2.6406685134015365e-10, -0.90541522611106229]], [[-6.986299841419749e-12, -6.9133592118879747e-12, 0.90622371816323821], [-2.618130831940452e-10, -2.6463957320603059e-10, -0.90650772392397816]], [[-6.9613071942774566e-12, -6.9395424290466483e-12, 0.89897847913208095], [-2.6166471205863267e-10, -2.6505752863392422e-10, -0.89825350436859608]], [[-6.9015705487362154e-12, -6.9199753382689915e-12, 0.88817599560445226], [-2.6640069318482646e-10, -2.656425323100925e-10, -0.88699092835462157]], [[-6.8099622202150577e-12, -6.9738365001184978e-12, 0.87343340469998276], [-2.6503495062870906e-10, -2.6377908478652655e-10, -0.87163079404060828]], [[-6.9867580450747381e-12, -7.0042141182343876e-12, 0.85369504926144513], [-2.6442899833727647e-10, -2.6415524503832887e-10, -0.85271756460899106]] ] d = np.array(d) E = np.array(E) F = np.array(F) # test for orthogonal forces equal zero: equal(F[..., :2], .0, 1e-7) stencil = 2 # 1 is too rough, 3 does not change compared to 2 FNa, FCl = F[..., 2].T FNa *= -1. # test symmetry equal(FNa, FCl, F_max_err) dd = np.diff(d)[0] kernel = { 1: np.array((0.5, 0, -0.5)), 2: np.array((-1. / 12., 2. / 3., 0, -2. / 3., 1. / 12.)), 3: np.array((1. / 60., -0.15, 0.75, 0, -0.75, 0.15, -1. / 60.)), } dEdz = np.convolve(E, kernel[stencil] / step, 'valid') err = np.maximum( np.abs(-dEdz - FNa[stencil:-stencil]), np.abs(-dEdz - FCl[stencil:-stencil]) ) # test forces against -dE / dd finite difference equal(err, .0, F_max_err) if SKIP_ENERGY_CALCULATION: # check only selected points: def check(index): atoms.positions[0][2] = 6.8 - index * step F_check = atoms.get_forces() equal(F_check[..., :2], .0, 1e-7) FNa_check, FCl_check = F_check[..., 2].T FNa_check *= -1. equal(FNa_check, FCl_check, F_max_err) err = np.maximum( np.abs(-dEdz[index - stencil] - FNa_check), np.abs(-dEdz[index - stencil] - FCl_check) ) equal(err, .0, F_max_err) l = len(FNa) # check(stencil) check(l // 2) # check(l - 1 - stencil) gpaw-0.11.0.13004/gpaw/test/solvation/pbc_pos_repeat.py0000664000175000017500000000471412553643471022755 0ustar jensjjensj00000000000000from gpaw.solvation.cavity import get_pbc_positions from ase.structure import molecule from ase.units import Bohr import numpy as np def get_nrepeats(nrepeats_c): return np.prod(np.array(nrepeats_c) * 2 + 1) def check_valid_repeat(pos_v, rpos_v, nrepeats_c, cell_cv): nrepeats_c = np.array(nrepeats_c) diff_v = rpos_v - pos_v actual_nrepeats_c = np.dot(diff_v, np.linalg.inv(cell_cv)) r_actual_nrepeats_c = np.around(actual_nrepeats_c) # check for integer multiple assert np.allclose(r_actual_nrepeats_c, actual_nrepeats_c) actual_nrepeats_c = np.abs(r_actual_nrepeats_c.astype(int)) # check for too large repeats assert (actual_nrepeats_c <= nrepeats_c).all() def check(pos_av, rpos_aav, nrepeats_c, cell_cv): assert len(pos_av) == len(rpos_aav) total_repeats = get_nrepeats(nrepeats_c) for a, pos_v in enumerate(pos_av): rpos_av = rpos_aav[a] assert len(rpos_av) == total_repeats for rpos_v in rpos_av: check_valid_repeat(pos_v, rpos_v, nrepeats_c, cell_cv) cells = ( ((10., .0, .0), (.0, 12., .0), (.0, .0, 12.)), # orthogonal ((10., 1., .0), (.0, 12., 1.), (1., .0, 11.5)), # non-orthogonal ) for cell in cells: atoms = molecule('H2O') atoms.center(vacuum=5.) atoms.set_cell(cell) pos_av = atoms.positions / Bohr cell_cv = atoms.get_cell() / Bohr Rcell_c = np.sqrt(np.sum(cell_cv ** 2, axis=1)) # non periodic should never repeat atoms.pbc = np.zeros((3, ), dtype=bool) pos_aav = get_pbc_positions(atoms, 1e10 / Bohr) check(pos_av, pos_aav, (0, 0, 0), cell_cv) # periodic, zero cutoff should not repeat atoms.pbc = np.ones((3, ), dtype=bool) pos_aav = get_pbc_positions(atoms, .0 / Bohr) check(pos_av, pos_aav, (0, 0, 0), cell_cv) # periodic, cutoff <= cell size should repeat once atoms.pbc = np.ones((3, ), dtype=bool) pos_aav = get_pbc_positions(atoms, 0.99 * Rcell_c.min()) check(pos_av, pos_aav, (1, 1, 1), cell_cv) # periodic, cutoff > cell size should repeat twice atoms.pbc = np.ones((3, ), dtype=bool) pos_aav = get_pbc_positions(atoms, 1.01 * Rcell_c.max()) check(pos_av, pos_aav, (2, 2, 2), cell_cv) # mixed bc, cutoff > 2 * cell size should repeat three times for i in range(8): pbc = np.array([int(p) for p in np.binary_repr(i, 3)]) atoms.pbc = pbc pos_aav = get_pbc_positions(atoms, 2.01 * Rcell_c.max()) check(pos_av, pos_aav, pbc * 3, cell_cv) gpaw-0.11.0.13004/gpaw/test/solvation/pbc.py0000664000175000017500000000217012553643471020526 0ustar jensjjensj00000000000000from gpaw.cluster import Cluster from ase.structure import molecule from ase.data.vdw import vdw_radii from gpaw.solvation import ( SolvationGPAW, EffectivePotentialCavity, Power12Potential, LinearDielectric ) from gpaw.solvation.poisson import ADM12PoissonSolver import warnings h = 0.3 vac = 3.0 u0 = .180 epsinf = 80. T = 298.15 vdw_radii = vdw_radii.copy() vdw_radii[1] = 1.09 atomic_radii = lambda atoms: [vdw_radii[n] for n in atoms.numbers] convergence = { 'energy': 0.05 / 8., 'density': 10., 'eigenstates': 10., } atoms = Cluster(molecule('H2O')) atoms.minimal_box(vac, h) atoms.pbc = True with warnings.catch_warnings(): # ignore production code warning for ADM12PoissonSolver warnings.simplefilter("ignore") psolver = ADM12PoissonSolver(eps=1e-7) atoms.calc = SolvationGPAW( xc='LDA', h=h, convergence=convergence, cavity=EffectivePotentialCavity( effective_potential=Power12Potential(atomic_radii=atomic_radii, u0=u0), temperature=T ), dielectric=LinearDielectric(epsinf=epsinf), poissonsolver=psolver ) atoms.get_potential_energy() atoms.get_forces() gpaw-0.11.0.13004/gpaw/test/solvation/__init__.py0000664000175000017500000000000012553643471021507 0ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/symmetry_ft.py0000664000175000017500000000600412553643472020327 0ustar jensjjensj00000000000000from math import sqrt import numpy as np from gpaw.symmetry import Symmetry from ase.dft.kpoints import monkhorst_pack # Primitive diamond lattice, with Si lattice parameter a = 5.475 cell_cv = .5 * a * np.array([(1, 1, 0), (1, 0, 1), (0, 1, 1)]) spos_ac = np.array([(.00, .00, .00), (.25, .25, .25)]) id_a = [1, 1] # Two identical atoms pbc_c = np.ones(3, bool) bzk_kc = monkhorst_pack((4, 4, 4)) # Do check symm = Symmetry(id_a, cell_cv, pbc_c, symmorphic=False) symm.analyze(spos_ac) ibzk_kc, w_k = symm.reduce(bzk_kc)[:2] assert len(symm.op_scc) == 48 assert len(w_k) == 10 a = 3 / 32.; b = 1 / 32.; c = 6 / 32. assert np.all(w_k == [a, b, a, c, c, a, a, a, a, b]) assert not symm.op_scc.sum(0).any() # Rotate unit cell and check again: cell_cv = a / sqrt(2) * np.array([(1, 0, 0), (0.5, sqrt(3) / 2, 0), (0.5, sqrt(3) / 6, sqrt(2.0 / 3))]) symm = Symmetry(id_a, cell_cv, pbc_c, symmorphic=False) symm.analyze(spos_ac) ibzkb_kc, wb_k = symm.reduce(bzk_kc)[:2] assert len(symm.op_scc) == 48 assert abs(w_k - wb_k).sum() < 1e-14 assert abs(ibzk_kc - ibzkb_kc).sum() < 1e-14 assert not symm.op_scc.sum(0).any() bzk_kc = monkhorst_pack((3, 3, 3)) symm = Symmetry(id_a, cell_cv, pbc_c) symm.analyze(spos_ac) ibzk_kc, w_k = symm.reduce(bzk_kc)[:2] assert len(symm.op_scc) == 24 assert len(w_k) == 4 assert abs(w_k * 27 - (1, 12, 6, 8)).sum() < 1e-14 assert not symm.op_scc.sum(0).any() # Rocksalt Ni2O2 a = 7.92; x = 2. * np.sqrt(1./3.); y = np.sqrt(1./8.); z1 = np.sqrt(1./24.); z2 = np.sqrt(1./6.) cell_cv = a * np.array([(x, y, -z1), (x, -y, -z1), (x, 0., z2)]) spos_ac = np.array([[0., 0. ,0.], [1./2., 1./2., 1./2.], [1./4., 1./4., 1./4.], [3./4., 3./4., 3./4.]]) id_a = [1, 2, 3, 3] pbc_c = np.array([1, 1, 1], bool) bzk_kc = monkhorst_pack((2, 2, 2)) # Do check symm = Symmetry(id_a, cell_cv, pbc_c, symmorphic=False) symm.analyze(spos_ac) ibzk_kc, w_k = symm.reduce(bzk_kc)[:2] assert len(symm.op_scc) == 12 assert len(w_k) == 2 assert np.all(w_k == [3/4., 1/4.]) #AlF3 a = 2.465250000; b = 1.423312751; c = 4.148733333 a1 = np.array([ a,-1.0*b, c]); a2 = np.array([ 0.0 , 2.0*b, c]); a3 = np.array([-1.0*a,-1.0*b, c]) cell_cv = np.array([a1,a2,a3]) id_a = [1, 1, 2, 2, 2, 2, 2, 2] spos_ac = np.array([(0.000000000, 0.000000000, 0.000000000), (0.500000000, 0.500000000, 0.500000000), (0.647758346, 0.852241654, 0.250000000), (0.852241654, 0.250000000, 0.647758346), (0.250000000, 0.647758346, 0.852241654), (0.352241654, 0.147758346, 0.750000000), (0.147758346, 0.750000000, 0.352241654), (0.750000000, 0.352241654, 0.147758346)]) pbc_c = np.array([1, 1, 1], bool) bzk_kc = monkhorst_pack((3, 3, 3)) # Do check symm = Symmetry(id_a, cell_cv, pbc_c, symmorphic=False) symm.analyze(spos_ac) ibzk_kc, w_k = symm.reduce(bzk_kc)[:2] assert len(symm.op_scc) == 12 assert len(w_k) == 6 assert np.all(w_k == [1/27., 2/9., 2/9., 2/9., 2/9., 2/27.]) assert not symm.op_scc.sum(0).any() gpaw-0.11.0.13004/gpaw/test/potential.py0000664000175000017500000000213112553643471017740 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW from gpaw.test import equal for mode in ['fd', 'pw']: print(mode) hydrogen = Atoms('H', cell=(2.5, 3, 3.5), pbc=1, calculator=GPAW(txt=None, mode=mode)) hydrogen.get_potential_energy() dens = hydrogen.calc.density ham = hydrogen.calc.hamiltonian ham.poisson.eps = 1e-20 dens.interpolate_pseudo_density() dens.calculate_pseudo_charge() ham.update(dens) ham.get_energy(hydrogen.calc.occupations) y = (ham.vt_sG[0, 0, 0, 0] - ham.vt_sG[0, 0, 0, 1]) * ham.gd.dv x = 0.0001 dens.nt_sG[0, 0, 0, 0] += x dens.nt_sG[0, 0, 0, 1] -= x dens.interpolate_pseudo_density() dens.calculate_pseudo_charge() ham.update(dens) e1 = ham.get_energy(hydrogen.calc.occupations) - ham.Ekin dens.nt_sG[0, 0, 0, 0] -= 2 * x dens.nt_sG[0, 0, 0, 1] += 2 * x dens.interpolate_pseudo_density() dens.calculate_pseudo_charge() ham.update(dens) e2 = ham.get_energy(hydrogen.calc.occupations) - ham.Ekin equal(y, (e1 - e2) / (2 * x), 2e-8) gpaw-0.11.0.13004/gpaw/test/lxc_fxc.py0000664000175000017500000000321712553643472017376 0ustar jensjjensj00000000000000from __future__ import print_function from gpaw.xc.libxc import LibXC from math import pi import numpy as np nspins = 1 for name in [ 'LDA', 'PBE', 'revPBE', 'RPBE', 'LDA_X', 'GGA_X_PBE_R', 'GGA_X_RPBE', 'LDA_C_PW', ]: xc = LibXC(name) xc.initialize(nspins) libxc = xc.xc lxc_fxc = libxc.calculate_fxc_spinpaired lxc_fxc_fd = libxc.calculate_fxc_fd_spinpaired na = 2.0 if nspins == 2: nb = 1.0 else: nb = 0.0 print(na, nb) if (nb > 0.0): assert (nspins == 2) if nspins == 2: sigma0 = 2.0 # (0.0, 1.0, 1.0) sigma1 = 2.0 sigma2 = 5.0 # (1.0, 2.0, 0.0) else: sigma0 = 2.0 # (0.0, 1.0, 1.0) sigma1 = 0.0 sigma2 = 0.0 taua=(3.*pi**2)**(2./3.)*na**(5./3.)/2.*sigma0 taub=(3.*pi**2)**(2./3.)*nb**(5./3.)/2.*sigma2 if ((sigma1 > 0.0) or (sigma2 > 0.0)): assert (nspins == 2) na = np.array([na]) sigma0 = np.array([sigma0]) dvdn = np.zeros((1)) dvdnda2 = np.zeros((6)) dvda2da2 = np.zeros_like(dvdnda2) dvdn_N = np.zeros_like(dvdn) dvdnda2_N = np.zeros_like(dvdnda2) dvda2da2_N = np.zeros_like(dvdnda2) lxc_fxc(na, dvdn, sigma0, dvdnda2, dvda2da2) lxc_fxc_fd(na, dvdn_N, sigma0, dvdnda2_N, dvda2da2_N) error = [0.0, 'exact'] for E in [ ('dvdn', dvdn[0], dvdn_N[0]), ('dvdnda2', dvdnda2[0], dvdnda2_N[0]), ('dvda2da2', dvda2da2[0], dvda2da2_N[0]), ]: for e in E[2:]: de = abs(e - E[1]) if de > error[0]: error[0] = de error[1] = E[0] print(name, error[0], error[1]) assert error[0] < 5.0e-7 gpaw-0.11.0.13004/gpaw/test/lebedev.py0000664000175000017500000000032112553643471017346 0ustar jensjjensj00000000000000from gpaw.sphere.lebedev import run, weight_n, Y_nL, R_nv weight0_n, Y0_nL, R0_nv = run() assert (abs(weight0_n - weight_n).sum() + abs(Y0_nL - Y_nL).sum() + abs(R0_nv - R_nv).sum()) < 1e-13 gpaw-0.11.0.13004/gpaw/test/gemm.py0000664000175000017500000000132712553643472016675 0ustar jensjjensj00000000000000from __future__ import print_function from time import time import numpy as np n = 1000 a1 = np.eye(n) a1 += 0.0001 a2 = 2 * a1 from gpaw.utilities.blas import gemm b = np.zeros((n, n)) t0 = time() gemm(1.0, a1, a2, 0.0, b) tgpaw = time() - t0 print('gpaw.gemm ', tgpaw) t0 = time() c = np.dot(a1, a2) tnumpy = time() - t0 print('numpy.dot ', tnumpy) """ SLID: gpaw.gemm 0.41842508316 numpy.dot 11.26800704 p019: gpaw.gemm 0.444674015045 numpy.dot 11.8213479519 m022: gpaw.gemm 0.446084022522 numpy.dot 11.9757530689 u091: gpaw.gemm 0.377645015717 numpy.dot 0.389540910721 CASIMIR: gpaw.gemm 2.19097900391 numpy.dot 8.21617603302 THUL: gpaw.gemm 0.520259857178 numpy.dot 0.505489110947 """ gpaw-0.11.0.13004/gpaw/test/XC2.py0000664000175000017500000000421412553643471016341 0ustar jensjjensj00000000000000from __future__ import print_function from math import pi from gpaw.atom.radialgd import EquidistantRadialGridDescriptor from gpaw.grid_descriptor import GridDescriptor from gpaw.xc import XC import numpy as np from gpaw.test import equal rgd = EquidistantRadialGridDescriptor(0.01, 100) for name in ['LDA', 'PBE']: xc = XC(name) for nspins in [1, 2]: n = rgd.zeros(nspins) v = rgd.zeros(nspins) n[:] = np.exp(-rgd.r_g**2) n[-1] *= 2 E = xc.calculate_spherical(rgd, n, v) i = 23 x = v[-1, i] * rgd.dv_g[i] n[-1, i] += 0.000001 Ep = xc.calculate_spherical(rgd, n, v) n[-1, i] -= 0.000002 Em = xc.calculate_spherical(rgd, n, v) x2 = (Ep - Em) / 0.000002 print(name, nspins, E, x, x2, x - x2) equal(x, x2, 1e-9) n[-1, i] += 0.000001 if nspins == 1: ns = rgd.empty(2) ns[:] = n / 2 Es = xc.calculate_spherical(rgd, ns, 0 * ns) equal(E, Es, 1e-13) N = 20 a = 1.0 gd = GridDescriptor((N, N, N), (a, a, a)) for name in ['LDA', 'PBE']: xc = XC(name) for nspins in [1, 2]: n = gd.empty(nspins) n.fill(0.03) z = np.arange(gd.beg_c[2], gd.end_c[2]) * a / N n[:] += 0.01 * np.sin(2 * pi * z / a) if nspins == 2: n[1] += 0.01 * np.cos(2 * pi * z / a) n /= nspins v = 0.0 * n E = xc.calculate(gd, n, v) here = (gd.beg_c[0] <= 1 < gd.end_c[0] and gd.beg_c[1] <= 2 < gd.end_c[1] and gd.beg_c[2] <= 3 < gd.end_c[2]) if here: x = v[-1, 1, 2, 3] * gd.dv n[-1, 1, 2, 3] += 0.000001 Ep = xc.calculate(gd, n, v) if here: n[-1, 1, 2, 3] -= 0.000002 Em = xc.calculate(gd, n, v) x2 = (Ep - Em) / 0.000002 if here: print(name, nspins, E, x, x2, x - x2) equal(x, x2, 1e-11) n[-1, 1, 2, 3] += 0.000001 if nspins == 1: ns = gd.empty(2) ns[:] = n / 2 Es = xc.calculate(gd, ns, 0 * ns) equal(E, Es, 1e-13) gpaw-0.11.0.13004/gpaw/test/gauss_func.py0000664000175000017500000000517612553643471020112 0ustar jensjjensj00000000000000from __future__ import print_function from math import pi, sqrt import numpy as np from gpaw.utilities.tools import coordinates from gpaw.utilities.gauss import Gaussian from gpaw.grid_descriptor import GridDescriptor from gpaw.test import equal from gpaw.mpi import world from gpaw.poisson import PoissonSolver def norm(a): return np.sqrt(np.sum(a.ravel()**2)) / len(a.ravel()) # Initialize classes a = 20 # Size of cell N = 48 # Number of grid points Nc = (N, N, N) # Number of grid points along each axis gd = GridDescriptor(Nc, (a,a,a), 0) # Grid-descriptor object solver = PoissonSolver(nn=3) # Numerical poisson solver solver.set_grid_descriptor(gd) solver.initialize() solve = solver.solve xyz, r2 = coordinates(gd) # Matrix with the square of the radial coordinate print(r2.shape) r = np.sqrt(r2) # Matrix with the values of the radial coordinate nH = np.exp(-2 * r) / pi # Density of the hydrogen atom gauss = Gaussian(gd) # An instance of Gaussian # /------------------------------------------------\ # | Check if Gaussian densities are made correctly | # \------------------------------------------------/ for gL in range(2, 9): g = gauss.get_gauss(gL) # a gaussian of gL'th order print('\nGaussian of order', gL) for mL in range(9): m = gauss.get_moment(g, mL) # the mL'th moment of g print(' %s\'th moment = %2.6f' % (mL, m)) equal(m, gL == mL, 1e-4) # Check the moments of the constructed 1s density print('\nDensity of Hydrogen atom') for L in range(4): m = gauss.get_moment(nH, L) print(' %s\'th moment = %2.6f' % (L, m)) equal(m, (L == 0) / sqrt(4 * pi), 1.5e-3) # Check that it is removed correctly v = gauss.remove_moment(nH, 0) m = gauss.get_moment(nH, 0) print('\nZero\'th moment of compensated Hydrogen density =', m) equal(m, 0., 1e-7) # /-------------------------------------------------\ # | Check if Gaussian potentials are made correctly | # \-------------------------------------------------/ # Array for storing the potential pot = gd.zeros(dtype=float, global_array=False) for L in range(7): # Angular index of gaussian # Get analytic functions ng = gauss.get_gauss(L) vg = gauss.get_gauss_pot(L) # Solve potential numerically niter = solve(pot, ng, charge=None, zero_initial_phi=True) # Determine residual residual = norm(pot - vg) residual = gd.integrate((pot - vg)**2)**0.5 # print result print('L=%s, processor %s of %s: %s'%( L, gd.comm.rank + 1, gd.comm.size, residual)) assert residual < 0.6 # mpirun -np 2 python gauss_func.py --gpaw-parallel --gpaw-debug gpaw-0.11.0.13004/gpaw/test/rpa_energy_N2.py0000664000175000017500000000260612553643471020442 0ustar jensjjensj00000000000000from __future__ import print_function from ase import * from ase.structure import molecule from gpaw import * from gpaw.test import equal from gpaw.xc.rpa import RPACorrelation from gpaw.xc.exx import EXX import numpy as np ecut = 25 N2 = molecule('N2') N2.center(vacuum=2.0) calc = GPAW(mode='pw', dtype=complex, xc='PBE', eigensolver='rmm-diis') N2.set_calculator(calc) E_n2_pbe = N2.get_potential_energy() calc.diagonalize_full_hamiltonian(nbands=104, scalapack=True) calc.write('N2.gpw', mode='all') exx = EXX('N2.gpw') exx.calculate() E_n2_hf = exx.get_total_energy() rpa = RPACorrelation('N2.gpw', nfrequencies=8) E_n2_rpa = rpa.calculate(ecut=[ecut]) #------------------------------------------------------------------------- N = molecule('N') N.set_cell(N2.cell) calc = GPAW(mode='pw', dtype=complex, xc='PBE', eigensolver='rmm-diis') N.set_calculator(calc) E_n_pbe = N.get_potential_energy() calc.diagonalize_full_hamiltonian(nbands=104, scalapack=True) calc.write('N.gpw', mode='all') exx = EXX('N.gpw') exx.calculate() E_n_hf = exx.get_total_energy() rpa = RPACorrelation('N.gpw', nfrequencies=8) E_n_rpa = rpa.calculate(ecut=[ecut]) print('Atomization energies:') print('PBE: ', E_n2_pbe - 2 * E_n_pbe) print('HF: ', E_n2_hf - 2 * E_n_hf) print('HF+RPA: ', E_n2_hf - 2 * E_n_hf + E_n2_rpa[0] - 2 * E_n_rpa[0]) equal(E_n2_rpa - 2*E_n_rpa, -1.72, 0.02) gpaw-0.11.0.13004/gpaw/test/cg.py0000664000175000017500000000160112553643471016333 0ustar jensjjensj00000000000000from ase import Atom, Atoms from gpaw import GPAW from gpaw.test import equal a = 4.05 d = a / 2**0.5 bulk = Atoms([Atom('Al', (0, 0, 0)), Atom('Al', (0.5, 0.5, 0.5))], pbc=True) bulk.set_cell((d, d, a), scale_atoms=True) h = 0.25 calc = GPAW(h=h, nbands=2*8, kpts=(2, 2, 2), convergence={'energy': 1e-5}) bulk.set_calculator(calc) e0 = bulk.get_potential_energy() niter0 = calc.get_number_of_iterations() calc = GPAW(h=h, nbands=2*8, kpts=(2, 2, 2), convergence={'energy': 1e-5}, eigensolver='cg') bulk.set_calculator(calc) e1 = bulk.get_potential_energy() niter1 = calc.get_number_of_iterations() equal(e0, e1, 4.e-5) energy_tolerance = 0.0001 niter_tolerance = 0 equal(e0, -6.97626, energy_tolerance) equal(e1, -6.97627, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/Cu.py0000664000175000017500000000176112553643471016320 0ustar jensjjensj00000000000000from __future__ import print_function import os from ase import Atoms from ase.units import Hartree from gpaw import GPAW from gpaw.test import equal, gen import gpaw.mpi as mpi # Generate non-scalar-relativistic setup for Cu: gen('Cu', scalarrel=False) a = 8.0 c = a / 2 Cu = Atoms('Cu', [(c, c, c)], magmoms=[1], cell=(a, a, a), pbc=0) calc = GPAW(h=0.2, lmax=0)# basis='sz') Cu.set_calculator(calc) e = Cu.get_potential_energy() niter = calc.get_number_of_iterations() e_4s_major = calc.get_eigenvalues(spin=0)[5] / Hartree e_3d_minor = calc.get_eigenvalues(spin=1)[4] / Hartree print(mpi.rank, e_4s_major, e_3d_minor) # # The reference values are from: # # http://physics.nist.gov/PhysRefData/DFTdata/Tables/29Cu.html # if mpi.rank == 0: print(e_4s_major - e_3d_minor, -0.184013 - -0.197109) assert abs(e_4s_major - e_3d_minor - (-0.184013 - -0.197109)) < 0.001 print(e, niter) energy_tolerance = 0.0005 niter_tolerance = 0 equal(e, -0.271504, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/restart_band_structure.py0000664000175000017500000000350012553643471022532 0ustar jensjjensj00000000000000from __future__ import print_function from gpaw import GPAW, restart, FermiDirac, PoissonSolver from ase import Atoms from gpaw.test import equal, gen import os from gpaw.mpi import world gen('Si', xcname='GLLBSC') e = {} niter = {} energy_tolerance = 0.0001 niter_tolerance = 0 e_ref = {'LDA': {'restart': -5.5728768784094758}, 'GLLBSC': {'restart': -5.4458036264351}} # svnversion 5252 niter_ref = {'LDA': {'restart': 16}, 'GLLBSC': {'restart': 16}} # svnversion 5252 for xc in ['LDA','GLLBSC']: a = 4.23 bulk = Atoms('Si2', cell=(a, a, a), pbc=True, scaled_positions=[[0, 0, 0], [0.5, 0.5, 0.5]]) calc = GPAW(h=0.25, nbands=8, poissonsolver=PoissonSolver(nn='M'), occupations=FermiDirac(width=0.01), kpts=(3, 3, 3), convergence={'eigenstates': 9.2e-11, 'bands': 8}, xc=xc, eigensolver='cg') bulk.set_calculator(calc) e[xc] = {'direct': bulk.get_potential_energy()} niter[xc] = {'direct': calc.get_number_of_iterations()} print(calc.get_ibz_k_points()) old_eigs = calc.get_eigenvalues(kpt=3) calc.write('Si_gs.gpw') del bulk del calc bulk, calc = restart('Si_gs.gpw', fixdensity=True, kpts=[[0, 0, 0], [1.0 / 3, 1.0 / 3, 1.0 / 3]]) e[xc] = {'restart': bulk.get_potential_energy()} niter[xc] = {'restart': calc.get_number_of_iterations()} if world.rank == 0: os.remove('Si_gs.gpw') diff = calc.get_eigenvalues(kpt=1)[:6]-old_eigs[:6] if world.rank == 0: print("occ. eig. diff.", diff) error = max(abs(diff)) assert error < 5e-6 for mode in e[xc].keys(): equal(e[xc][mode], e_ref[xc][mode], energy_tolerance) gpaw-0.11.0.13004/gpaw/test/aluminum_EELS_RPA.py0000664000175000017500000000371112553643472021110 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np import sys import os import time from ase.units import Bohr from ase.lattice import bulk from ase.utils import devnull from gpaw import GPAW, PW from gpaw.test import findpeak from gpaw.atom.basis import BasisMaker from gpaw.response.df import DielectricFunction from gpaw.mpi import serial_comm, rank, size, world from gpaw.wavefunctions.pw import PW if rank != 0: sys.stdout = devnull assert size <= 4**3 # Ground state calculation t1 = time.time() a = 4.043 atoms = bulk('Al', 'fcc', a=a) atoms.center() calc = GPAW(mode=PW(200), kpts=(4,4,4), parallel={'band':1}, idiotproof=False, # allow uneven distribution of k-points xc='LDA') atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('Al', 'all') t2 = time.time() # Excited state calculation q = np.array([1/4.,0.,0.]) w = np.linspace(0, 24, 241) df = DielectricFunction(calc='Al', frequencies=w, eta=0.2, ecut=50, hilbert=False) df.get_eels_spectrum(xc='RPA', filename='EELS_Al', q_c=q) #df.check_sum_rule() #df.write('Al.pckl') t3 = time.time() print('') print('For ground state calc, it took', (t2 - t1) / 60, 'minutes') print('For excited state calc, it took', (t3 - t2) / 60, 'minutes') world.barrier() d = np.loadtxt('EELS_Al',delimiter=',') # New results are compared with test values wpeak1,Ipeak1 = findpeak(d[:,0],d[:,1]) wpeak2,Ipeak2 = findpeak(d[:,0],d[:,2]) test_wpeak1 = 15.7064968875 # eV test_Ipeak1 = 29.0721098689 # eV test_wpeak2 = 15.728889329 # eV test_Ipeak2 = 26.4625750021 # eV if np.abs(test_wpeak1-wpeak1)<1e-2 and np.abs(test_wpeak2-wpeak2)<1e-2: pass else: print(test_wpeak1-wpeak1,test_wpeak2-wpeak2) raise ValueError('Plasmon peak not correct ! ') if abs(test_Ipeak1 - Ipeak1) > 1 or abs(test_Ipeak2 - Ipeak2) > 1: print((Ipeak1 - test_Ipeak1, Ipeak2 - test_Ipeak2)) raise ValueError('Please check spectrum strength ! ') gpaw-0.11.0.13004/gpaw/test/exx_unocc.py0000664000175000017500000000350112553643471017736 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atoms from ase.parallel import parprint from ase.utils.timing import Timer from gpaw import GPAW from gpaw.test import equal from gpaw.xc.hybrid import HybridXC timer = Timer() loa = Atoms('Be2', [(0, 0, 0), (2.45, 0, 0)], cell=[5.9, 4.8, 5.0]) loa.center() txt = None xc = 'PBE0' nbands = 4 unocc = True load = False # usual calculation fname = 'Be2.gpw' if not load: xco = HybridXC(xc) cocc = GPAW(h=0.3, eigensolver='rmm-diis', xc=xco, nbands=nbands, convergence={'eigenstates': 1e-4}, txt=txt) cocc.calculate(loa) else: cocc = GPAW(fname) cocc.converge_wave_functions() fo_n = 1. * cocc.get_occupation_numbers() eo_n = 1. * cocc.get_eigenvalues() if unocc: # apply Fock opeartor also to unoccupied orbitals xcu = HybridXC(xc, unocc=True) cunocc = GPAW(h=0.3, eigensolver='rmm-diis', xc=xcu, nbands=nbands, convergence={'eigenstates': 1e-4}, txt=txt) cunocc.calculate(loa) parprint(' HF occ HF unocc diff') parprint('Energy %10.4f %10.4f %10.4f' % (cocc.get_potential_energy(), cunocc.get_potential_energy(), cocc.get_potential_energy() - cunocc.get_potential_energy() )) equal(cocc.get_potential_energy(), cunocc.get_potential_energy(), 1.e-4) fu_n = cunocc.get_occupation_numbers() eu_n = cunocc.get_eigenvalues() parprint('Eigenvalues:') for eo, fo, eu, fu in zip(eo_n, fo_n, eu_n, fu_n): parprint('%8.4f %5.2f %8.4f %5.2f %8.4f' % (eo, fo, eu, fu, eu - eo)) if fo > 0.01: equal(eo, eu, 3.5e-4) gpaw-0.11.0.13004/gpaw/test/zher.py0000664000175000017500000000150512553643471016715 0ustar jensjjensj00000000000000from __future__ import print_function from gpaw.utilities.blas import czher, axpy import numpy as np from time import time alpha = 0.5 x = np.random.rand(3) + 1j * np.random.rand(3) a = np.random.rand(9).reshape(3,3) + np.random.rand(9).reshape(3,3) * 1j # make a hermitian for i in range(3): for j in range(3): a[i,j] = a[j,i].conj() a[i,i] = np.real(a[i,i]) b = alpha * np.outer(x.conj(), x) + a czher(alpha, x, a) for i in range(3): for j in range(i,3): a[j,i] = a[i,j].conj() assert np.abs(b-a).sum() < 1e-14 # testing speed t_czher = 0 t_axpy = 0 for i in np.arange(1000): t0 = time() czher(alpha, x, a) t_czher += time() - t0 t0 = time() xx = np.outer(x.conj(), x) axpy(alpha, xx, a) t_axpy += time() - t0 print('t_czher:', t_czher) print('t_axpy:', t_axpy) gpaw-0.11.0.13004/gpaw/test/lcao_dos.py0000664000175000017500000000264612553643471017537 0ustar jensjjensj00000000000000# Check that the LCAODOS works. from gpaw import GPAW from ase.structure import molecule #import pylab as pl system = molecule('H2O') system.center(vacuum=3.0) system.pbc = 1 calc = GPAW(mode='lcao', basis='dzp', h=0.3, xc='oldLDA', kpts=[2, 1, 1], #parallel=dict(sl_auto=True), nbands=8, #kpts=[4, 4, 4] ) system.set_calculator(calc) system.get_potential_energy() from gpaw.utilities.dos import LCAODOS, fold # Use RestartLCAODOS if you just restarted from a file. # Requires one diagonalization though! lcaodos = LCAODOS(calc) def printdos(eps, w): print('sum of weights', sum(w)) print('energy, weight') for e0, w0 in zip(eps, w): print(e0, w0) print('-----') eps0, w0 = lcaodos.get_orbital_pdos(0) # O 2s printdos(eps0, w0) assert w0[0] > 1.6 # s state on which we projected with two electrons. assert (w0[1:] < 0.2).all(), w0 # There is another s with some weight ~ 0.16. #eps1_n, w1_n = fold(eps * 27.211, w, 600, 0.1) #pl.plot(eps1, w1) #pl.show() #for e0, w0 in zip(eps, w): # print e0, w0 #print eps.shape #print w.shape a1 = [0, 1, 2] eps1, w1 = lcaodos.get_atomic_subspace_pdos(a1) assert abs(2 * len(eps1) - sum(w1)) < 0.01 printdos(eps1, w1) print('indices %s' % lcaodos.get_atom_indices(a1)) a2 = 0 # all BFs on the O atom eps2, w2 = lcaodos.get_atomic_subspace_pdos(a2) printdos(eps2, w2) print('indices %s' % lcaodos.get_atom_indices(a2)) gpaw-0.11.0.13004/gpaw/test/blas.py0000664000175000017500000000352012553643471016665 0ustar jensjjensj00000000000000import numpy as np from gpaw.utilities.blas import \ gemm, axpy, r2k, rk, gemmdot, rotate, dotc, dotu from gpaw.utilities.tools import tri2full a = np.arange(5 * 7).reshape(5, 7) + 4. a2 = np.arange(3 * 7).reshape(3, 7) + 3. b = np.arange(7) - 2. # Check gemmdot with floats assert np.all(np.dot(a, b) == gemmdot(a, b)) assert np.all(np.dot(a, a2.T) == gemmdot(a, a2, trans='t')) assert np.all(np.dot(a, a2.T) == gemmdot(a, a2, trans='c')) assert np.dot(b, b) == gemmdot(b, b) # Check gemmdot with complex arrays a = a * (2 + 1.j) a2 = a2 * (-1 + 3.j) b = b * (3 - 2.j) assert np.all(np.dot(a, b) == gemmdot(a, b)) assert np.all(np.dot(a, a2.T) == gemmdot(a, a2, trans='t')) assert np.all(np.dot(a, a2.T.conj()) == gemmdot(a, a2, trans='c')) assert np.dot(b, b) == gemmdot(b, b, trans='n') assert np.dot(b, b.conj()) == gemmdot(b, b, trans='c') assert np.vdot(a, 5.j * a) == dotc(a, 5.j * a) # Check gemm for transa='n' a2 = np.arange(7 * 5 * 1 * 3).reshape(7, 5, 1, 3) * (-1. + 4.j) + 3. c = np.tensordot(a, a2, [1, 0]) gemm(1., a2, a, -1., c, 'n') assert not c.any() # Check gemm for transa='c' a = np.arange(4 * 5 * 1 * 3).reshape(4, 5, 1, 3) * (3. - 2.j) + 4. c = np.tensordot(a, a2.conj(), [[1, 2, 3], [1, 2, 3]]) gemm(1., a2, a, -1., c, 'c') assert not c.any() # Check axpy c = 5.j * a axpy(-5.j, a, c) assert not c.any() # Check rk c = np.tensordot(a, a.conj(), [[1, 2, 3], [1, 2, 3]]) rk(1., a, -1., c) tri2full(c) assert not c.any() # Check gemmdot for transa='c' c = np.tensordot(a, a2.conj(), [-1, -1]) gemmdot(a, a2, beta=-1., out=c, trans='c') assert not c.any() # Check gemmdot for transa='n' a2.shape = 3, 7, 5, 1 c = np.tensordot(a, a2, [-1, 0]) gemmdot(a, a2, beta=-1., out=c, trans='n') assert not c.any() # Check r2k a2 = 5. * a c = np.tensordot(a, a2.conj(), [[1, 2, 3], [1, 2, 3]]) r2k(.5, a, a2, -1., c) tri2full(c) assert not c.any() gpaw-0.11.0.13004/gpaw/test/excited_state.py0000664000175000017500000000334512553643471020576 0ustar jensjjensj00000000000000import os import sys import time from ase.units import Bohr from ase import Atom, Atoms from ase.parallel import parprint from gpaw import GPAW from gpaw.mpi import world from gpaw.test import equal from gpaw.lrtddft import LrTDDFT from gpaw.lrtddft.excited_state import ExcitedState txt='-' txt='/dev/null' R=0.7 # approx. experimental bond length a = 3.0 c = 4.0 H2 = Atoms([Atom('H', (a / 2, a / 2, (c - R) / 2)), Atom('H', (a / 2, a / 2, (c + R) / 2))], cell=(a, a, c)) calc = GPAW(xc='PBE', h=0.25, nbands=3, spinpol=False, txt=txt) H2.set_calculator(calc) xc='LDA' lr = LrTDDFT(calc, xc=xc) # excited state with forces accuracy = 0.015 exst = ExcitedState(lr, 0, d=0.01, parallel=2, txt=sys.stdout, ) t0 = time.time() parprint("########### first call to forces --> calculate") forces = exst.get_forces(H2) parprint("time used:", time.time() - t0) for c in range(2): equal(forces[0,c], 0.0, accuracy) equal(forces[1,c], 0.0, accuracy) equal(forces[0, 2] + forces[1, 2], 0.0, accuracy) parprint("########### second call to potential energy --> just return") t0 = time.time() E = exst.get_potential_energy() parprint("E=", E) parprint("time used:", time.time() - t0) t0 = time.time() E = exst.get_potential_energy(H2) parprint("E=", E) parprint("time used:", time.time() - t0) parprint("########### second call to forces --> just return") t0 = time.time() exst.get_forces() parprint("time used:", time.time() - t0) t0 = time.time() exst.get_forces(H2) parprint("time used:", time.time() - t0) parprint("########### moved atoms, call to forces --> calculate") p = H2.get_positions() p[1, 1] += 0.1 H2.set_positions(p) t0 = time.time() exst.get_forces(H2) parprint("time used:", time.time() - t0) gpaw-0.11.0.13004/gpaw/test/aluminum_EELS_ALDA.py0000664000175000017500000000366412553643471021175 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np import sys import os import time from ase.units import Bohr from ase.lattice import bulk from ase.utils import devnull from gpaw import GPAW, PW from gpaw.test import findpeak from gpaw.atom.basis import BasisMaker from gpaw.response.df import DielectricFunction from gpaw.mpi import serial_comm, rank, size, world from gpaw.wavefunctions.pw import PW if rank != 0: sys.stdout = devnull assert size <= 4**3 # Ground state calculation t1 = time.time() a = 4.043 atoms = bulk('Al', 'fcc', a=a) atoms.center() calc = GPAW(mode=PW(200), kpts=(4,4,4), parallel={'band':1}, idiotproof=False, # allow uneven distribution of k-points xc='LDA') atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('Al', 'all') t2 = time.time() # Excited state calculation q = np.array([1/4.,0.,0.]) w = np.linspace(0, 24, 241) df = DielectricFunction(calc='Al', frequencies=w, eta=0.2, ecut=50, hilbert=False) df.get_eels_spectrum(xc='ALDA', filename='EELS_Al_ALDA',q_c=q) #df.check_sum_rule() #df.write('Al.pckl') t3 = time.time() print('For ground state calc, it took', (t2 - t1) / 60, 'minutes') print('For excited state calc, it took', (t3 - t2) / 60, 'minutes') world.barrier() d = np.loadtxt('EELS_Al_ALDA',delimiter=',') # New results are compared with test values wpeak1,Ipeak1 = findpeak(d[:,0],d[:,1]) wpeak2,Ipeak2 = findpeak(d[:,0],d[:,2]) test_wpeak1 = 15.4929666813 # eV test_Ipeak1 = 29.644489594 test_wpeak2 = 15.5196459206 # eV test_Ipeak2 = 26.5680624522 if abs(test_wpeak1 - wpeak1) > 0.02 or abs(test_wpeak2 - wpeak2) > 0.02: print((test_wpeak1 - wpeak1, test_wpeak2 - wpeak2)) raise ValueError('Plasmon peak not correct ! ') if abs(test_Ipeak1-Ipeak1) > 1 or abs(test_Ipeak2 - Ipeak2) > 1: print((Ipeak1 - test_Ipeak1, Ipeak2 - test_Ipeak2)) raise ValueError('Please check spectrum strength ! ') gpaw-0.11.0.13004/gpaw/test/bulk.py0000664000175000017500000000160012553643471016676 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atom, Atoms from gpaw import GPAW from gpaw.test import equal import numpy as np bulk = Atoms([Atom('Li')], pbc=True) k = 4 g = 8 calc = GPAW(gpts=(g, g, g), kpts=(k, k, k), nbands=2)#, txt=None) bulk.set_calculator(calc) a = np.linspace(2.6, 2.8, 5) e = [] for x in a: bulk.set_cell((x, x, x)) e1 = bulk.get_potential_energy() niter1 = calc.get_number_of_iterations() e.append(e1) try: from gpaw.io.etsf import ETSFWriter except ImportError: pass # Scientific.IO.NetCDF was not installed else: if calc.wfs.world.size == 1: ETSFWriter().write(calc) fit = np.polyfit(a, e, 2) a0 = np.roots(np.polyder(fit, 1))[0] e0 = np.polyval(fit, a0) print('a,e =', a0, e0) equal(a0, 2.64124, 0.0001) equal(e0, -1.98351, 0.00002) energy_tolerance = 0.00002 niter_tolerance = 0 equal(e1, -1.96157, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/lcao_pair_and_coulomb.py0000664000175000017500000000403312553643471022237 0ustar jensjjensj00000000000000import numpy as np import pickle from ase.structure import molecule from gpaw.lcao.tools import makeU, makeV from gpaw import GPAW, FermiDirac, restart from gpaw.lcao.pwf2 import LCAOwrap from gpaw.mpi import world, rank, MASTER, serial_comm from gpaw.test import equal scat = range(2) atoms = molecule('H2') atoms.set_cell([6.4, 6.4, 6.4]) atoms.center() calc = GPAW(mode='lcao', occupations=FermiDirac(0.1)) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('lcao_pair.gpw') if rank == MASTER: atoms, calc = restart('lcao_pair.gpw', txt=None, communicator=serial_comm) lcao = LCAOwrap(calc) fermi = calc.get_fermi_level() H = lcao.get_hamiltonian() S = lcao.get_overlap() pickle.dump((H, S), open('lcao_pair_hs.pckl', 'wb'), 2) symbols = atoms.get_chemical_symbols() #indices = get_bfi2(symbols, basis, scat) indices = range(2) lcao.get_xc(indices=indices).dump('lcao_pair_xc.pckl') lcao.get_Fcore(indices=indices).dump('lcao_pair_Fcore.pckl') w_wG = lcao.get_orbitals(indices=indices) P_awi = lcao.get_projections(indices=indices) pickle.dump((w_wG, P_awi), open('lcao_pair_w_wG__P_awi.pckl', 'wb'), 2) world.barrier() makeU('lcao_pair.gpw', 'lcao_pair_w_wG__P_awi.pckl', 'lcao_pair_eps_q__U_pq.pckl', 1.0e-5, dppname='lcao_pair_D_pp.pckl') world.barrier() makeV('lcao_pair.gpw', 'lcao_pair_w_wG__P_awi.pckl', 'lcao_pair_eps_q__U_pq.pckl', 'lcao_pair_V_qq.pckl', 'lcao_pair_V_qq.log', False) world.barrier() V_qq = np.load('lcao_pair_V_qq.pckl') eps_q, U_pq = np.load('lcao_pair_eps_q__U_pq.pckl') assert U_pq.flags.contiguous Usq_pq = U_pq * np.sqrt(eps_q) V_pp = np.dot(np.dot(Usq_pq, V_qq), Usq_pq.T.conj()) V_pp_ref = np.array( [[ 15.34450177, 11.12669608, 11.12669608, 12.82934563], [ 11.12669608, 8.82280293, 8.82280293, 11.12669608], [ 11.12669608, 8.82280293, 8.82280293, 11.12669608], [ 12.82934563, 11.12669608, 11.12669608, 15.34450178]]) equal(abs(V_pp_ref-V_pp).max(), 0.0, 1.0e-5) gpaw-0.11.0.13004/gpaw/test/cmrtest/0000775000175000017500000000000012553644063017051 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/cmrtest/cmr_test4.py0000664000175000017500000000240112553643471021326 0ustar jensjjensj00000000000000# This test makes sure that the i/o interfaces work with CMR. # CMR itself does not have to be installed for this test. # # The reason why CMR cannot use direct writes to DB/GPAW files is that # GPAW cannot always write a GPAW without performing a new calculation e.g. # GPAW(filename).write(...) # fails in some rare cases. import os from ase import Atom, Atoms from ase.calculators.emt import EMT import warnings # cmr calls all available methods in ase.atoms detected by the module inspect. # Therefore also deprecated methods are called - and we choose to silence those warnings. warnings.filterwarnings('ignore', 'ase.atoms.*deprecated',) import cmr # from cmr.tools.log import Log # cmr.logger.set_message_selection(Log.MSG_TYPE_ALL) a = 4.05 d = a / 2 ** 0.5 bulk = Atoms([Atom('Al', (0, 0, 0)), Atom('Al', (0.5, 0.5, 0.5))], pbc=True) bulk.set_cell((d, d, a), scale_atoms=True) h = 0.3 bulk.set_calculator(EMT()) e0 = bulk.get_potential_energy() bulk.write("cmr_test4.traj") bulk.write("cmr_test4a.cmr") cmr.convert({"input":"cmr_test4.traj", "output":"cmr_test4.cmr"}) data = cmr.read("cmr_test4.cmr") data.dump() group = cmr.create_group() group.add(data) group.write("cmr_group4.cmr") g = cmr.read("cmr_group4.cmr") g.dump_all() gpaw-0.11.0.13004/gpaw/test/cmrtest/cmr_test3.py0000664000175000017500000000243112553643471021330 0ustar jensjjensj00000000000000# This test makes sure that the i/o interfaces work with CMR. # CMR itself does not have to be installed for this test. # # The reason why CMR cannot use direct writes to DB/GPAW files is that # GPAW cannot always write a GPAW without performing a new calculation e.g. # GPAW(filename).write(...) # fails in some rare cases. import os from ase import Atom, Atoms import gpaw.io from gpaw import GPAW from gpaw.test import equal from gpaw.mpi import world, rank import warnings # cmr calls all available methods in ase.atoms detected by the module inspect. # Therefore also deprecated methods are called - and we choose to silence those warnings. warnings.filterwarnings('ignore', 'ase.atoms.*deprecated',) import cmr # from cmr.tools.log import Log # cmr.logger.set_message_selection(Log.MSG_TYPE_ALL) a = 4.05 d = a / 2 ** 0.5 bulk = Atoms([Atom('Al', (0, 0, 0)), Atom('Al', (0.5, 0.5, 0.5))], pbc=True) bulk.set_cell((d, d, a), scale_atoms=True) h = 0.18 calc = GPAW(h=h, nbands=2 * 8, kpts=(2, 2, 2), convergence={'energy': 1e-5}) bulk.set_calculator(calc) e0 = bulk.get_potential_energy() calc.write("cmr_test3.gpw") cmr.convert({"input":"cmr_test3.gpw", "output":"cmr_test3.cmr"}) data = cmr.read("cmr_test3.cmr") data.dump() gpaw-0.11.0.13004/gpaw/test/cmrtest/cmr_test2.py0000664000175000017500000000262712553643471021336 0ustar jensjjensj00000000000000# This test makes sure that the i/o interfaces work with CMR. # CMR itself does not have to be installed for this test. # # The reason why CMR cannot use direct writes to DB/GPAW files is that # GPAW cannot always write a GPAW without performing a new calculation e.g. # GPAW(filename).write(...) # fails in some rare cases. import os from ase import Atom, Atoms import gpaw.io from gpaw import GPAW from gpaw.test import equal from gpaw.mpi import world, rank import warnings # cmr calls all available methods in ase.atoms detected by the module inspect. # Therefore also deprecated methods are called - and we choose to silence those warnings. warnings.filterwarnings('ignore', 'ase.atoms.*deprecated',) a = 4.05 d = a / 2 ** 0.5 bulk = Atoms([Atom('Al', (0, 0, 0)), Atom('Al', (0.5, 0.5, 0.5))], pbc=True) bulk.set_cell((d, d, a), scale_atoms=True) h = 0.18 calc = GPAW(h=h, nbands=2 * 8, kpts=(2, 2, 2), convergence={'energy': 1e-5}) bulk.set_calculator(calc) e0 = bulk.get_potential_energy() calc.write("cmr_test2.gpw") assert os.path.exists("cmr_test2.gpw") reader = gpaw.io.open("cmr_test2.gpw", 'r') w = {} for key in reader.parameters: w[key] = reader.parameters[key] for key in reader.shapes: w[key] = reader.get(key) for key in reader.dims: w[key] = reader.dims[key] world.barrier() if rank == 0: os.unlink("cmr_test2.gpw") gpaw-0.11.0.13004/gpaw/test/cmrtest/Li2_atomize.py0000664000175000017500000002401012553643471021600 0ustar jensjjensj00000000000000from __future__ import print_function import os from ase.structure import molecule from ase.io import read, write from ase.parallel import rank from gpaw import GPAW, restart import warnings # cmr calls all available methods in ase.atoms detected by the module inspect. # Therefore also deprecated methods are called - and we choose to silence those warnings. warnings.filterwarnings('ignore', 'ase.atoms.*deprecated',) import cmr #from cmr.tools.log import Log #cmr.logger.set_message_selection(Log.MSG_TYPE_ALL) calculate = True recalculate = True analyse_from_dir = True # analyse local cmr files upload_to_db = False # upload cmr files to the database analyse_from_db = False # analyse database create_group = True # group calculations beloging to a given reaction clean = False if create_group: assert analyse_from_dir or analyse_from_db if analyse_from_db: assert upload_to_db symbol = 'Li' # define the project in order to find it in the database! project_id = 'my first project: atomize' vacuum = 3.5 # calculator parameters xc = 'LDA' mode = 'lcao' h = 0.20 cmr_params_template = { 'db_keywords': [project_id], # add project_id also as a field to support search across projects 'project_id': project_id, # user's tags 'U_vacuum': vacuum, 'U_xc': xc, 'U_mode': mode, 'U_h': h, } if calculate: # molecule formula = symbol + '2' # set formula name to be written into the cmr file cmr_params = cmr_params_template.copy() cmr_params['U_formula'] = formula cmrfile = formula + '.cmr' system = molecule(formula) system.center(vacuum=vacuum) # Note: Molecules do not need broken cell symmetry! if 0: system.cell[1, 1] += 0.01 system.cell[2, 2] += 0.02 # Hund rule (for atoms) hund = (len(system) == 1) cmr_params['U_hund'] = hund # first calculation: LDA lcao calc = GPAW(mode=mode, xc=xc, h=h, hund=hund, txt=formula + '.txt') system.set_calculator(calc) e = system.get_potential_energy() # write gpw file calc.write(formula) # add total energy to users tags cmr_params['U_potential_energy'] = e # write the information 'as in' corresponding trajectory file # plus cmr_params into cmr file write(cmrfile, system, cmr_params=cmr_params) del calc # atom formula = symbol # set formula name to be written into the cmr file cmr_params = cmr_params_template.copy() cmr_params['U_formula'] = formula cmrfile = formula + '.cmr' system = molecule(formula) system.center(vacuum=vacuum) # Note: Li does not need broken cell symmetry! Many other atoms do! if 0: system.cell[1, 1] += 0.01 system.cell[2, 2] += 0.02 # Hund rule (for atoms) hund = (len(system) == 1) cmr_params['U_hund'] = hund # first calculation: LDA lcao calc = GPAW(mode=mode, xc=xc, h=h, hund=hund, txt=formula + '.txt') system.set_calculator(calc) e = system.get_potential_energy() # write gpw file calc.write(formula) # add total energy to users tags cmr_params['U_potential_energy'] = e # write the information 'as in' corresponding trajectory file # plus cmr_params into cmr file write(cmrfile, system, cmr_params=cmr_params) del calc if recalculate: # now calculate PBE energies on LDA orbitals # molecule formula = symbol + '2' system, calc = restart(formula, txt=None) ediff = calc.get_xc_difference('PBE') cmrfile = formula + '.cmr' # add new results to the cmrfile data = cmr.read(cmrfile) data.set_user_variable('U_potential_energy_PBE', data['U_potential_energy'] + ediff) data.write(cmrfile) del calc # atom formula = symbol system, calc = restart(formula, txt=None) ediff = calc.get_xc_difference('PBE') cmrfile = formula + '.cmr' # add new results to the cmrfile data = cmr.read(cmrfile) data.set_user_variable('U_potential_energy_PBE', data['U_potential_energy'] + ediff) data.write(cmrfile) del calc if analyse_from_dir: # analyze the results from cmr files in the local directory from cmr.ui import DirectoryReader # read all compounds in the project with lcao and LDA orbitals reader = DirectoryReader(directory='.', ext='.cmr') all = reader.find(name_value_list=[('U_mode', 'lcao'), ('U_xc', 'LDA')], keyword_list=[project_id]) if rank == 0: print('results from cmr files in the local directory') # print requested results # column_length=0 aligns data in the table (-1 : data unaligned is default) all.print_table(column_length=0, columns=['U_formula', 'U_vacuum', 'U_xc', 'U_h', 'U_hund', 'U_potential_energy', 'U_potential_energy_PBE', 'ase_temperature']) # access the results directly and calculate atomization energies f2 = symbol + '2' f1 = symbol if rank == 0: # results are accesible only on master rank r2 = all.get('U_formula', f2) r1 = all.get('U_formula', f1) # calculate atomization energies (ea) ea_LDA = 2 * r1['U_potential_energy'] - r2['U_potential_energy'] ea_PBE = 2 * r1['U_potential_energy_PBE'] - r2['U_potential_energy_PBE'] print('atomization energy [eV] ' + xc + ' = ' + str(ea_LDA)) print('atomization energy [eV] PBE = ' + str(ea_PBE)) if create_group: # ea_LDA and ea_PBE define a group group = cmr.create_group(); group.add(r1['db_hash']); group.add(r2['db_hash']); group.set_user_variable('U_ea_LDA', ea_LDA) group.set_user_variable('U_ea_PBE', ea_PBE) group.set_user_variable('U_description', 'atomization energy [eV]') group.set_user_variable('U_reaction', '2 * ' + symbol + ' - ' + symbol + '2') group.set_user_variable('db_keywords', [project_id]) group.set_user_variable('project_id', project_id) group.write(symbol + '2_atomize_from_dir.cmr'); if True: all = reader.find(keyword_list=[project_id]) if rank == 0: print('contents of the cmr files present in the local directory') # print requested results # column_length=0 aligns data in the table (-1 : data unaligned is default) all.print_table(column_length=0, columns=['U_formula', 'U_vacuum', 'U_xc', 'U_h', 'U_hund', 'U_potential_energy', 'U_potential_energy_PBE', 'ase_temperature', 'U_reaction', 'U_ea_LDA', 'U_ea_PBE', 'U_description']) if upload_to_db: # upload cmr files to the database if rank == 0: os.system('cmr --commit ' + symbol + '*.cmr') if analyse_from_db: # analyze the results from the database # analysis can only be performed on rank 0!! from cmr.ui import DBReader reader = DBReader() all = reader.find(name_value_list=[('U_mode', 'lcao'), ('U_xc', 'LDA'), #('db_user', '') ], keyword_list=[project_id]) if rank == 0: print('results from the database') # print requested results # column_length=0 aligns data in the table (-1 : data unaligned is default) all.print_table(column_length=0, columns=['U_formula', 'U_vacuum', 'U_xc', 'U_h', 'U_hund', 'U_potential_energy', 'U_potential_energy_PBE', 'ase_temperature']) # access the results directly and calculate atomization energies f2 = symbol + '2' f1 = symbol # results are accesible only on master rank r1 = all.get('U_formula', f1) r2 = all.get('U_formula', f2) # check if results were successfully retrieved, otherwise we have to wait if r1 is None or r2 is None: print("Results are not yet in the database. Wait, and try again.") else: # calculate atomization energies (ea) ea_LDA = 2 * r1['U_potential_energy'] - r2['U_potential_energy'] ea_PBE = 2 * r1['U_potential_energy_PBE'] - r2['U_potential_energy_PBE'] if rank == 0: print('atomization energy [eV] ' + xc + ' = ' + str(ea_LDA)) print('atomization energy [eV] PBE = ' + str(ea_PBE)) if create_group: # ea_LDA and ea_PBE define a group group = cmr.create_group(); group.add(r1['db_hash']); group.add(r2['db_hash']); group.set_user_variable('U_ea_LDA', ea_LDA) group.set_user_variable('U_ea_PBE', ea_PBE) group.set_user_variable('U_description', 'atomization energy [eV] (from database)') group.set_user_variable('U_reaction', '2 * ' + symbol + ' - ' + symbol + '2') group.set_user_variable('db_keywords', [project_id]) group.set_user_variable('project_id', project_id) group.write(symbol + '2_atomize_from_db.cmr'); group.write(".cmr"); if True: all = reader.find(keyword_list=[project_id]) if rank == 0: print('contents of the database') # print requested results # column_length=0 aligns data in the table (-1 : data unaligned is default) all.print_table(column_length=0, columns=['U_formula', 'U_vacuum', 'U_xc', 'U_h', 'U_hund', 'U_potential_energy', 'U_potential_energy_PBE', 'ase_temperature', 'U_reaction', 'U_ea_LDA', 'U_ea_PBE', 'U_description']) if clean: if rank == 0: for file in [symbol + '.cmr', symbol + '.gpw', symbol + '.txt', symbol + '2.cmr', symbol + '2.gpw', symbol + '2.txt', symbol + '2_atomize_from_dir.cmr', symbol + '2_atomize_from_db.cmr']: if os.path.exists(file): os.unlink(file) gpaw-0.11.0.13004/gpaw/test/cmrtest/cmr_append.py0000664000175000017500000000543612553643471021545 0ustar jensjjensj00000000000000# this example shows how to append new calculated results to an already # existing cmr file, illustrated for calculation of PBE energy on LDA density import os from ase.structure import molecule from ase.io import read, write from ase.parallel import barrier, rank from gpaw import GPAW, restart from gpaw.test import equal import warnings # cmr calls all available methods in ase.atoms detected by the module inspect. # Therefore also deprecated methods are called - and we choose to silence those warnings. warnings.filterwarnings('ignore', 'ase.atoms.*deprecated',) import cmr # from cmr.tools.log import Log # cmr.logger.set_message_selection(Log.MSG_TYPE_ALL) # define the project in order to find it in the database! project_id = 'modify cmr file after gpw restart' formula = 'H2' vacuum = 2.0 xc = 'LDA' mode = 'lcao' h = 0.20 cmr_params = { 'db_keywords': [project_id], # add project_id also as a field to support search across projects 'project_id': project_id, # user's tags: xc tag will be set later for illustration purpose! 'formula': formula, 'vacuum': vacuum, 'mode': mode, 'h': h, } cmrfile = formula + '.cmr' system1 = molecule(formula) system1.center(vacuum=vacuum) # first calculation: LDA lcao calc = GPAW(mode=mode, xc=xc, h=h, txt=None) system1.set_calculator(calc) e = system1.get_potential_energy() calc.write(formula) # read gpw file system2, calc2 = restart(formula, txt=None) # write the information 'as in' gpw file into db file # (called *db to avoid conflict with the *cmr file below) if 1: # not used in this example calc2.write(formula + '.db', cmr_params=cmr_params) # write the information 'as in' corresponding trajectory file into cmr file write(cmrfile, system2, cmr_params=cmr_params) # add the xc tag to the cmrfile data = cmr.read(cmrfile) data.set_user_variable('xc', xc) data.write(cmrfile) # perform PBE calculation on LDA density ediff = calc2.get_xc_difference('PBE') # add new results to the cmrfile data = cmr.read(cmrfile) data.set_user_variable('PBE', data['ase_potential_energy'] + ediff) data.write(cmrfile) # analyze the results with CMR from cmr.ui import DirectoryReader reader = DirectoryReader(directory='.', ext='.cmr') # read all compounds in the project with lcao all = reader.find(name_value_list=[('mode', 'lcao')], keyword_list=[project_id]) results = all.get('formula', formula) print(results['formula'], results['xc'], results['ase_potential_energy']) # column_length=0 aligns data in the table (-1 : data unaligned is default) all.print_table(column_length=0, columns=['formula', 'xc', 'h', 'ase_potential_energy', 'PBE']) equal(results['PBE'], e + ediff, 1e-6) if rank == 0: for file in [formula + '.gpw', formula + '.db', cmrfile]: if os.path.exists(file): os.unlink(file) gpaw-0.11.0.13004/gpaw/test/cmrtest/cmr_test.py0000664000175000017500000000234112553643471021245 0ustar jensjjensj00000000000000import os from ase import Atom, Atoms from gpaw import GPAW from gpaw.test import equal import warnings # cmr calls all available methods in ase.atoms detected by the module inspect. # Therefore also deprecated methods are called - and we choose to silence those warnings. warnings.filterwarnings('ignore', 'ase.atoms.*deprecated',) import cmr # from cmr.tools.log import Log # cmr.logger.set_message_selection(Log.MSG_TYPE_ALL) a = 4.05 d = a / 2 ** 0.5 bulk = Atoms([Atom('Al', (0, 0, 0)), Atom('Al', (0.5, 0.5, 0.5))], pbc=True) bulk.set_cell((d, d, a), scale_atoms=True) h = 0.18 calc = GPAW(h=h, nbands=2 * 8, kpts=(2, 2, 2), convergence={'energy': 1e-5}) bulk.set_calculator(calc) e0 = bulk.get_potential_energy() for ext in [".db", ".cmr"]: calc.write("test1"+ext) assert os.path.exists("test1"+ext) calc.write("test2"+ext, cmr_params={"value":1, "keywords":["a", "b"]}) assert os.path.exists("test2"+ext) data = cmr.read("test2"+ext) assert data["value"] == 1 assert len(data["db_keywords"]) == 2 # test the restart ability if 0: calc = GPAW("test.db") calc.get_total_energy() calc = GPAW("test2.cmr") calc.get_total_energy() gpaw-0.11.0.13004/gpaw/test/cmrtest/__init__.py0000664000175000017500000000000012553643471021152 0ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/lcao_atomic_corrections.py0000664000175000017500000000377412553643471022643 0ustar jensjjensj00000000000000# Test that the atomic corrections of LCAO work correctly, # by verifying that the different implementations yield the same numbers. # # For example the corrections P^* dH P to the Hamiltonian. # # This is done by invoking GPAW once for each type of calculation. from ase.structure import molecule from gpaw import GPAW, LCAO, PoissonSolver from gpaw.lcao.atomic_correction import DenseAtomicCorrection, \ DistributedAtomicCorrection, ScipyAtomicCorrection from gpaw.mpi import world # Use a cell large enough that some overlaps are zero. # Thus the matrices will have at least some sparsity. system = molecule('H2O') system.center(vacuum=3.0) system.pbc = (0, 0, 1) system = system.repeat((1, 1, 2)) # Break symmetries so we don't get funny degeneracy effects. system.rattle(stdev=0.05) corrections = [DenseAtomicCorrection(), DistributedAtomicCorrection()] #corrections.pop() # XXXXXXXXXXXXXXXXXXXXXXXXXXXX try: import scipy except ImportError: pass else: corrections.append(ScipyAtomicCorrection(tolerance=0.0)) energies = [] for correction in corrections: parallel = {} if world.size >= 4: parallel['band'] = 2 if correction.name != 'dense': parallel['sl_auto'] = True calc = GPAW(mode=LCAO(atomic_correction=correction), basis='sz(dzp)', #kpts=(1, 1, 4), #spinpol=True, poissonsolver=PoissonSolver(relax='J', eps=1e100, nn=1), parallel=parallel, h=0.35) def stopcalc(): calc.scf.converged = True calc.attach(stopcalc, 2) system.set_calculator(calc) energy = system.get_potential_energy() energies.append(energy) master = calc.wfs.world.rank == 0 if master: print('energies', energies) eref = energies[0] errs = [] for energy, c in zip(energies, corrections): err = abs(energy - eref) nops = calc.wfs.world.sum(c.nops) errs.append(err) if master: print('err=%e :: name=%s :: nops=%d' % (err, c.name, nops)) assert max(errs) < 1e-11 gpaw-0.11.0.13004/gpaw/test/parallel/0000775000175000017500000000000012553644063017164 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/parallel/ut_hsops.py0000664000175000017500000007513212553643472021415 0ustar jensjjensj00000000000000from __future__ import print_function import gc import sys import time import numpy as np try: # Matplotlib is not a dependency import matplotlib as mpl mpl.use('Agg') # force the antigrain backend except (ImportError, RuntimeError): mpl = None from ase.units import Bohr from ase.utils import devnull from gpaw.mpi import world, distribute_cpus from gpaw.utilities.tools import tri2full, md5_array, gram_schmidt from gpaw.band_descriptor import BandDescriptor from gpaw.grid_descriptor import GridDescriptor from gpaw.kohnsham_layouts import BandLayouts from gpaw.hs_operators import MatrixOperator from gpaw.parameters import InputParameters from gpaw.xc import XC from gpaw.setup import SetupData, Setups from gpaw.lfc import LFC # ------------------------------------------------------------------- from gpaw.test.ut_common import ase_svnversion, shapeopt, TestCase, \ TextTestRunner, CustomTextTestRunner, defaultTestLoader, \ initialTestLoader, create_random_atoms, create_parsize_maxbands memstats = False if memstats: # Developer use of this feature requires ASE 3.1.0 svn.rev. 905 or later. assert ase_svnversion >= 905 # wasn't bug-free untill 973! from ase.utils.memory import MemorySingleton, MemoryStatistics # ------------------------------------------------------------------- p = InputParameters(spinpol=False) xc = XC(p.xc) p.setups = dict([(symbol, SetupData(symbol, xc.name)) for symbol in 'HN']) class UTBandParallelSetup(TestCase): """ Setup a simple band parallel calculation.""" # Number of bands nbands = 36 # Spin-paired, single kpoint nspins = 1 nibzkpts = 1 # Strided or blocked groups parstride_bands = None # Mean spacing and number of grid points per axis (G x G x G) h = 1.0 / Bohr G = 20 # Wavefunction data type dtype = None def setUp(self): for virtvar in ['dtype','parstride_bands']: assert getattr(self,virtvar) is not None, 'Virtual "%s"!' % virtvar parsize_domain, parsize_bands = create_parsize_maxbands(self.nbands, world.size) assert self.nbands % parsize_bands == 0 comms = distribute_cpus(parsize_domain, parsize_bands, self.nspins, self.nibzkpts) domain_comm, kpt_comm, band_comm, block_comm = \ [comms[name] for name in 'dkbK'] self.block_comm = block_comm # Set up band descriptor: self.bd = BandDescriptor(self.nbands, band_comm, self.parstride_bands) # Set up grid descriptor: res, ngpts = shapeopt(100, self.G**3, 3, 0.2) cell_c = self.h * np.array(ngpts) pbc_c = (True, False, True) self.gd = GridDescriptor(ngpts, cell_c, pbc_c, domain_comm, parsize_domain) # Create Kohn-Sham layouts for these band and grid descriptors: self.ksl = self.create_kohn_sham_layouts() # What to do about kpoints? self.kpt_comm = kpt_comm def tearDown(self): del self.bd, self.gd, self.ksl, self.kpt_comm, self.block_comm def create_kohn_sham_layouts(self): return BandLayouts(self.gd, self.bd, self.block_comm, self.dtype) # ================================= def verify_comm_sizes(self): if world.size == 1: return comm_sizes = tuple([comm.size for comm in [world, self.bd.comm, \ self.gd.comm, self.kpt_comm]]) self._parinfo = '%d world, %d band, %d domain, %d kpt' % comm_sizes self.assertEqual((self.nspins*self.nibzkpts) % self.kpt_comm.size, 0) def verify_kohn_sham_layouts(self): # TODO do more here :) self.assertFalse(self.ksl.using_blacs) self.assertTrue(self.ksl.bd is self.bd) self.assertTrue(self.ksl.gd is self.gd) def verify_band_stride_related(self): # Verify that (q1+q2)%B-q1 falls in ]-B;Q[ where Q=B//2+1 for B in range(1,256): Q = B//2+1 #dqs = [] #for q1 in range(B): # for q2 in range(Q): # dq = (q1+q2)%B-q1 # dqs.append(dq) #dqs = np.array(dqs) q1s = np.arange(B)[:,np.newaxis] q2s = np.arange(Q)[np.newaxis,:] dqs = (q1s+q2s)%B-q1s self.assertEqual(dqs.min(), -B+1) self.assertEqual(dqs.max(), Q-1) def verify_band_indexing_consistency(self): for n in range(self.bd.nbands): band_rank, myn = self.bd.who_has(n) self.assertEqual(self.bd.global_index(myn, band_rank), n) for band_rank in range(self.bd.comm.size): for myn in range(self.bd.mynbands): n = self.bd.global_index(myn, band_rank) self.assertTrue(self.bd.who_has(n) == (band_rank, myn)) def verify_band_ranking_consistency(self): rank_n = self.bd.get_band_ranks() for band_rank in range(self.bd.comm.size): my_band_indices = self.bd.get_band_indices(band_rank) matches = np.argwhere(rank_n == band_rank).ravel() self.assertTrue((matches == my_band_indices).all()) for myn in range(self.bd.mynbands): n = self.bd.global_index(myn, band_rank) self.assertEqual(my_band_indices[myn], n) class UTBandParallelSetup_Blocked(UTBandParallelSetup): __doc__ = UTBandParallelSetup.__doc__ parstride_bands = False dtype = float class UTBandParallelSetup_Strided(UTBandParallelSetup): __doc__ = UTBandParallelSetup.__doc__ parstride_bands = True dtype = float # ------------------------------------------------------------------- def record_memory(wait=0.1): assert gc.collect() == 0, 'Uncollected garbage!' world.barrier() time.sleep(wait) mem = MemoryStatistics() time.sleep(wait) world.barrier() return mem def create_memory_info(mem1, mem2, vmkey='VmData'): dm = np.array([(mem2-mem1)[vmkey]], dtype=float) dm_r = np.empty(world.size, dtype=float) world.all_gather(dm, dm_r) return dm_r, ','.join(['%8.4f MB' % v for v in dm_r/1024**2.]) # ------------------------------------------------------------------- class UTConstantWavefunctionSetup(UTBandParallelSetup): __doc__ = UTBandParallelSetup.__doc__ + """ The pseudo wavefunctions are constants normalized to their band index.""" allocated = False blocking = None async = None def setUp(self): UTBandParallelSetup.setUp(self) for virtvar in ['dtype','blocking','async']: assert getattr(self,virtvar) is not None, 'Virtual "%s"!' % virtvar # Create randomized atoms self.atoms = create_random_atoms(self.gd) # Do we agree on the atomic positions? pos_ac = self.atoms.get_positions() pos_rac = np.empty((world.size,)+pos_ac.shape, pos_ac.dtype) world.all_gather(pos_ac, pos_rac) if (pos_rac-pos_rac[world.rank,...][np.newaxis,...]).any(): raise RuntimeError('Discrepancy in atomic positions detected.') # Create setups for atoms self.Z_a = self.atoms.get_atomic_numbers() self.setups = Setups(self.Z_a, p.setups, p.basis, p.lmax, xc) # Create atomic projector overlaps spos_ac = self.atoms.get_scaled_positions() % 1.0 self.rank_a = self.gd.get_ranks_from_positions(spos_ac) self.pt = LFC(self.gd, [setup.pt_j for setup in self.setups], dtype=self.dtype) self.pt.set_positions(spos_ac) if memstats: # Hack to scramble heap usage into steady-state level HEAPSIZE = 25 * 1024**2 for i in range(100): data = np.empty(np.random.uniform(0, HEAPSIZE // 8), float) del data self.mem_pre = record_memory() self.mem_alloc = None self.mem_test = None # Stuff for pseudo wave functions and projections if self.dtype == complex: self.gamma = 1j**(1.0/self.nbands) else: self.gamma = 1.0 self.psit_nG = None self.P_ani = None self.Qeff_a = None self.Qtotal = None self.allocate() def tearDown(self): UTBandParallelSetup.tearDown(self) del self.P_ani, self.psit_nG del self.pt, self.setups, self.atoms if memstats: self.print_memory_summary() del self.mem_pre, self.mem_alloc, self.mem_test self.allocated = False def print_memory_summary(self): if not memstats: raise RuntimeError('No memory statistics were recorded!') if world.rank == 0: sys.stdout.write('\n') sys.stdout.flush() dm_r, dminfo = create_memory_info(MemorySingleton(), self.mem_pre) if world.rank == 0: print('overhead: %s -> %8.4f MB' % (dminfo, dm_r.sum()/1024**2.)) dm_r, dminfo = create_memory_info(self.mem_pre, self.mem_alloc) if world.rank == 0: print('allocate: %s -> %8.4f MB' % (dminfo, dm_r.sum()/1024**2.)) dm_r, dminfo = create_memory_info(self.mem_alloc, self.mem_test) if world.rank == 0: print('test-use: %s -> %8.4f MB' % (dminfo, dm_r.sum()/1024**2.)) def allocate(self): """ Allocate constant wavefunctions and their projections according to:: / \ _____ i*phase*(n-m) = ( 1 + Q ) * V m*n * e n n' \ total/ """ if self.allocated: raise RuntimeError('Already allocated!') self.allocate_wavefunctions() self.allocate_projections() # XXX DEBUG disables projection contributions if False: for a,P_ni in self.P_ani.items(): P_ni[:] = 0. self.Qeff_a[a] = 0. self.Qtotal = 0. self.Z_a[:] = 2**63-1 # XXX DEBUG self.Qtotal = np.empty(1, dtype=float) self.Qtotal[:] = np.sum([Qeff for Qeff in self.Qeff_a.values()]) self.gd.comm.sum(self.Qtotal) band_indices = np.arange(self.nbands).astype(self.dtype) z = self.gamma**band_indices * band_indices**0.5 self.S0_nn = (1. + self.Qtotal) * np.outer(z.conj(), z) self.allocated = True if memstats: self.mem_alloc = record_memory() def allocate_wavefunctions(self): """ Allocate constant pseudo wavefunctions according to:: ~ ~ _____ i*phase*(n-m) = V m*n * e n n' """ if self.allocated: raise RuntimeError('Already allocated!') # Fill in wave functions gpts_c = self.gd.get_size_of_global_array() self.psit_nG = self.gd.empty(self.bd.mynbands, self.dtype) for myn, psit_G in enumerate(self.psit_nG): n = self.bd.global_index(myn) # Fill psit_nG: | psit_n > = exp(i*phase*n) * sqrt(n) / sqrt(V) psit_G[:] = self.gamma**n * n**0.5 / (self.gd.dv * gpts_c.prod())**0.5 def allocate_projections(self): """ Construct dummy projection of pseudo wavefunction according to:: ___ \ ~ ~a a ~a ~ 1 _____ i*phase*(n-m) ) dO

= +/- --- * V m*n * e /___ n i ii' i' n' Z ii' a """ if self.allocated: raise RuntimeError('Already allocated!') # Fill in projector overlaps my_band_indices = self.bd.get_band_indices() my_atom_indices = np.argwhere(self.gd.comm.rank == self.rank_a).ravel() # Holm-Nielsen check: natoms = len(self.atoms) assert (self.gd.comm.sum(float(sum(my_atom_indices))) == natoms * (natoms - 1) // 2) # Check that LFC agrees with us: self.assertEqual(len(my_atom_indices), len(self.pt.my_atom_indices)) for a1, a2 in zip(my_atom_indices, self.pt.my_atom_indices): self.assertEqual(a1, a2) self.Qeff_a = {} self.P_ani = self.pt.dict(self.bd.mynbands) for a in my_atom_indices: ni = self.setups[a].ni # Fill P_ni: = beta_i * exp(i*phase*n) * sqrt(n) # # | ____ | # | \ * a | 1 # | ) beta dO beta | = ---- # | /___ i ij j | Z # | ij | a # # Substitution by linear transformation: beta_i -> dO_ij alpha_j, # where we start out with some initial non-constant vector: alpha_i = np.exp(-np.arange(ni).astype(self.dtype)/ni) try: # Try Cholesky decomposition dO_ii = L_ii * L_ii^dag L_ii = np.linalg.cholesky(self.setups[a].dO_ii) alpha_i /= np.vdot(alpha_i, alpha_i)**0.5 beta_i = np.linalg.solve(L_ii.T.conj(), alpha_i) except np.linalg.LinAlgError: # Eigenvector decomposition dO_ii = V_ii * W_ii * V_ii^dag W_i, V_ii = np.linalg.eigh(self.setups[a].dO_ii) alpha_i /= np.abs(np.vdot(alpha_i, np.dot(np.diag(W_i), alpha_i)))**0.5 beta_i = np.linalg.solve(V_ii.T.conj(), alpha_i) # Normalize according to plus/minus charge beta_i /= self.Z_a[a]**0.5 self.Qeff_a[a] = np.vdot(beta_i, np.dot(self.setups[a].dO_ii, \ beta_i)).real self.P_ani[a][:] = np.outer(self.gamma**my_band_indices \ * my_band_indices**0.5, beta_i) def check_and_plot(self, A_nn, A0_nn, digits, keywords=''): # Construct fingerprint of input matrices for comparison fingerprint = np.array([md5_array(A_nn, numeric=True), md5_array(A0_nn, numeric=True)]) # Compare fingerprints across all processors fingerprints = np.empty((world.size, 2), np.int64) world.all_gather(fingerprint, fingerprints) if fingerprints.ptp(0).any(): raise RuntimeError('Distributed matrices are not identical!') # If assertion fails, catch temporarily while plotting, then re-raise try: self.assertAlmostEqual(np.abs(A_nn-A0_nn).max(), 0, digits) except AssertionError: if world.rank == 0 and mpl is not None: from matplotlib.figure import Figure fig = Figure() ax = fig.add_axes([0.0, 0.1, 1.0, 0.83]) ax.set_title(self.__class__.__name__) im = ax.imshow(np.abs(A_nn-A0_nn), interpolation='nearest') fig.colorbar(im) fig.text(0.5, 0.05, 'Keywords: ' + keywords, \ horizontalalignment='center', verticalalignment='top') from matplotlib.backends.backend_agg import FigureCanvasAgg img = 'ut_hsops_%s_%s.png' % (self.__class__.__name__, \ '_'.join(keywords.split(','))) FigureCanvasAgg(fig).print_figure(img.lower(), dpi=90) raise def get_optimal_number_of_blocks(self, blocking='fast'): """Estimate the optimal number of blocks for band parallelization. The number of blocks determines how many parallel send/receive operations are performed, as well as the added memory footprint of the required send/receive buffers. ``blocking`` ``nblocks`` Description ============ ============= ======================================== 'fast' ``1`` Heavy on memory, more accurate and fast. 'light' ``mynbands`` Light on memory, less accurate and slow. 'intdiv' ``...`` First integer divisible value 'nonintdiv' ``...`` Some non-integer divisible cases """ #if self.bd.comm.size == 1: # return 1 if blocking == 'fast': return 1 elif blocking == 'light': return self.bd.mynbands elif blocking == 'intdiv': # Find first value of nblocks that leads to integer # divisible mybands / nblock. This is very like to be # 2 but coded here for the general case nblocks = 2 while self.bd.mynbands % nblocks != 0: nblocks +=1 return nblocks elif blocking == 'nonintdiv1': # Find first value of nblocks that leads to non-integer # divisible mynbands / nblock that is less than M nblocks = 2 M = self.bd.mynbands // nblocks while self.bd.mynbands % nblocks < M: nblocks += 1 M = self.bd.mynbands // nblocks return nblocks elif blocking == 'nonintdiv2': # Find first value of nblocks that leads to non-integer # divisible mynbands / nblock that is less than M nblocks = 2 M = self.bd.mynbands // nblocks while self.bd.mynbands % nblocks > M: nblocks += 1 M = self.mynbands // nblocks return nblocks else: nblocks = blocking assert self.bd.mynbands // nblocks > 0 return nblocks # ================================= def test_contents_wavefunction(self): # Integrate diagonal brakets of pseudo wavefunctions gpts_c = self.gd.get_size_of_global_array() intpsit_myn = self.bd.empty(dtype=self.dtype) for myn, psit_G in enumerate(self.psit_nG): n = self.bd.global_index(myn) intpsit_myn[myn] = np.vdot(psit_G, psit_G) * self.gd.dv self.gd.comm.sum(intpsit_myn) if memstats: self.mem_test = record_memory() my_band_indices = self.bd.get_band_indices() self.assertAlmostEqual(np.abs(intpsit_myn-my_band_indices).max(), 0, 9) intpsit_n = self.bd.collect(intpsit_myn, broadcast=True) self.assertAlmostEqual(np.abs(intpsit_n-np.arange(self.nbands)).max(), 0, 9) def test_contents_projection(self): # Distribute inverse effective charges to everybody in domain all_Qeff_a = np.empty(len(self.atoms), dtype=float) for a,rank in enumerate(self.rank_a): if rank == self.gd.comm.rank: Qeff = np.array([self.Qeff_a[a]]) else: Qeff = np.empty(1, dtype=float) self.gd.comm.broadcast(Qeff, rank) all_Qeff_a[a] = Qeff # Check absolute values consistency of inverse effective charges self.assertAlmostEqual(np.abs(1./self.Z_a-np.abs(all_Qeff_a)).max(), 0, 9) # Check sum of inverse effective charges against total self.assertAlmostEqual(all_Qeff_a.sum(), self.Qtotal, 9) # Make sure that we all agree on inverse effective charges fingerprint = np.array([md5_array(all_Qeff_a, numeric=True)]) all_fingerprints = np.empty(world.size, fingerprint.dtype) world.all_gather(fingerprint, all_fingerprints) if all_fingerprints.ptp(0).any(): raise RuntimeError('Distributed eff. charges are not identical!') def test_overlaps_hermitian(self): # Set up Hermitian overlap operator: S = lambda x: x dS = lambda a, P_ni: np.dot(P_ni, self.setups[a].dO_ii) nblocks = self.get_optimal_number_of_blocks(self.blocking) overlap = MatrixOperator(self.ksl, nblocks, self.async, True) S_nn = overlap.calculate_matrix_elements(self.psit_nG, \ self.P_ani, S, dS).T.copy() # transpose to get tri2full(S_nn, 'U') # upper to lower... if self.bd.comm.rank == 0: self.gd.comm.broadcast(S_nn, 0) self.bd.comm.broadcast(S_nn, 0) if memstats: self.mem_test = record_memory() self.check_and_plot(S_nn, self.S0_nn, 9, 'overlaps,hermitian') def test_overlaps_nonhermitian(self): alpha = np.random.normal(size=1).astype(self.dtype) if self.dtype == complex: alpha += 1j*np.random.normal(size=1) world.broadcast(alpha, 0) # Set up non-Hermitian overlap operator: S = lambda x: alpha*x dS = lambda a, P_ni: np.dot(alpha*P_ni, self.setups[a].dO_ii) nblocks = self.get_optimal_number_of_blocks(self.blocking) overlap = MatrixOperator(self.ksl, nblocks, self.async, False) S_nn = overlap.calculate_matrix_elements(self.psit_nG, \ self.P_ani, S, dS).T.copy() # transpose to get if self.bd.comm.rank == 0: self.gd.comm.broadcast(S_nn, 0) self.bd.comm.broadcast(S_nn, 0) if memstats: self.mem_test = record_memory() self.check_and_plot(S_nn, alpha*self.S0_nn, 9, 'overlaps,nonhermitian') def test_trivial_cholesky(self): # Known starting point of SI_nn = I_nn = np.eye(*self.S0_nn.shape) alpha = 1e-3 # shift eigenvalues away from zero SI_nn = self.S0_nn + alpha * I_nn # Try Cholesky decomposition SI_nn = L_nn * L_nn^dag L_nn = np.linalg.cholesky(SI_nn) # |psit_n> -> C_nn |psit_n> , C_nn^(-1) = L_nn^dag # -> = diag(W_n) C_nn = np.linalg.inv(L_nn.T.conj()) # Set up Hermitian overlap operator: S = lambda x: x dS = lambda a, P_ni: np.dot(P_ni, self.setups[a].dO_ii) nblocks = self.get_optimal_number_of_blocks(self.blocking) overlap = MatrixOperator(self.ksl, nblocks, self.async, True) self.psit_nG = overlap.matrix_multiply(C_nn.T.copy(), self.psit_nG, self.P_ani) D_nn = overlap.calculate_matrix_elements(self.psit_nG, \ self.P_ani, S, dS).T.copy() # transpose to get tri2full(D_nn, 'U') # upper to lower... if self.bd.comm.rank == 0: self.gd.comm.broadcast(D_nn, 0) self.bd.comm.broadcast(D_nn, 0) if memstats: self.mem_test = record_memory() # D_nn = C_nn^dag * S_nn * C_nn = I_nn - alpha * C_nn^dag * C_nn D0_nn = I_nn - alpha * np.dot(C_nn.T.conj(), C_nn) self.check_and_plot(D_nn, D0_nn, 6, 'trivial,cholesky') #XXX precision def test_trivial_diagonalize(self): # Known starting point of S_nn = S_nn = self.S0_nn # Eigenvector decomposition S_nn = V_nn * W_nn * V_nn^dag # Utilize the fact that they are analytically known (cf. Maple) band_indices = np.arange(self.nbands) V_nn = np.eye(self.nbands).astype(self.dtype) if self.dtype == complex: V_nn[1:,1] = np.conj(self.gamma)**band_indices[1:] * band_indices[1:]**0.5 V_nn[1,2:] = -self.gamma**band_indices[1:-1] * band_indices[2:]**0.5 else: V_nn[2:,1] = band_indices[2:]**0.5 V_nn[1,2:] = -band_indices[2:]**0.5 W_n = np.zeros(self.nbands).astype(self.dtype) W_n[1] = (1. + self.Qtotal) * self.nbands * (self.nbands - 1) / 2. # Find the inverse basis Vinv_nn = np.linalg.inv(V_nn) # Test analytical eigenvectors for consistency against analytical S_nn D_nn = np.dot(Vinv_nn, np.dot(S_nn, V_nn)) self.assertAlmostEqual(np.abs(D_nn.diagonal()-W_n).max(), 0, 8) self.assertAlmostEqual(np.abs(np.tril(D_nn, -1)).max(), 0, 4) self.assertAlmostEqual(np.abs(np.triu(D_nn, 1)).max(), 0, 4) del Vinv_nn, D_nn # Perform Gram Schmidt orthonormalization for diagonalization # |psit_n> -> C_nn |psit_n>, using orthonormalized basis Q_nn # -> = diag(W_n) # using S_nn = V_nn * W_nn * V_nn^(-1) = Q_nn * W_nn * Q_nn^dag C_nn = V_nn.copy() gram_schmidt(C_nn) self.assertAlmostEqual(np.abs(np.dot(C_nn.T.conj(), C_nn) \ - np.eye(self.nbands)).max(), 0, 6) # Set up Hermitian overlap operator: S = lambda x: x dS = lambda a, P_ni: np.dot(P_ni, self.setups[a].dO_ii) nblocks = self.get_optimal_number_of_blocks(self.blocking) overlap = MatrixOperator(self.ksl, nblocks, self.async, True) self.psit_nG = overlap.matrix_multiply(C_nn.T.copy(), self.psit_nG, self.P_ani) D_nn = overlap.calculate_matrix_elements(self.psit_nG, \ self.P_ani, S, dS).T.copy() # transpose to get tri2full(D_nn, 'U') # upper to lower... if self.bd.comm.rank == 0: self.gd.comm.broadcast(D_nn, 0) self.bd.comm.broadcast(D_nn, 0) if memstats: self.mem_test = record_memory() # D_nn = C_nn^dag * S_nn * C_nn = W_n since Q_nn^dag = Q_nn^(-1) D0_nn = np.dot(C_nn.T.conj(), np.dot(S_nn, C_nn)) self.assertAlmostEqual(np.abs(D0_nn-np.diag(W_n)).max(), 0, 9) self.check_and_plot(D_nn, D0_nn, 9, 'trivial,diagonalize') def test_multiply_randomized(self): # Known starting point of S_nn = S_nn = self.S0_nn if self.dtype == complex: C_nn = np.random.uniform(size=self.nbands**2) * \ np.exp(1j*np.random.uniform(0,2*np.pi,size=self.nbands**2)) else: C_nn = np.random.normal(size=self.nbands**2) C_nn = C_nn.reshape((self.nbands,self.nbands)) / np.linalg.norm(C_nn,2) world.broadcast(C_nn, 0) # Set up Hermitian overlap operator: S = lambda x: x dS = lambda a, P_ni: np.dot(P_ni, self.setups[a].dO_ii) nblocks = self.get_optimal_number_of_blocks(self.blocking) overlap = MatrixOperator(self.ksl, nblocks, self.async, True) self.psit_nG = overlap.matrix_multiply(C_nn.T.copy(), self.psit_nG, self.P_ani) D_nn = overlap.calculate_matrix_elements(self.psit_nG, \ self.P_ani, S, dS).T.copy() # transpose to get tri2full(D_nn, 'U') # upper to lower... if self.bd.comm.rank == 0: self.gd.comm.broadcast(D_nn, 0) self.bd.comm.broadcast(D_nn, 0) if memstats: self.mem_test = record_memory() # D_nn = C_nn^dag * S_nn * C_nn D0_nn = np.dot(C_nn.T.conj(), np.dot(S_nn, C_nn)) self.check_and_plot(D_nn, D0_nn, 9, 'multiply,randomized') def test_multiply_nonhermitian(self): alpha = np.random.normal(size=1).astype(self.dtype) if self.dtype == complex: alpha += 1j*np.random.normal(size=1) world.broadcast(alpha, 0) # Known starting point of S_nn = S_nn = alpha*self.S0_nn if self.dtype == complex: C_nn = np.random.uniform(size=self.nbands**2) * \ np.exp(1j*np.random.uniform(0,2*np.pi,size=self.nbands**2)) else: C_nn = np.random.normal(size=self.nbands**2) C_nn = C_nn.reshape((self.nbands,self.nbands)) / np.linalg.norm(C_nn,2) world.broadcast(C_nn, 0) # Set up non-Hermitian overlap operator: S = lambda x: alpha*x dS = lambda a, P_ni: np.dot(alpha*P_ni, self.setups[a].dO_ii) nblocks = self.get_optimal_number_of_blocks(self.blocking) overlap = MatrixOperator(self.ksl, nblocks, self.async, False) self.psit_nG = overlap.matrix_multiply(C_nn.T.copy(), self.psit_nG, self.P_ani) D_nn = overlap.calculate_matrix_elements(self.psit_nG, \ self.P_ani, S, dS).T.copy() # transpose to get if self.bd.comm.rank == 0: self.gd.comm.broadcast(D_nn, 0) self.bd.comm.broadcast(D_nn, 0) if memstats: self.mem_test = record_memory() # D_nn = C_nn^dag * S_nn * C_nn D0_nn = np.dot(C_nn.T.conj(), np.dot(S_nn, C_nn)) self.check_and_plot(D_nn, D0_nn, 9, 'multiply,nonhermitian') # ------------------------------------------------------------------- def UTConstantWavefunctionFactory(dtype, parstride_bands, blocking, async): sep = '_' classname = 'UTConstantWavefunctionSetup' \ + sep + {float:'Float', complex:'Complex'}[dtype] \ + sep + {False:'Blocked', True:'Strided'}[parstride_bands] \ + sep + {'fast':'Fast', 'light':'Light', 'intdiv':'Intdiv', 'nonintdiv1':'Nonintdiv1', 'nonintdiv2':'Nonintdiv2'}[blocking] \ + sep + {False:'Synchronous', True:'Asynchronous'}[async] class MetaPrototype(UTConstantWavefunctionSetup, object): __doc__ = UTConstantWavefunctionSetup.__doc__ dtype = dtype parstride_bands = parstride_bands blocking = blocking async = async MetaPrototype.__name__ = classname return MetaPrototype # ------------------------------------------------------------------- if __name__ in ['__main__', '__builtin__']: # We may have been imported by test.py, if so we should redirect to logfile if __name__ == '__builtin__': testrunner = CustomTextTestRunner('ut_hsops.log', verbosity=2) else: stream = (world.rank == 0) and sys.stdout or devnull testrunner = TextTestRunner(stream=stream, verbosity=2) parinfo = [] # Initial Verification only tests case : dtype = float for test in [UTBandParallelSetup_Blocked, UTBandParallelSetup_Strided]: info = ['', test.__name__, test.__doc__.strip('\n'), ''] testsuite = initialTestLoader.loadTestsFromTestCase(test) list(map(testrunner.stream.writeln, info)) testresult = testrunner.run(testsuite) assert testresult.wasSuccessful(), 'Initial verification failed!' parinfo.extend([' Parallelization options: %s' % tci._parinfo for \ tci in testsuite._tests if hasattr(tci, '_parinfo')]) parinfo = np.unique(np.sort(parinfo)).tolist() testcases = [] for dtype in [float, complex]: for parstride_bands in [False, True]: for blocking in ['fast', 'light', 'intdiv', 'nonintdiv1', 'nonintdiv2']: for async in [False, True]: testcases.append(UTConstantWavefunctionFactory(dtype, \ parstride_bands, blocking, async)) for test in testcases: info = ['', test.__name__, test.__doc__.strip('\n')] + parinfo + [''] testsuite = defaultTestLoader.loadTestsFromTestCase(test) list(map(testrunner.stream.writeln, info)) testresult = testrunner.run(testsuite) # Provide feedback on failed tests if imported by test.py if __name__ == '__builtin__' and not testresult.wasSuccessful(): raise SystemExit('Test failed. Check ut_hsops.log for details.') gpaw-0.11.0.13004/gpaw/test/parallel/blacsdist.py0000664000175000017500000000410012553643472021504 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from gpaw.mpi import world from gpaw.blacs import BlacsGrid, Redistributor from gpaw.utilities import compiled_with_sl def test(comm, M, N, mcpus, ncpus, mb, nb): grid0 = BlacsGrid(comm, 1, 1) desc0 = grid0.new_descriptor(M, N, M, N, 0, 0) A_mn = desc0.zeros(dtype=float) A_mn[:] = comm.size + 1 grid1 = BlacsGrid(comm, mcpus, ncpus) desc1 = grid1.new_descriptor(M, N, mb, nb, 0, 0) # ??? B_mn = desc1.zeros(dtype=float) B_mn[:] = comm.rank if comm.rank == 0: msg = 'Slices of global matrix indices by rank' print(msg) print('-' * len(msg)) for rank in range(comm.size): comm.barrier() if rank == comm.rank: print('Rank %d:' % rank) last_Mstart = -1 for Mstart, Mstop, Nstart, Nstop, block in desc1.my_blocks(B_mn): if Mstart > last_Mstart and last_Mstart >= 0: print() print('[%3d:%3d, %3d:%3d]' % (Mstart, Mstop, Nstart, Nstop), end=' ') last_Mstart = Mstart assert (block == comm.rank).all() #print block #print print() print() comm.barrier() redistributor = Redistributor(comm, desc1, desc0) redistributor.redistribute(B_mn, A_mn) if comm.rank == 0: msg = 'Rank where each element of the global matrix is stored' print(msg) print('-' * len(msg)) print(A_mn) if __name__ in ['__main__', '__builtin__']: if not compiled_with_sl(): print('Not built with ScaLAPACK. Test does not apply.') else: M, N = 10, 10 mb, nb = 2, 2 mcpus = int(np.ceil(world.size**0.5)) ncpus = world.size // mcpus if world.rank == 0: print('world size: ', world.size) print('M x N: ', M, 'x', N) print('mcpus x ncpus:', mcpus, 'x', ncpus) print('mb x nb: ', mb, 'x', nb) print() test(world, M, N, mcpus, ncpus, mb, nb) gpaw-0.11.0.13004/gpaw/test/parallel/submatrix_redist.py0000664000175000017500000000131612553643472023132 0ustar jensjjensj00000000000000from __future__ import print_function from gpaw.mpi import world from gpaw.blacs import BlacsGrid, Redistributor if world.size < 2: raise ValueError('Runs on two or more processors') grid = BlacsGrid(world, 2, world.size // 2) desc = grid.new_descriptor(12, 8, 2, 3) a = desc.zeros() a[:] = world.rank subdesc = grid.new_descriptor(7, 7, 2, 2) b = subdesc.zeros() r = Redistributor(grid.comm, desc, subdesc) ia = 3 ja = 2 ib = 1 jb = 1 M = 4 N = 5 r.redistribute(a, b, M, N, ia, ja, ib, jb) a0 = desc.collect_on_master(a) b0 = subdesc.collect_on_master(b) if world.rank == 0: print(a0) print(b0) xa = a0[ia:ia + M, ja:ja + N] xb = b0[ib:ib + M, jb:jb + N] assert (xa == xb).all() gpaw-0.11.0.13004/gpaw/test/parallel/scalapack_mpirecv_crash.py0000664000175000017500000000146212553643472024373 0ustar jensjjensj00000000000000# *** An error occurred in MPI_Recv # *** on communicator MPI COMMUNICATOR 36 DUP FROM 28 # *** MPI_ERR_TRUNCATE: message truncated # *** MPI_ERRORS_ARE_FATAL (your MPI job will now abort) # works with 'sl_default': (2, 2, 32) from ase.lattice.surface import fcc100, add_adsorbate from gpaw import GPAW, ConvergenceError from gpaw.mpi import world from gpaw.utilities import compiled_with_sl assert world.size == 4 slab = fcc100('Cu', size=(2, 2, 4)) add_adsorbate(slab,'O', 1.1, 'hollow') slab.center(vacuum=3.0, axis=2) calc = GPAW(mode='lcao', kpts=(2, 2, 1), txt='-', maxiter=1,) if compiled_with_sl(): calc.set(parallel={'domain': (1, 1, 4), 'sl_default': (2, 2, 64)}) slab.set_calculator(calc) try: slab.get_potential_energy() except ConvergenceError: pass gpaw-0.11.0.13004/gpaw/test/parallel/ut_hsblacs.py0000664000175000017500000004055412553643472021700 0ustar jensjjensj00000000000000 import sys import numpy as np from ase.utils import devnull from gpaw import debug from gpaw.mpi import world from gpaw.utilities.tools import tri2full from gpaw.hs_operators import MatrixOperator from gpaw.utilities import compiled_with_sl from gpaw.utilities.scalapack import scalapack_set from gpaw.blacs import Redistributor from gpaw.kohnsham_layouts import BlacsBandLayouts if 0: # causes numpy doctests failures - exact formatting is expected! np.set_printoptions(linewidth=168) #XXX large xterm width # ------------------------------------------------------------------- from gpaw.test.ut_common import ase_svnversion, TextTestRunner, \ CustomTextTestRunner, defaultTestLoader, initialTestLoader memstats = False if memstats: # Developer use of this feature requires ASE 3.1.0 svn.rev. 905 or later. assert ase_svnversion >= 905 # wasn't bug-free untill 973! from ase.utils.memory import MemorySingleton, MemoryStatistics from gpaw.test.parallel.ut_hsops import UTBandParallelSetup, \ UTConstantWavefunctionSetup # ------------------------------------------------------------------- class UTBandParallelBlacsSetup(UTBandParallelSetup): """ Setup a simple band parallel calculation using BLACS.""" def create_kohn_sham_layouts(self): # Find BLACS parameters for Kohn-Sham layouts cpus = self.bd.comm.size * self.gd.comm.size self.mcpus = int(cpus**0.5) self.ncpus = cpus//self.mcpus return BlacsBandLayouts(self.gd, self.bd, self.block_comm, self.dtype, self.mcpus, self.ncpus, 6) # ================================= def verify_comm_sizes(self): if world.size == 1: return comm_sizes = tuple([comm.size for comm in [world, self.bd.comm, \ self.gd.comm, self.kpt_comm]]) comm_sizes += (self.mcpus, self.ncpus) self._parinfo = '%d world, %d band, %d domain, %d kpt, %d x %d BLACS' % comm_sizes self.assertEqual((self.nspins*self.nibzkpts) % self.kpt_comm.size, 0) def verify_kohn_sham_layouts(self): # TODO do more here :) self.assertTrue(self.ksl.using_blacs) self.assertTrue(self.ksl.bd is self.bd) self.assertTrue(self.ksl.gd is self.gd) class UTBandParallelBlacsSetup_Blocked(UTBandParallelBlacsSetup): __doc__ = UTBandParallelBlacsSetup.__doc__ parstride_bands = False dtype = float class UTBandParallelBlacsSetup_Strided(UTBandParallelSetup): __doc__ = UTBandParallelBlacsSetup.__doc__ parstride_bands = True dtype = float # ------------------------------------------------------------------- class UTConstantWavefunctionBlacsSetup(UTConstantWavefunctionSetup, UTBandParallelBlacsSetup): __doc__ = UTBandParallelBlacsSetup.__doc__ + """ The pseudo wavefunctions are constants normalized to their band index.""" # ================================= def test_overlaps_hermitian(self): # Set up Hermitian overlap operator: S = lambda x: x dS = lambda a, P_ni: np.dot(P_ni, self.setups[a].dO_ii) nblocks = self.get_optimal_number_of_blocks(self.blocking) overlap = MatrixOperator(self.ksl, nblocks, self.async, True) S_nn = overlap.calculate_matrix_elements(self.psit_nG, self.P_ani, S, dS) if memstats: self.mem_test = record_memory() S_NN = self.ksl.nndescriptor.collect_on_master(S_nn) if self.bd.comm.rank == 0 and self.gd.comm.rank == 0: assert S_NN.shape == (self.bd.nbands,) * 2 S_NN = S_NN.T.copy() # Fortran -> C indexing tri2full(S_NN, 'U') # upper to lower... else: assert S_NN.nbytes == 0 S_NN = np.empty((self.bd.nbands,) * 2, dtype=S_NN.dtype) if self.bd.comm.rank == 0: self.gd.comm.broadcast(S_NN, 0) self.bd.comm.broadcast(S_NN, 0) self.check_and_plot(S_NN, self.S0_nn, 9, 'overlaps,hermitian') def test_overlaps_nonhermitian(self): alpha = np.random.normal(size=1).astype(self.dtype) if self.dtype == complex: alpha += 1j*np.random.normal(size=1) world.broadcast(alpha, 0) # Set up non-Hermitian overlap operator: S = lambda x: alpha*x dS = lambda a, P_ni: np.dot(alpha*P_ni, self.setups[a].dO_ii) nblocks = self.get_optimal_number_of_blocks(self.blocking) overlap = MatrixOperator(self.ksl, nblocks, self.async, False) if 0: #XXX non-hermitian case so Nn2nn not just uplo='L' but rather 'G' blockcomm = self.ksl.nndescriptor.blacsgrid.comm self.ksl.Nn2nn = Redistributor(blockcomm, self.ksl.Nndescriptor, self.ksl.nndescriptor) S_nn = overlap.calculate_matrix_elements(self.psit_nG, self.P_ani, S, dS) if memstats: self.mem_test = record_memory() S_NN = self.ksl.nndescriptor.collect_on_master(S_nn) if self.bd.comm.rank == 0 and self.gd.comm.rank == 0: assert S_NN.shape == (self.bd.nbands,) * 2 S_NN = S_NN.T.copy() # Fortran -> C indexing else: assert S_NN.nbytes == 0 S_NN = np.empty((self.bd.nbands,) * 2, dtype=S_NN.dtype) if self.bd.comm.rank == 0: self.gd.comm.broadcast(S_NN, 0) self.bd.comm.broadcast(S_NN, 0) self.check_and_plot(S_NN, alpha*self.S0_nn, 9, 'overlaps,nonhermitian') def test_trivial_cholesky(self): # Set up Hermitian overlap operator: S = lambda x: x dS = lambda a, P_ni: np.dot(P_ni, self.setups[a].dO_ii) nblocks = self.get_optimal_number_of_blocks(self.blocking) overlap = MatrixOperator(self.ksl, nblocks, self.async, True) S_nn = overlap.calculate_matrix_elements(self.psit_nG, self.P_ani, S, dS) # Known starting point of SI_nn = I_nn = self.ksl.nndescriptor.empty(dtype=S_nn.dtype) scalapack_set(self.ksl.nndescriptor, I_nn, 0.0, 1.0, 'L') alpha = 1e-3 # shift eigenvalues away from zero C_nn = S_nn + alpha * I_nn self.ksl.nndescriptor.inverse_cholesky(C_nn, 'L') self.psit_nG = overlap.matrix_multiply(C_nn, self.psit_nG, self.P_ani) D_nn = overlap.calculate_matrix_elements(self.psit_nG, self.P_ani, S, dS) D_NN = self.ksl.nndescriptor.collect_on_master(D_nn) if self.bd.comm.rank == 0 and self.gd.comm.rank == 0: assert D_NN.shape == (self.bd.nbands,) * 2 D_NN = D_NN.T.copy() # Fortran -> C indexing tri2full(D_NN, 'U') # upper to lower.. else: assert D_NN.nbytes == 0 D_NN = np.empty((self.bd.nbands,) * 2, dtype=D_NN.dtype) if self.bd.comm.rank == 0: self.gd.comm.broadcast(D_NN, 0) self.bd.comm.broadcast(D_NN, 0) # D_NN = C_NN^dag * S_NN * C_NN = I_NN - alpha * C_NN^dag * C_NN I_NN = np.eye(self.bd.nbands) C0_NN = np.linalg.inv(np.linalg.cholesky(self.S0_nn + alpha*I_NN).T.conj()) D0_NN = I_NN - alpha * np.dot(C0_NN.T.conj(), C0_NN) self.check_and_plot(D_NN, D0_NN, 6, 'trivial,cholesky') #XXX precision def test_trivial_diagonalize(self): #XXX XXX XXX # Known starting point of S_nn = S_nn = self.S0_nn # Eigenvector decomposition S_nn = V_nn * W_nn * V_nn^dag # Utilize the fact that they are analytically known (cf. Maple) W_n = np.zeros(self.nbands).astype(self.dtype) W_n[1] = (1. + self.Qtotal) * self.nbands * (self.nbands - 1) / 2. # Set up Hermitian overlap operator: S = lambda x: x dS = lambda a, P_ni: np.dot(P_ni, self.setups[a].dO_ii) nblocks = self.get_optimal_number_of_blocks(self.blocking) overlap = MatrixOperator(self.ksl, nblocks, self.async, True) S_nn = overlap.calculate_matrix_elements(self.psit_nG, self.P_ani, S, dS) eps_N = self.bd.empty(global_array=True) # XXX dtype? C_nn = self.ksl.nndescriptor.empty(dtype=S_nn.dtype) self.ksl.nndescriptor.diagonalize_dc(S_nn, C_nn, eps_N, 'L') self.assertAlmostEqual(np.abs(np.sort(eps_N)-np.sort(W_n)).max(), 0, 9) #eps_n = self.bd.empty() #self.bd.distribute(eps_N, eps_n) # XXX only blocked groups, right? # Rotate wavefunctions to diagonalize the overlap self.psit_nG = overlap.matrix_multiply(C_nn, self.psit_nG, self.P_ani) # Recaulculate the overlap matrix, which should now be diagonal D_nn = overlap.calculate_matrix_elements(self.psit_nG, self.P_ani, S, dS) D_NN = self.ksl.nndescriptor.collect_on_master(D_nn) if self.bd.comm.rank == 0 and self.gd.comm.rank == 0: assert D_NN.shape == (self.bd.nbands,) * 2 D_NN = D_NN.T.copy() # Fortran -> C indexing tri2full(D_NN, 'U') # upper to lower... else: assert D_NN.nbytes == 0 D_NN = np.empty((self.bd.nbands,) * 2, dtype=D_NN.dtype) if self.bd.comm.rank == 0: self.gd.comm.broadcast(D_NN, 0) self.bd.comm.broadcast(D_NN, 0) D0_NN = np.diag(eps_N) self.check_and_plot(D_NN, D0_NN, 9, 'trivial,diagonalize') def test_multiply_randomized(self): # Known starting point of S_nn = S_NN = self.S0_nn if self.dtype == complex: C_NN = np.random.uniform(size=self.nbands**2) * \ np.exp(1j*np.random.uniform(0,2*np.pi,size=self.nbands**2)) else: C_NN = np.random.normal(size=self.nbands**2) C_NN = C_NN.reshape((self.nbands,self.nbands)) / np.linalg.norm(C_NN,2) world.broadcast(C_NN, 0) # Set up Hermitian overlap operator: S = lambda x: x dS = lambda a, P_ni: np.dot(P_ni, self.setups[a].dO_ii) nblocks = self.get_optimal_number_of_blocks(self.blocking) overlap = MatrixOperator(self.ksl, nblocks, self.async, True) if self.bd.comm.rank == 0 and self.gd.comm.rank == 0: assert C_NN.shape == (self.bd.nbands,) * 2 tmp_NN = C_NN.T.copy() # C -> Fortran indexing else: tmp_NN = self.ksl.nndescriptor.as_serial().empty(dtype=C_NN.dtype) C_nn = self.ksl.nndescriptor.distribute_from_master(tmp_NN) self.psit_nG = overlap.matrix_multiply(C_nn, self.psit_nG, self.P_ani) D_nn = overlap.calculate_matrix_elements(self.psit_nG, self.P_ani, S, dS) if memstats: self.mem_test = record_memory() D_NN = self.ksl.nndescriptor.collect_on_master(D_nn) if self.bd.comm.rank == 0 and self.gd.comm.rank == 0: assert D_NN.shape == (self.bd.nbands,) * 2 D_NN = D_NN.T.copy() # Fortran -> C indexing tri2full(D_NN, 'U') # upper to lower... else: assert D_NN.nbytes == 0 D_NN = np.empty((self.bd.nbands,) * 2, dtype=D_NN.dtype) if self.bd.comm.rank == 0: self.gd.comm.broadcast(D_NN, 0) self.bd.comm.broadcast(D_NN, 0) # D_nn = C_nn^dag * S_nn * C_nn D0_NN = np.dot(C_NN.T.conj(), np.dot(S_NN, C_NN)) self.check_and_plot(D_NN, D0_NN, 9, 'multiply,randomized') def test_multiply_nonhermitian(self): alpha = np.random.normal(size=1).astype(self.dtype) if self.dtype == complex: alpha += 1j*np.random.normal(size=1) world.broadcast(alpha, 0) # Known starting point of S_nn = S_NN = alpha*self.S0_nn if self.dtype == complex: C_NN = np.random.uniform(size=self.nbands**2) * \ np.exp(1j*np.random.uniform(0,2*np.pi,size=self.nbands**2)) else: C_NN = np.random.normal(size=self.nbands**2) C_NN = C_NN.reshape((self.nbands,self.nbands)) / np.linalg.norm(C_NN,2) world.broadcast(C_NN, 0) # Set up Hermitian overlap operator: S = lambda x: alpha*x dS = lambda a, P_ni: np.dot(alpha*P_ni, self.setups[a].dO_ii) nblocks = self.get_optimal_number_of_blocks(self.blocking) overlap = MatrixOperator(self.ksl, nblocks, self.async, False) if 0: #XXX non-hermitian case so Nn2nn not just uplo='L' but rather 'G' blockcomm = self.ksl.nndescriptor.blacsgrid.comm self.ksl.Nn2nn = Redistributor(blockcomm, self.ksl.Nndescriptor, self.ksl.nndescriptor) if self.bd.comm.rank == 0 and self.gd.comm.rank == 0: assert C_NN.shape == (self.bd.nbands,) * 2 tmp_NN = C_NN.T.copy() # C -> Fortran indexing else: tmp_NN = self.ksl.nndescriptor.as_serial().empty(dtype=C_NN.dtype) C_nn = self.ksl.nndescriptor.distribute_from_master(tmp_NN) self.psit_nG = overlap.matrix_multiply(C_nn, self.psit_nG, self.P_ani) D_nn = overlap.calculate_matrix_elements(self.psit_nG, self.P_ani, S, dS) if memstats: self.mem_test = record_memory() D_NN = self.ksl.nndescriptor.collect_on_master(D_nn) if self.bd.comm.rank == 0 and self.gd.comm.rank == 0: assert D_NN.shape == (self.bd.nbands,) * 2 D_NN = D_NN.T.copy() # Fortran -> C indexing else: assert D_NN.nbytes == 0 D_NN = np.empty((self.bd.nbands,) * 2, dtype=D_NN.dtype) if self.bd.comm.rank == 0: self.gd.comm.broadcast(D_NN, 0) self.bd.comm.broadcast(D_NN, 0) # D_nn = C_nn^dag * S_nn * C_nn D0_NN = np.dot(C_NN.T.conj(), np.dot(S_NN, C_NN)) self.check_and_plot(D_NN, D0_NN, 9, 'multiply,nonhermitian') # ------------------------------------------------------------------- def UTConstantWavefunctionFactory(dtype, parstride_bands, blocking, async): sep = '_' classname = 'UTConstantWavefunctionBlacsSetup' \ + sep + {float:'Float', complex:'Complex'}[dtype] \ + sep + {False:'Blocked', True:'Strided'}[parstride_bands] \ + sep + {'fast':'Fast', 'light':'Light', 'intdiv':'Intdiv', 'nonintdiv1': 'Nonintdiv1', 'nonintdiv2':'Nonintdiv2'}[blocking] \ + sep + {False:'Synchronous', True:'Asynchronous'}[async] class MetaPrototype(UTConstantWavefunctionBlacsSetup, object): __doc__ = UTConstantWavefunctionBlacsSetup.__doc__ dtype = dtype parstride_bands = parstride_bands blocking = blocking async = async MetaPrototype.__name__ = classname return MetaPrototype # ------------------------------------------------------------------- if __name__ in ['__main__', '__builtin__'] and compiled_with_sl(): # We may have been imported by test.py, if so we should redirect to logfile if __name__ == '__builtin__': testrunner = CustomTextTestRunner('ut_hsblacs.log', verbosity=2) else: stream = (world.rank == 0) and sys.stdout or devnull testrunner = TextTestRunner(stream=stream, verbosity=2) parinfo = [] # Initial Verification only tests case : dtype = float for test in [UTBandParallelBlacsSetup_Blocked]: #, UTBandParallelBlacsSetup_Strided]: info = ['', test.__name__, test.__doc__.strip('\n'), ''] testsuite = initialTestLoader.loadTestsFromTestCase(test) list(map(testrunner.stream.writeln, info)) testresult = testrunner.run(testsuite) assert testresult.wasSuccessful(), 'Initial verification failed!' parinfo.extend([' Parallelization options: %s' % tci._parinfo for \ tci in testsuite._tests if hasattr(tci, '_parinfo')]) parinfo = np.unique(np.sort(parinfo)).tolist() testcases = [] for dtype in [float, complex]: for parstride_bands in [False]: #XXX [False, True]: for blocking in ['fast', 'light', 'intdiv', 'nonintdiv1', 'nonintdiv2']: for async in [False, True]: testcases.append(UTConstantWavefunctionFactory(dtype, \ parstride_bands, blocking, async)) for test in testcases: info = ['', test.__name__, test.__doc__.strip('\n')] + parinfo + [''] testsuite = defaultTestLoader.loadTestsFromTestCase(test) list(map(testrunner.stream.writeln, info)) testresult = testrunner.run(testsuite) # Provide feedback on failed tests if imported by test.py if __name__ == '__builtin__' and not testresult.wasSuccessful(): raise SystemExit('Test failed. Check ut_hsblacs.log for details.') gpaw-0.11.0.13004/gpaw/test/parallel/scalapack_diag.py0000664000175000017500000000434712553643472022457 0ustar jensjjensj00000000000000import numpy as np from gpaw.blacs import BlacsGrid, parallelprint from gpaw.mpi import world, rank, size from gpaw.utilities.lapack import diagonalize from gpaw.utilities.scalapack import scalapack_diagonalize_dc from gpaw.blacs import Redistributor def scal_diagonalize(A, nodes='master'): # Diagonalize matrix A (size N*N) with scalapack # Usage: eps, B = scal_diagonalize(A) # eps and B and the eigenvalues and eigenvectors # nodes = 'master': eigenvectors only available on master node # nodes = 'all': eigenvectors broadcast to all nodes # make sure A is N*N, and hermitian N = A.shape[0] assert A.shape[0] == A.shape[1] for i in range(N): for j in range(i, N): assert A[i,j] == A[j,i].conj() # create blacs descriptor mb = 64 g = BlacsGrid(world, 2, size//2) nndesc1 = g.new_descriptor(N, N, N, N) nndesc2 = g.new_descriptor(N, N, mb, mb) # distribute A to blacs grid A_ if rank != 0: A = nndesc1.zeros(dtype=A.dtype) A_ = nndesc2.empty(dtype=A.dtype) redistributor = Redistributor(world, nndesc1, nndesc2) redistributor.redistribute(A, A_) # diagonalize B_ = nndesc2.zeros(dtype=A.dtype) eps = np.zeros(N,dtype=A.dtype) nndesc2.diagonalize_dc(A_, B_, eps, 'L') # distribute the eigenvectors to master B = np.zeros_like(A) redistributor = Redistributor(world, nndesc2, nndesc1) redistributor.redistribute(B_, B) if nodes == 'master': return eps, B elif nodes == 'all': if rank != 0: B = np.zeros((N, N)) world.broadcast(B, 0) return eps, B # generate a matrix N = 512 A = np.arange(N**2,dtype=float).reshape(N,N) for i in range(N): for j in range(i,N): A[i,j] = A[j,i] # diagonalize eps, B = scal_diagonalize(A) check = 1 if check and rank == 0: # check whether it gives the same result with lapack eps1 = np.zeros(N) diagonalize(A, eps1) assert np.abs(eps-eps1).sum() < 1e-6 for i in range(N//size): # the eigenvectors are row of the matrix, it can be differ by a minus sign. if np.abs(A[i,:] - B[i,:]).sum() > 1e-6: if np.abs(A[i,:] + B[i,:]).sum() > 1e-6: raise ValueError('Check !') gpaw-0.11.0.13004/gpaw/test/parallel/hamiltonian.py0000664000175000017500000000705512553643472022053 0ustar jensjjensj00000000000000from __future__ import print_function from time import time import sys from fractions import gcd import numpy as np from gpaw import parsize_domain, parsize_bands from gpaw.band_descriptor import BandDescriptor from gpaw.grid_descriptor import GridDescriptor from gpaw.kohnsham_layouts import BandLayouts from gpaw.mpi import world, distribute_cpus from gpaw.utilities.lapack import inverse_cholesky from gpaw.hs_operators import MatrixOperator from gpaw.fd_operators import Laplace G = 120 # number of grid points (G x G x G) N = 2000 # number of bands repeats = 1 try: N = int(sys.argv[1]) J = int(sys.argv[2]) except (IndexError, ValueError): N = 6 J = 3 repeats = 3 # B: number of band groups # D: number of domains if parsize_bands is None: if parsize_domain is None: B = gcd(N, world.size) D = world.size // B else: B = world.size // np.prod(parsize_domain) D = parsize_domain else: B = parsize_bands D = world.size // B M = N // B # number of bands per group assert M * B == N, 'M=%d, B=%d, N=%d' % (M,B,N) h = 0.2 # grid spacing a = h * G # side length of box assert np.prod(D) * B == world.size, 'D=%s, B=%d, W=%d' % (D,B,world.size) # Set up communicators: comms = distribute_cpus(parsize_domain=D, parsize_bands=B, nspins=1, nibzkpts=1) domain_comm, kpt_comm, band_comm, block_comm = \ [comms[name] for name in ['d', 'k', 'b', 'K']] assert kpt_comm.size == 1 if world.rank == 0: print('MPI: %d domains, %d band groups' % (domain_comm.size, band_comm.size)) # Set up band and grid descriptors: bd = BandDescriptor(N, band_comm, False) gd = GridDescriptor((G, G, G), (a, a, a), True, domain_comm, parsize=D) ksl = BandLayouts(gd, bd, block_comm, float) # Random wave functions: psit_mG = gd.empty(M) for m in range(M): np.random.seed(world.rank * M + m) psit_mG[m] = np.random.uniform(-0.5, 0.5, tuple(gd.n_c)) if world.rank == 0: print('Size of wave function array:', psit_mG.shape) P_ani = {0: psit_mG[:, :2, 0, 0].copy(), 1: psit_mG[:, -1, -1, -3:].copy()} kin = Laplace(gd, -0.5, 2).apply vt_G = gd.empty() vt_G.fill(0.567) def run(psit_mG): overlap = MatrixOperator(ksl, J) def H(psit_xG): Htpsit_xG = np.empty_like(psit_xG) kin(psit_xG, Htpsit_xG) for psit_G, y_G in zip(psit_xG, Htpsit_xG): y_G += vt_G * psit_G return Htpsit_xG dH_aii = {0: np.ones((2, 2)) * 0.123, 1: np.ones((3, 3)) * 0.321} def dH(a, P_ni): return np.dot(P_ni, dH_aii[a]) H_nn = overlap.calculate_matrix_elements(psit_mG, P_ani, H, dH) t1 = time() if world.rank == 0: eps_n, H_nn = np.linalg.eigh(H_nn) H_nn = np.ascontiguousarray(H_nn.T) t2 = time() if world.rank == 0: print('Diagonalization Time %f' % (t2-t1)) print(eps_n) # Distribute matrix: world.broadcast(H_nn, 0) psit_mG = overlap.matrix_multiply(H_nn, psit_mG, P_ani) if world.rank == 0: print('Made it past matrix multiply') # Check: assert not(P_ani[0] - psit_mG[:, :2, 0, 0]).round(10).any() assert not(P_ani[1] - psit_mG[:, -1, -1, -3:]).round(10).any() H_nn = overlap.calculate_matrix_elements(psit_mG, P_ani, H, dH) if world.rank == 0: for n in range(N): assert abs(H_nn[n, n] - eps_n[n]) < 1.5e-8 assert not H_nn[n + 1:, n].round(8).any() return psit_mG ta = time() for x in range(repeats): psit_mG = run(psit_mG) tb = time() if world.rank == 0: print('Total Time %f' % (tb -ta)) gpaw-0.11.0.13004/gpaw/test/parallel/ut_invops.py0000664000175000017500000004654112553643472021601 0ustar jensjjensj00000000000000 import sys import numpy as np try: # Matplotlib is not a dependency import matplotlib as mpl mpl.use('Agg') # force the antigrain backend except (ImportError, RuntimeError): mpl = None from ase.units import Bohr from ase.utils import devnull from gpaw.mpi import world, distribute_cpus from gpaw.utilities.tools import md5_array from gpaw.utilities.gauss import gaussian_wave from gpaw.band_descriptor import BandDescriptor from gpaw.grid_descriptor import GridDescriptor from gpaw.kpt_descriptor import KPointDescriptor from gpaw.kohnsham_layouts import BandLayouts from gpaw.parameters import InputParameters from gpaw.xc import XC from gpaw.setup import SetupData, Setups from gpaw.wavefunctions.base import WaveFunctions from gpaw.wavefunctions.fd import FDWaveFunctions from gpaw.fd_operators import Laplace # required but not really used from gpaw.pair_overlap import GridPairOverlap, ProjectorPairOverlap # ------------------------------------------------------------------- from gpaw.test.ut_common import ase_svnversion, shapeopt, TestCase, \ TextTestRunner, CustomTextTestRunner, defaultTestLoader, \ initialTestLoader, create_random_atoms, create_parsize_minbands # ------------------------------------------------------------------- p = InputParameters(spinpol=False) xc = XC(p.xc) p.setups = dict([(symbol, SetupData(symbol, xc.name)) for symbol in 'HO']) class UTDomainParallelSetup(TestCase): """ Setup a simple domain parallel calculation.""" # Number of bands nbands = 1 # Spin-paired, single kpoint nspins = 1 nibzkpts = 1 # Mean spacing and number of grid points per axis (G x G x G) h = 0.25 / Bohr G = 48 # Type of boundary conditions employed boundaries = None def setUp(self): for virtvar in ['boundaries']: assert getattr(self,virtvar) is not None, 'Virtual "%s"!' % virtvar parsize_domain, parsize_bands = create_parsize_minbands(self.nbands, world.size) assert self.nbands % np.prod(parsize_bands) == 0 comms = distribute_cpus(parsize_domain, parsize_bands, self.nspins, self.nibzkpts) domain_comm, kpt_comm, band_comm, block_comm = \ [comms[name] for name in 'dkbK'] self.block_comm = block_comm # Set up band descriptor: self.bd = BandDescriptor(self.nbands, band_comm) # Set up grid descriptor: res, ngpts = shapeopt(300, self.G**3, 3, 0.2) cell_c = self.h * np.array(ngpts) pbc_c = {'zero' : False, \ 'periodic': True, \ 'mixed' : (True, False, True)}[self.boundaries] self.gd = GridDescriptor(ngpts, cell_c, pbc_c, domain_comm, parsize_domain) # What to do about kpoints? self.kpt_comm = kpt_comm def tearDown(self): del self.bd, self.gd, self.kpt_comm, self.block_comm # ================================= def verify_comm_sizes(self): if world.size == 1: return comm_sizes = tuple([comm.size for comm in [world, self.bd.comm, \ self.gd.comm, self.kpt_comm]]) self._parinfo = '%d world, %d band, %d domain, %d kpt' % comm_sizes self.assertEqual(self.nbands % self.bd.comm.size, 0) self.assertEqual((self.nspins*self.nibzkpts) % self.kpt_comm.size, 0) class UTDomainParallelSetup_Zero(UTDomainParallelSetup): __doc__ = UTDomainParallelSetup.__doc__ boundaries = 'zero' class UTDomainParallelSetup_Periodic(UTDomainParallelSetup): __doc__ = UTDomainParallelSetup.__doc__ boundaries = 'periodic' class UTDomainParallelSetup_Mixed(UTDomainParallelSetup): __doc__ = UTDomainParallelSetup.__doc__ boundaries = 'mixed' # ------------------------------------------------------------------- # Helper functions/classes here class FDWFS(FDWaveFunctions): def __init__(self, gd, bd, kd, setups, block_comm, dtype): # override constructor assert kd.comm.size == 1 WaveFunctions.__init__(self, gd, 1, setups, bd, dtype, world, kd, None) self.kin = Laplace(gd, -0.5, dtype=dtype) self.diagksl = None self.orthoksl = BandLayouts(gd, bd, block_comm, dtype) self.initksl = None self.overlap = None self.rank_a = None def allocate_arrays_for_projections(self, my_atom_indices): # no alloc pass def collect_projections(self, P_ani): if self.gd.comm.size == 1 and self.bd.comm.size == 1: return np.concatenate([P_ni.T for P_ni in P_ani.values()]) assert len(self.kpt_u) == 1 self.kpt_u[0].P_ani = P_ani all_P_ni = WaveFunctions.collect_projections(self, 0, 0) if self.world.rank == 0: P_In = all_P_ni.T.copy() else: nproj = sum([setup.ni for setup in self.setups]) P_In = np.empty((nproj, self.bd.nbands), self.pt.dtype) self.world.broadcast(P_In, 0) return P_In # ------------------------------------------------------------------- class UTGaussianWavefunctionSetup(UTDomainParallelSetup): __doc__ = UTDomainParallelSetup.__doc__ + """ The pseudo wavefunctions are moving gaussians centered around each atom.""" allocated = False dtype = None # Default arguments for scaled Gaussian wave _sigma0 = 2.0 #0.75 _k0_c = 2*np.pi*np.array([1/5., 1/3., 0.]) def setUp(self): UTDomainParallelSetup.setUp(self) for virtvar in ['dtype']: assert getattr(self,virtvar) is not None, 'Virtual "%s"!' % virtvar # Create randomized atoms self.atoms = create_random_atoms(self.gd, 5) # also tested: 10xNH3/BDA # XXX DEBUG START if False: from ase import view view(self.atoms*(1+2*self.gd.pbc_c)) # XXX DEBUG END # Do we agree on the atomic positions? pos_ac = self.atoms.get_positions() pos_rac = np.empty((world.size,)+pos_ac.shape, pos_ac.dtype) world.all_gather(pos_ac, pos_rac) if (pos_rac-pos_rac[world.rank,...][np.newaxis,...]).any(): raise RuntimeError('Discrepancy in atomic positions detected.') # Create setups for atoms self.Z_a = self.atoms.get_atomic_numbers() self.setups = Setups(self.Z_a, p.setups, p.basis, p.lmax, xc) # K-point descriptor bzk_kc = np.array([[0, 0, 0]], dtype=float) self.kd = KPointDescriptor(bzk_kc, 1) self.kd.set_symmetry(self.atoms, self.setups) self.kd.set_communicator(self.kpt_comm) # Create gamma-point dummy wavefunctions self.wfs = FDWFS(self.gd, self.bd, self.kd, self.setups, self.block_comm, self.dtype) spos_ac = self.atoms.get_scaled_positions() % 1.0 self.wfs.set_positions(spos_ac) self.pt = self.wfs.pt # XXX shortcut ## Also create pseudo partial waveves #from gpaw.lfc import LFC #self.phit = LFC(self.gd, [setup.phit_j for setup in self.setups], \ # self.kpt_comm, dtype=self.dtype) #self.phit.set_positions(spos_ac) self.r_cG = None self.buf_G = None self.psit_nG = None self.allocate() def tearDown(self): UTDomainParallelSetup.tearDown(self) del self.r_cG, self.buf_G, self.psit_nG del self.pt, self.setups, self.atoms self.allocated = False def allocate(self): self.r_cG = self.gd.get_grid_point_coordinates() cell_cv = self.atoms.get_cell() / Bohr assert np.abs(cell_cv-self.gd.cell_cv).max() < 1e-9 center_c = 0.5*cell_cv.diagonal() self.buf_G = self.gd.empty(dtype=self.dtype) self.psit_nG = self.gd.empty(self.bd.mynbands, dtype=self.dtype) for myn,psit_G in enumerate(self.psit_nG): n = self.bd.global_index(myn) psit_G[:] = self.get_scaled_gaussian_wave(center_c, scale=10+2j*n) k_c = 2*np.pi*np.array([1/2., -1/7., 0.]) for pos_c in self.atoms.get_positions() / Bohr: sigma = self._sigma0/(1+np.sum(pos_c**2))**0.5 psit_G += self.get_scaled_gaussian_wave(pos_c, sigma, k_c, n+5j) self.allocated = True def get_scaled_gaussian_wave(self, pos_c, sigma=None, k_c=None, scale=None): if sigma is None: sigma = self._sigma0 if k_c is None: k_c = self._k0_c if scale is None: A = None else: # 4*pi*int(exp(-r^2/(2*w^2))^2*r^2, r=0...infinity)= w^3*pi^(3/2) # = scale/A^2 -> A = scale*(sqrt(Pi)*w)^(-3/2) hence int -> scale^2 A = scale/(sigma*(np.pi)**0.5)**1.5 return gaussian_wave(self.r_cG, pos_c, sigma, k_c, A, self.dtype, self.buf_G) def check_and_plot(self, P_ani, P0_ani, digits, keywords=''): # Collapse into viewable matrices P_In = self.wfs.collect_projections(P_ani) P0_In = self.wfs.collect_projections(P0_ani) # Construct fingerprint of input matrices for comparison fingerprint = np.array([md5_array(P_In, numeric=True), md5_array(P0_In, numeric=True)]) # Compare fingerprints across all processors fingerprints = np.empty((world.size, 2), np.int64) world.all_gather(fingerprint, fingerprints) if fingerprints.ptp(0).any(): raise RuntimeError('Distributed matrices are not identical!') # If assertion fails, catch temporarily while plotting, then re-raise try: self.assertAlmostEqual(np.abs(P_In-P0_In).max(), 0, digits) except AssertionError: if world.rank == 0 and mpl is not None: from matplotlib.figure import Figure fig = Figure() ax = fig.add_axes([0.0, 0.1, 1.0, 0.83]) ax.set_title(self.__class__.__name__) im = ax.imshow(np.abs(P_In-P0_In), interpolation='nearest') fig.colorbar(im) fig.text(0.5, 0.05, 'Keywords: ' + keywords, \ horizontalalignment='center', verticalalignment='top') from matplotlib.backends.backend_agg import FigureCanvasAgg img = 'ut_invops_%s_%s.png' % (self.__class__.__name__, \ '_'.join(keywords.split(','))) FigureCanvasAgg(fig).print_figure(img.lower(), dpi=90) raise # ================================= def test_projection_linearity(self): kpt = self.wfs.kpt_u[0] Q_ani = self.pt.dict(self.bd.mynbands) self.pt.integrate(self.psit_nG, Q_ani, q=kpt.q) for Q_ni in Q_ani.values(): self.assertTrue(Q_ni.dtype == self.dtype) P0_ani = dict([(a,Q_ni.copy()) for a,Q_ni in Q_ani.items()]) self.pt.add(self.psit_nG, Q_ani, q=kpt.q) self.pt.integrate(self.psit_nG, P0_ani, q=kpt.q) #rank_a = self.gd.get_ranks_from_positions(spos_ac) #my_atom_indices = np.argwhere(self.gd.comm.rank == rank_a).ravel() # ~ a ~ a' #TODO XXX should fix PairOverlap-ish stuff for < p | phi > overlaps # i i' #spos_ac = self.pt.spos_ac # NewLFC doesn't have this spos_ac = self.atoms.get_scaled_positions() % 1.0 gpo = GridPairOverlap(self.gd, self.setups) B_aa = gpo.calculate_overlaps(spos_ac, self.pt) # Compare fingerprints across all processors fingerprint = np.array([md5_array(B_aa, numeric=True)]) fingerprints = np.empty(world.size, np.int64) world.all_gather(fingerprint, fingerprints) if fingerprints.ptp(0).any(): raise RuntimeError('Distributed matrices are not identical!') P_ani = dict([(a,Q_ni.copy()) for a,Q_ni in Q_ani.items()]) for a1 in range(len(self.atoms)): if a1 in P_ani.keys(): P_ni = P_ani[a1] else: # Atom a1 is not in domain so allocate a temporary buffer P_ni = np.zeros((self.bd.mynbands,self.setups[a1].ni,), dtype=self.dtype) for a2, Q_ni in Q_ani.items(): # B_aa are the projector overlaps across atomic pairs B_ii = gpo.extract_atomic_pair_matrix(B_aa, a1, a2) P_ni += np.dot(Q_ni, B_ii.T) #sum over a2 and last i in B_ii self.gd.comm.sum(P_ni) self.check_and_plot(P_ani, P0_ani, 8, 'projection,linearity') def test_extrapolate_overlap(self): kpt = self.wfs.kpt_u[0] ppo = ProjectorPairOverlap(self.wfs, self.atoms) # Compare fingerprints across all processors fingerprint = np.array([md5_array(ppo.B_aa, numeric=True)]) fingerprints = np.empty(world.size, np.int64) world.all_gather(fingerprint, fingerprints) if fingerprints.ptp(0).any(): raise RuntimeError('Distributed matrices are not identical!') work_nG = np.empty_like(self.psit_nG) P_ani = ppo.apply(self.psit_nG, work_nG, self.wfs, kpt, \ calculate_P_ani=True, extrapolate_P_ani=True) P0_ani = self.pt.dict(self.bd.mynbands) self.pt.integrate(work_nG, P0_ani, kpt.q) del work_nG self.check_and_plot(P_ani, P0_ani, 11, 'extrapolate,overlap') def test_extrapolate_inverse(self): kpt = self.wfs.kpt_u[0] ppo = ProjectorPairOverlap(self.wfs, self.atoms) # Compare fingerprints across all processors fingerprint = np.array([md5_array(ppo.B_aa, numeric=True)]) fingerprints = np.empty(world.size, np.int64) world.all_gather(fingerprint, fingerprints) if fingerprints.ptp(0).any(): raise RuntimeError('Distributed matrices are not identical!') work_nG = np.empty_like(self.psit_nG) P_ani = ppo.apply_inverse(self.psit_nG, work_nG, self.wfs, kpt, \ calculate_P_ani=True, extrapolate_P_ani=True) P0_ani = self.pt.dict(self.bd.mynbands) self.pt.integrate(work_nG, P0_ani, kpt.q) del work_nG self.check_and_plot(P_ani, P0_ani, 11, 'extrapolate,inverse') def test_overlap_inverse_after(self): kpt = self.wfs.kpt_u[0] kpt.P_ani = self.pt.dict(self.bd.mynbands) ppo = ProjectorPairOverlap(self.wfs, self.atoms) # Compare fingerprints across all processors fingerprint = np.array([md5_array(ppo.B_aa, numeric=True)]) fingerprints = np.empty(world.size, np.int64) world.all_gather(fingerprint, fingerprints) if fingerprints.ptp(0).any(): raise RuntimeError('Distributed matrices are not identical!') work_nG = np.empty_like(self.psit_nG) self.pt.integrate(self.psit_nG, kpt.P_ani, kpt.q) P0_ani = dict([(a,P_ni.copy()) for a,P_ni in kpt.P_ani.items()]) ppo.apply(self.psit_nG, work_nG, self.wfs, kpt, calculate_P_ani=False) res_nG = np.empty_like(self.psit_nG) ppo.apply_inverse(work_nG, res_nG, self.wfs, kpt, calculate_P_ani=True) del work_nG P_ani = self.pt.dict(self.bd.mynbands) self.pt.integrate(res_nG, P_ani, kpt.q) abserr = np.empty(1, dtype=float) for n in range(self.nbands): band_rank, myn = self.bd.who_has(n) if band_rank == self.bd.comm.rank: abserr[:] = np.abs(self.psit_nG[myn] - res_nG[myn]).max() self.gd.comm.max(abserr) self.bd.comm.broadcast(abserr, band_rank) self.assertAlmostEqual(abserr.item(), 0, 10) self.check_and_plot(P_ani, P0_ani, 10, 'overlap,inverse,after') def test_overlap_inverse_before(self): kpt = self.wfs.kpt_u[0] kpt.P_ani = self.pt.dict(self.bd.mynbands) ppo = ProjectorPairOverlap(self.wfs, self.atoms) # Compare fingerprints across all processors fingerprint = np.array([md5_array(ppo.B_aa, numeric=True)]) fingerprints = np.empty(world.size, np.int64) world.all_gather(fingerprint, fingerprints) if fingerprints.ptp(0).any(): raise RuntimeError('Distributed matrices are not identical!') work_nG = np.empty_like(self.psit_nG) self.pt.integrate(self.psit_nG, kpt.P_ani, kpt.q) P0_ani = dict([(a,P_ni.copy()) for a,P_ni in kpt.P_ani.items()]) ppo.apply_inverse(self.psit_nG, work_nG, self.wfs, kpt, calculate_P_ani=False) res_nG = np.empty_like(self.psit_nG) ppo.apply(work_nG, res_nG, self.wfs, kpt, calculate_P_ani=True) del work_nG P_ani = self.pt.dict(self.bd.mynbands) self.pt.integrate(res_nG, P_ani, kpt.q) abserr = np.empty(1, dtype=float) for n in range(self.nbands): band_rank, myn = self.bd.who_has(n) if band_rank == self.bd.comm.rank: abserr[:] = np.abs(self.psit_nG[myn] - res_nG[myn]).max() self.gd.comm.max(abserr) self.bd.comm.broadcast(abserr, band_rank) self.assertAlmostEqual(abserr.item(), 0, 10) self.check_and_plot(P_ani, P0_ani, 10, 'overlap,inverse,before') # ------------------------------------------------------------------- def UTGaussianWavefunctionFactory(boundaries, dtype): sep = '_' classname = 'UTGaussianWavefunctionSetup' \ + sep + {'zero':'Zero', 'periodic':'Periodic', 'mixed':'Mixed'}[boundaries] \ + sep + {float:'Float', complex:'Complex'}[dtype] class MetaPrototype(UTGaussianWavefunctionSetup, object): __doc__ = UTGaussianWavefunctionSetup.__doc__ boundaries = boundaries dtype = dtype MetaPrototype.__name__ = classname return MetaPrototype # ------------------------------------------------------------------- if __name__ in ['__main__', '__builtin__']: # We may have been imported by test.py, if so we should redirect to logfile if __name__ == '__builtin__': testrunner = CustomTextTestRunner('ut_invops.log', verbosity=2) else: stream = (world.rank == 0) and sys.stdout or devnull testrunner = TextTestRunner(stream=stream, verbosity=2) parinfo = [] for test in [UTDomainParallelSetup_Zero, UTDomainParallelSetup_Periodic, \ UTDomainParallelSetup_Mixed]: info = ['', test.__name__, test.__doc__.strip('\n'), ''] testsuite = initialTestLoader.loadTestsFromTestCase(test) list(map(testrunner.stream.writeln, info)) testresult = testrunner.run(testsuite) assert testresult.wasSuccessful(), 'Initial verification failed!' parinfo.extend([' Parallelization options: %s' % tci._parinfo for \ tci in testsuite._tests if hasattr(tci, '_parinfo')]) parinfo = np.unique(np.sort(parinfo)).tolist() testcases = [] for boundaries in ['zero', 'periodic', 'mixed']: for dtype in [float, complex]: testcases.append(UTGaussianWavefunctionFactory(boundaries, \ dtype)) for test in testcases: info = ['', test.__name__, test.__doc__.strip('\n')] + parinfo + [''] testsuite = defaultTestLoader.loadTestsFromTestCase(test) list(map(testrunner.stream.writeln, info)) testresult = testrunner.run(testsuite) # Provide feedback on failed tests if imported by test.py if __name__ == '__builtin__' and not testresult.wasSuccessful(): raise SystemExit('Test failed. Check ut_invops.log for details.') gpaw-0.11.0.13004/gpaw/test/parallel/fd_parallel.py0000664000175000017500000001072312553643472022011 0ustar jensjjensj00000000000000from __future__ import print_function import sys from ase.utils import devnull from gpaw import GPAW from gpaw import KohnShamConvergenceError from gpaw.utilities import compiled_with_sl from gpaw.mpi import world from ase.structure import molecule # Calculates energy and forces for various parallelizations tolerance = 4e-5 parallel = dict() basekwargs = dict(mode='fd', eigensolver='rmm-diis', maxiter=3, nbands=6, parallel=parallel) Eref = None Fref_av = None def run(formula='H2O', vacuum=2.0, cell=None, pbc=0, **morekwargs): print(formula, parallel) system = molecule(formula) kwargs = dict(basekwargs) kwargs.update(morekwargs) calc = GPAW(**kwargs) system.set_calculator(calc) system.center(vacuum) if cell is None: system.center(vacuum) else: system.set_cell(cell) system.set_pbc(pbc) try: system.get_potential_energy() except KohnShamConvergenceError: pass E = calc.hamiltonian.Etot F_av = calc.forces.calculate(calc.wfs, calc.density, calc.hamiltonian) global Eref, Fref_av if Eref is None: Eref = E Fref_av = F_av eerr = abs(E - Eref) ferr = abs(F_av - Fref_av).max() if calc.wfs.world.rank == 0: print('Energy', E) print() print('Forces') print(F_av) print() print('Errs', eerr, ferr) if eerr > tolerance or ferr > tolerance: if calc.wfs.world.rank == 0: stderr = sys.stderr else: stderr = devnull if eerr > tolerance: print('Failed!', file=stderr) print('E = %f, Eref = %f' % (E, Eref), file=stderr) msg = 'Energy err larger than tolerance: %f' % eerr if ferr > tolerance: print('Failed!', file=stderr) print('Forces:', file=stderr) print(F_av, file=stderr) print(file=stderr) print('Ref forces:', file=stderr) print(Fref_av, file=stderr) print(file=stderr) msg = 'Force err larger than tolerance: %f' % ferr print(file=stderr) print('Args:', file=stderr) print(formula, vacuum, cell, pbc, morekwargs, file=stderr) print(parallel, file=stderr) raise AssertionError(msg) # reference: # state-parallelization = 1, # domain-decomposition = (1, 2, 2) run() # state-parallelization = 2, # domain-decomposition = (1, 2, 1) parallel['band'] = 2 parallel['domain'] = (1, 2, world.size // 4) run() if compiled_with_sl(): # state-parallelization = 2, # domain-decomposition = (1, 2, 1) # with blacs parallel['sl_default'] = (2, 2, 2) run() # state-parallelization = 1, # domain-decomposition = (1, 2, 2) # with blacs del parallel['band'] del parallel['domain'] run() # perform spin polarization test parallel = dict() basekwargs = dict(mode='fd', eigensolver='rmm-diis', maxiter=3, #basis='dzp', #nbands=18, nbands=6, parallel=parallel) Eref = None Fref_av = None OH_kwargs = dict(formula='NH2', vacuum=1.5, pbc=1, spinpol=1, width=0.1) # start with empty parallel keyword # del parallel['sl_default'] # parallel = None # parallel = dict() # print parallel # del parallel['band'] parallel['domain'] = (1, 2, 1) # reference: # spin-polarization = 2, # state-paralllization = 1, # domain-decomposition = (1, 2, 1) run(**OH_kwargs) # spin-polarization = 2, # state-parallelization= 2, # domain-decomposition = (1, 1, 1) del parallel['domain'] parallel['band'] = 2 run(**OH_kwargs) # do last test with buffer_size keyword parallel['buffer_size'] = 50 run(**OH_kwargs) if compiled_with_sl(): # spin-polarization = 2, # state-parallelization= 2, # domain-decomposition = (1, 1, 1) # with blacs del parallel['buffer_size'] parallel['sl_default'] = (2, 1, 2) run(**OH_kwargs) # spin-polarization = 2, # state-parallelization = 1, # domain-decomposition = (1, 2, 1) # with blacs del parallel['band'] parallel['domain'] = (1, 2, 1) run(**OH_kwargs) # spin-polarization = 1, # state-parallelization = 1, # domain-decomposition = (1, 2, 2) parallel['domain'] = (1, 2, 2) run(**OH_kwargs) # do last test with buffer_size keyword parallel['buffer_size'] = 50 run(**OH_kwargs) gpaw-0.11.0.13004/gpaw/test/parallel/lcao_parallel.py0000664000175000017500000001032412553643472022333 0ustar jensjjensj00000000000000from __future__ import print_function import sys from ase.utils import devnull from gpaw import GPAW from gpaw import KohnShamConvergenceError from gpaw.utilities import compiled_with_sl from gpaw.mpi import world from ase.structure import molecule # Calculates energy and forces for various parallelizations tolerance = 4e-5 parallel = dict() basekwargs = dict(mode='lcao', maxiter=3, #basis='dzp', #nbands=18, nbands=6, parallel=parallel) Eref = None Fref_av = None def run(formula='H2O', vacuum=2.0, cell=None, pbc=0, **morekwargs): print(formula, parallel) system = molecule(formula) kwargs = dict(basekwargs) kwargs.update(morekwargs) calc = GPAW(**kwargs) system.set_calculator(calc) system.center(vacuum) if cell is None: system.center(vacuum) else: system.set_cell(cell) system.set_pbc(pbc) try: system.get_potential_energy() except KohnShamConvergenceError: pass E = calc.hamiltonian.Etot F_av = calc.forces.calculate(calc.wfs, calc.density, calc.hamiltonian) global Eref, Fref_av if Eref is None: Eref = E Fref_av = F_av eerr = abs(E - Eref) ferr = abs(F_av - Fref_av).max() if calc.wfs.world.rank == 0: print('Energy', E) print() print('Forces') print(F_av) print() print('Errs', eerr, ferr) if eerr > tolerance or ferr > tolerance: if calc.wfs.world.rank == 0: stderr = sys.stderr else: stderr = devnull if eerr > tolerance: print('Failed!', file=stderr) print('E = %f, Eref = %f' % (E, Eref), file=stderr) msg = 'Energy err larger than tolerance: %f' % eerr if ferr > tolerance: print('Failed!', file=stderr) print('Forces:', file=stderr) print(F_av, file=stderr) print(file=stderr) print('Ref forces:', file=stderr) print(Fref_av, file=stderr) print(file=stderr) msg = 'Force err larger than tolerance: %f' % ferr print(file=stderr) print('Args:', file=stderr) print(formula, vacuum, cell, pbc, morekwargs, file=stderr) print(parallel, file=stderr) raise AssertionError(msg) # reference: # state-parallelization = 1, # domain-decomposition = (1, 2, 2) run() # state-parallelization = 2, # domain-decomposition = (1, 2, 1) parallel['band'] = 2 parallel['domain'] = (1, 2, world.size // 4) run() if compiled_with_sl(): # state-parallelization = 2, # domain-decomposition = (1, 2, 1) # with blacs parallel['sl_default'] = (2, 2, 2) run() # state-parallelization = 1, # domain-decomposition = (1, 2, 2) # with blacs del parallel['band'] del parallel['domain'] run() # perform spin polarization test parallel = dict() basekwargs = dict(mode='lcao', maxiter=3, #basis='dzp', #nbands=18, nbands=6, parallel=parallel) Eref = None Fref_av = None OH_kwargs = dict(formula='NH2', vacuum=1.5, pbc=1, spinpol=1, width=0.1) # start with empty parallel keyword # del parallel['sl_default'] # parallel = None # parallel = dict() # print parallel # del parallel['band'] parallel['domain'] = (1, 2, 1) # reference: # spin-polarization = 2, # state-parallelization = 1, # domain-decomposition = (1, 2, 1) run(**OH_kwargs) # spin-polarization = 1, # state-parallelization= 2, # domain-decomposition = (1, 1, 1) del parallel['domain'] parallel['band'] = 2 run(**OH_kwargs) if compiled_with_sl(): # spin-polarization = 2, # state-parallelization = 2, # domain-decomposition = (1, 1, 1) # with blacs parallel['sl_default'] = (2, 1, 2) run(**OH_kwargs) # spin-polarization = 2, # state-parallelization = 1, # domain-decomposition = (1, 2, 1) del parallel['band'] parallel['domain'] = (1, 2, 1) run(**OH_kwargs) # spin-polarization = 1, # state-parallelization = 1, # domain-decomposition = (1, 2, 2) parallel['domain'] = (1, 2, 2) run(**OH_kwargs) gpaw-0.11.0.13004/gpaw/test/parallel/lcao_projections.py0000664000175000017500000000416712553643472023106 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from ase.structure import molecule from gpaw import GPAW from gpaw.eigensolvers.rmm_diis_old import RMM_DIIS from gpaw.lcao.projected_wannier import get_lcao_projections_HSP atoms = molecule('C2H2') atoms.center(vacuum=3.0) calc = GPAW(gpts=(32, 32, 48), eigensolver=RMM_DIIS()) atoms.set_calculator(calc) atoms.get_potential_energy() V_qnM, H_qMM, S_qMM, P_aqMi = get_lcao_projections_HSP( calc, bfs=None, spin=0, projectionsonly=False) # Test H and S eig = sorted(np.linalg.eigvals(np.linalg.solve(S_qMM[0], H_qMM[0])).real) eig_ref = np.array([-17.87911292, -13.24864985, -11.43106707, -7.12558127, -7.12558127, 0.59294531, 0.59294531, 3.92526888, 7.45117399, 26.73466374]) print(eig) assert np.allclose(eig, eig_ref) # Test V Vref_nM = np.array( [[-0.845 , -0. , 0.39836, 0. , -0.845 , 0. , -0.39836, -0. , -0.40865, -0.40865], [-0.43521, 0. , -0.61583, -0. , 0.43521, 0. , -0.61583, -0. , 0.60125, -0.60125], [ 0.12388, 0. , 0.62178, 0. , 0.12388, 0. , -0.62178, 0. , 0.50672, 0.50672], [-0. , -0.56118, 0. , 0.62074, -0. , -0.56118, -0. , 0.62074, -0. , -0. ], [-0. , 0.62074, -0. , 0.56118, 0. , 0.62074, 0. , 0.56118, -0. , -0. ], [ 0. , 0.5003 , 0. , 0.10456, 0. , -0.5003 , -0. , -0.10456, -0. , -0. ], [-0. , 0.10456, 0. , -0.5003 , -0. , -0.10456, -0. , 0.5003 , 0. , 0. ], [ 0.12449, -0. , -0.02292, 0. , -0.12449, 0. , -0.02292, -0. , 0.29925, -0.29925], [-0.05659, 0. , -0.02315, 0. , -0.05659, -0. , 0.02315, -0. , 0.27325, 0.27325], [-0.15622, 0. , 0.14149, -0. , 0.15622, 0. , 0.14149, -0. , 0.04507, -0.04507]]) ## np.set_printoptions(precision=5, suppress=1) ## from gpaw.mpi import rank ## if rank == 0: ## print V_qnM[0] print(abs(V_qnM[0]) - abs(Vref_nM)) # assert <--- this to zero gpaw-0.11.0.13004/gpaw/test/parallel/ut_parallel.py0000664000175000017500000001032312553643472022044 0ustar jensjjensj00000000000000 import sys import time import numpy as np from gpaw.mpi import world from gpaw.test.parunittest import ParallelTestCase, ParallelTextTestRunner, \ defaultParallelTestLoader, main # ------------------------------------------------------------------ class UTParallel(ParallelTestCase): """Parallel test suite of parallel test suite (don't ask).""" def reset_times(self, minwait=0.1, maxwait=0.2): if world.size == 1: return self.time_r = np.random.uniform(minwait, maxwait, size=world.size) world.broadcast(self.time_r, 0) def sleep_times(self): if world.size == 1: return time.sleep(self.time_r[world.rank]) class UTParallel_Succeeds(UTParallel): __doc__ = UTParallel.__doc__ passes = True numtests = 1 numerrors = 0 numfails = 0 def test_all_passes(self): self.reset_times() self.assertTrue(True) self.sleep_times() class UTParallel_Raises(UTParallel): __doc__ = UTParallel.__doc__ passes = False numtests = 2 numerrors = 2 numfails = 0 def test_master_raises(self): self.reset_times() if world.rank == 0: raise Exception('I am special!') self.sleep_times() # Nichols A. Romero # naromero@alcf.anl.gov # Feb. 28, 2010 # This test may not be valid # def test_slave_exits(self): # self.reset_times() # if world.rank == world.size-1: # sys.exit(-1) # self.sleep_times() def test_some_raises(self): self.reset_times() if world.rank % 3 == 0: raise RuntimeError elif world.rank % 3 == 1: raise IOError self.sleep_times() class UTParallel_Fails(UTParallel): __doc__ = UTParallel.__doc__ passes = False numtests = 4 numerrors = 0 numfails = 4 def test_master_fails(self): self.reset_times() self.assertTrue(world.rank!=0) self.sleep_times() def test_all_fails(self): self.reset_times() self.assertTrue(False) self.sleep_times() def test_odd_fails(self): self.reset_times() self.assertTrue(world.size>1 and world.rank%2==0) self.sleep_times() def test_even_fails(self): self.reset_times() self.assertTrue(world.size>1 and world.rank%2==1) self.sleep_times() # ------------------------------------------------------------------ if __name__ in ['__main__', '__builtin__']: # We may have been imported by test.py, if so we should redirect to logfile output = (__name__ == '__builtin__') and 'ut_parallel.log' or sys.stdout testrunner = ParallelTextTestRunner(stream=output, verbosity=2) testcases = [UTParallel_Succeeds, UTParallel_Raises, UTParallel_Fails] for test in testcases: info = '\n' + test.__name__ + '\n' + test.__doc__.strip('\n') + '\n' testsuite = defaultParallelTestLoader.loadTestsFromTestCase(test) testrunner.stream.writeln(info) testresult = testrunner.run(testsuite) verified = ((testresult.wasSuccessful() == test.passes) and (testresult.testsRun == test.numtests) and (len(testresult.errors) == test.numerrors) and (len(testresult.failures) == test.numfails)) if verified: conclusion = 'STATUS: %s performed as expected.' % test else: conclusion = 'STATUS: %s did not meet expectations.\n\n' \ ' ** Number of tests: %2d ran, %2d expected.\n%s\n' \ ' ** Number of errors: %2d raised, %2d expected.\n%s\n' \ ' ** Number of failures: %2d failed, %2d expected.\n%s' \ % (test, testresult.testsRun, test.numtests, testsuite, \ len(testresult.errors), test.numerrors, testresult.errors, \ len(testresult.failures), test.numfails, testresult.failures) separator0 = '*'*len(testresult.separator1) list(map(testrunner.stream.writeln, ['',separator0,conclusion,separator0,''])) # Provide feedback on failed tests if imported by test.py if __name__ == '__builtin__' and not verified: raise SystemExit('Test failed. Check ut_parallel.log for details.') gpaw-0.11.0.13004/gpaw/test/parallel/parallel_eigh.py0000664000175000017500000000457012553643472022337 0ustar jensjjensj00000000000000import numpy as np from gpaw.mpi import world, MASTER from gpaw.blacs import BlacsGrid from gpaw.blacs import Redistributor def parallel_eigh(matrixfile, blacsgrid=(4, 2), blocksize=64): """Diagonalize matrix in parallel""" assert np.prod(blacsgrid) == world.size grid = BlacsGrid(world, *blacsgrid) if world.rank == MASTER: H_MM = np.load(matrixfile) assert H_MM.ndim == 2 assert H_MM.shape[0] == H_MM.shape[1] NM = len(H_MM) else: NM = 0 NM = world.sum(NM) # Distribute matrix shape to all nodes # descriptor for the individual blocks block_desc = grid.new_descriptor(NM, NM, blocksize, blocksize) # descriptor for global array on MASTER local_desc = grid.new_descriptor(NM, NM, NM, NM) # Make some dummy array on all the slaves if world.rank != MASTER: H_MM = local_desc.zeros() assert local_desc.check(H_MM) # The local version of the matrix H_mm = block_desc.empty() # Distribute global array to smaller blocks redistributor = Redistributor(world, local_desc, block_desc) redistributor.redistribute(H_MM, H_mm) # Allocate arrays for eigenvalues and -vectors eps_M = np.empty(NM) C_mm = block_desc.empty() block_desc.diagonalize_ex(H_mm, C_mm, eps_M) # Collect eigenvectors on MASTER C_MM = local_desc.empty() redistributor2 = Redistributor(world, block_desc, local_desc) redistributor2.redistribute(C_mm, C_MM) # Return eigenvalues and -vectors on Master if world.rank == MASTER: return eps_M, C_MM else: return None, None from gpaw.utilities import compiled_with_sl if __name__ == '__main__' and compiled_with_sl(): # Test script which should be run on 1, 2, 4, or 8 CPUs if world.size == 1: blacsgrid = (1, 1) elif world.size == 2: blacsgrid = (2, 1) elif world.size == 4: blacsgrid = (2, 2) elif world.size == 8: blacsgrid = (4, 2) else: raise RuntimeError('Please use 1, 2, 4, or 8 nodes for this test') if world.rank == MASTER: a = np.diag(range(1,51)).astype(float) a.dump('H_50x50.pckl') eps, U = np.linalg.eigh(a) eps, U = parallel_eigh('H_50x50.pckl', blacsgrid, blocksize=6) if world.rank == MASTER: assert abs(eps - range(1, 51)).sum() < 1e-5 assert abs(U - np.identity(50)).sum() < 1e-5 gpaw-0.11.0.13004/gpaw/test/parallel/diamond_gllb.py0000664000175000017500000000457112553643472022163 0ustar jensjjensj00000000000000from __future__ import print_function from ase.lattice import bulk from sys import argv from ase.dft.kpoints import ibz_points, get_bandpath from gpaw import * from ase import * from gpaw.test import gen from gpaw import setup_paths import os """ Calculate diamond with various parallelizations with GLLBSC """ xc = 'GLLBSC' gen('C',xcname=xc) setup_paths.insert(0, '.') KSb = [] dxcb = [] eigensolver='rmm-diis' for band in [1,2,4]: # Calculate ground state atoms = bulk('C', 'diamond', a=3.567) calc = GPAW(h=0.15, kpts=(4,4,4), xc=xc, nbands = 8, eigensolver=eigensolver, parallel={'band':band}) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('Cgs.gpw') # Calculate accurate KS-band gap from band structure points = ibz_points['fcc'] # CMB is in G-X G = points['Gamma'] X = points['X'] kpts, x, X = get_bandpath([G, X], atoms.cell, npoints=12) calc = GPAW('Cgs.gpw', kpts=kpts, fixdensity=True, symmetry='off', nbands=8, convergence=dict(bands=8), eigensolver=eigensolver, parallel={'band':band}) calc.get_atoms().get_potential_energy() # Get the accurate KS-band gap homolumo = calc.occupations.get_homo_lumo(calc.wfs) homo, lumo = homolumo print("band gap ",(lumo-homo)*27.2) # Redo the ground state calculation calc = GPAW(h=0.15, kpts=(4,4,4), xc=xc, nbands = 8, eigensolver=eigensolver, parallel={'band':band}) atoms.set_calculator(calc) atoms.get_potential_energy() # And calculate the discontinuity potential with accurate band gap response = calc.hamiltonian.xc.xcs['RESPONSE'] response.calculate_delta_xc(homolumo=homolumo) calc.write('CGLLBSC.gpw') # Redo the band structure calculation atoms, calc = restart('CGLLBSC.gpw', kpts=kpts, fixdensity=True, symmetry='off', convergence=dict(bands=8)) atoms.get_potential_energy() response = calc.hamiltonian.xc.xcs['RESPONSE'] KS, dxc = response.calculate_delta_xc_perturbation() KSb.append(KS) dxcb.append(dxc) assert abs(KS+dxc-5.41)<0.10 #M. Kuisma et. al, Phys. Rev. B 82, 115106, QP gap for C, 5.41eV, expt. 5.48eV assert abs(KSb[0]-KSb[1])<1e-6 assert abs(KSb[0]-KSb[2])<1e-6 assert abs(dxcb[0]-dxcb[1])<1e-6 assert abs(dxcb[0]-dxcb[2])<1e-6 gpaw-0.11.0.13004/gpaw/test/parallel/scalapack.py0000664000175000017500000001532512553643472021471 0ustar jensjjensj00000000000000"""Test of ScaLAPACK diagonalize and inverse cholesky. The test generates a random symmetric matrix H0 and positive definite matrix S0 on a 1-by-1 BLACS grid. They are redistributed to a mprocs-by-nprocs BLACS grid, diagonalized in parallel, and eigenvalues are compared against LAPACK. Eigenvectors are not compared. """ from __future__ import print_function import sys import numpy as np from numpy.linalg import inv from gpaw.mpi import world, rank from gpaw.blacs import BlacsGrid, Redistributor, parallelprint from gpaw.utilities.tools import tri2full from gpaw.utilities import compiled_with_sl from gpaw.utilities.lapack import diagonalize, general_diagonalize, \ inverse_cholesky from gpaw.utilities.blas import rk, gemm from gpaw.utilities.scalapack import scalapack_general_diagonalize_dc, \ scalapack_general_diagonalize_ex, \ scalapack_diagonalize_dc, scalapack_diagonalize_ex, \ scalapack_inverse_cholesky, scalapack_inverse ## , \ ## scalapack_diagonalize_mr3, scalapack_general_diagonalize_mr3 tol = 1.0e-8 def main(N=72, seed=42, mprocs=2, nprocs=2, dtype=float): gen = np.random.RandomState(seed) grid = BlacsGrid(world, mprocs, nprocs) if (dtype==complex): epsilon = 1.0j else: epsilon = 0.0 # Create descriptors for matrices on master: glob = grid.new_descriptor(N, N, N, N) # print globA.asarray() # Populate matrices local to master: H0 = glob.zeros(dtype=dtype) + gen.rand(*glob.shape) S0 = glob.zeros(dtype=dtype) + gen.rand(*glob.shape) C0 = glob.empty(dtype=dtype) if rank == 0: # Complex case must have real numbers on the diagonal. # We make a simple complex Hermitian matrix below. H0 = H0 + epsilon * (0.1*np.tri(N, N, k= -N // nprocs) + 0.3*np.tri(N, N, k=-1)) S0 = S0 + epsilon * (0.2*np.tri(N, N, k= -N // nprocs) + 0.4*np.tri(N, N, k=-1)) # Make matrices symmetric rk(1.0, H0.copy(), 0.0, H0) rk(1.0, S0.copy(), 0.0, S0) # Overlap matrix must be semi-positive definite S0 = S0 + 50.0*np.eye(N, N, 0) # Hamiltonian is usually diagonally dominant H0 = H0 + 75.0*np.eye(N, N, 0) C0 = S0.copy() S0_inv = S0.copy() # Local result matrices W0 = np.empty((N),dtype=float) W0_g = np.empty((N),dtype=float) # Calculate eigenvalues / other serial results if rank == 0: diagonalize(H0.copy(), W0) general_diagonalize(H0.copy(), W0_g, S0.copy()) inverse_cholesky(C0) # result returned in lower triangle tri2full(S0_inv, 'L') S0_inv = inv(S0_inv) # tri2full(C0) # symmetrize assert glob.check(H0) and glob.check(S0) and glob.check(C0) # Create distributed destriptors with various block sizes: dist = grid.new_descriptor(N, N, 8, 8) # Distributed matrices: # We can use empty here, but end up with garbage on # on the other half of the triangle when we redistribute. # This is fine because ScaLAPACK does not care. H = dist.empty(dtype=dtype) S = dist.empty(dtype=dtype) Sinv = dist.empty(dtype=dtype) Z = dist.empty(dtype=dtype) C = dist.empty(dtype=dtype) Sinv = dist.empty(dtype=dtype) # Eigenvalues are non-BLACS matrices W = np.empty((N), dtype=float) W_dc = np.empty((N), dtype=float) W_mr3 = np.empty((N), dtype=float) W_g = np.empty((N), dtype=float) W_g_dc = np.empty((N), dtype=float) W_g_mr3 = np.empty((N), dtype=float) Glob2dist = Redistributor(world, glob, dist) Glob2dist.redistribute(H0, H, uplo='L') Glob2dist.redistribute(S0, S, uplo='L') Glob2dist.redistribute(S0, C, uplo='L') # C0 was previously overwritten Glob2dist.redistribute(S0, Sinv, uplo='L') # we don't test the expert drivers anymore since there # might be a buffer overflow error ## scalapack_diagonalize_ex(dist, H.copy(), Z, W, 'L') scalapack_diagonalize_dc(dist, H.copy(), Z, W_dc, 'L') ## scalapack_diagonalize_mr3(dist, H.copy(), Z, W_mr3, 'L') ## scalapack_general_diagonalize_ex(dist, H.copy(), S.copy(), Z, W_g, 'L') scalapack_general_diagonalize_dc(dist, H.copy(), S.copy(), Z, W_g_dc, 'L') ## scalapack_general_diagonalize_mr3(dist, H.copy(), S.copy(), Z, W_g_mr3, 'L') scalapack_inverse_cholesky(dist, C, 'L') if dtype == complex: # Only supported for complex for now scalapack_inverse(dist, Sinv, 'L') # Undo redistribute C_test = glob.empty(dtype=dtype) Sinv_test = glob.empty(dtype=dtype) Dist2glob = Redistributor(world, dist, glob) Dist2glob.redistribute(C, C_test) Dist2glob.redistribute(Sinv, Sinv_test) if rank == 0: ## diag_ex_err = abs(W - W0).max() diag_dc_err = abs(W_dc - W0).max() ## diag_mr3_err = abs(W_mr3 - W0).max() ## general_diag_ex_err = abs(W_g - W0_g).max() general_diag_dc_err = abs(W_g_dc - W0_g).max() ## general_diag_mr3_err = abs(W_g_mr3 - W0_g).max() inverse_chol_err = abs(C_test-C0).max() tri2full(Sinv_test,'L') inverse_err = abs(Sinv_test - S0_inv).max() ## print 'diagonalize ex err', diag_ex_err print('diagonalize dc err', diag_dc_err) ## print 'diagonalize mr3 err', diag_mr3_err ## print 'general diagonalize ex err', general_diag_ex_err print('general diagonalize dc err', general_diag_dc_err) ## print 'general diagonalize mr3 err', general_diag_mr3_err print('inverse chol err', inverse_chol_err) if dtype == complex: print('inverse err', inverse_err) else: ## diag_ex_err = 0.0 diag_dc_err = 0.0 ## diag_mr3_err = 0.0 ## general_diag_ex_err = 0.0 general_diag_dc_err = 0.0 ## general_diag_mr3_err = 0.0 inverse_chol_err = 0.0 inverse_err = 0.0 # We don't like exceptions on only one cpu ## diag_ex_err = world.sum(diag_ex_err) diag_dc_err = world.sum(diag_dc_err) ## diag_mr3_err = world.sum(diag_mr3_err) ## general_diag_ex_err = world.sum(general_diag_ex_err) general_diag_dc_err = world.sum(general_diag_dc_err) ## general_diag_mr3_err = world.sum(general_diag_mr3_err) inverse_chol_err = world.sum(inverse_chol_err) inverse_err = world.sum(inverse_err) ## assert diag_ex_err < tol assert diag_dc_err < tol ## assert diag_mr3_err < tol ## assert general_diag_ex_err < tol assert general_diag_dc_err < tol ## assert general_diag_mr3_err < tol assert inverse_chol_err < tol if dtype == complex: assert inverse_err < tol if __name__ in ['__main__', '__builtin__']: if not compiled_with_sl(): print('Not built with ScaLAPACK. Test does not apply.') else: main(dtype=complex) main(dtype=float) gpaw-0.11.0.13004/gpaw/test/parallel/arraydict_redist.py0000664000175000017500000000425612553643472023104 0ustar jensjjensj00000000000000import numpy as np from gpaw.mpi import world from gpaw.utilities.partition import AtomPartition from gpaw.arraydict import ArrayDict gen = np.random.RandomState(0) def shape(a): return (a, a // 2) # Shapes: (0, 0), (1, 0), (2, 1), ... natoms = 33 if world.size == 1: rank_a = np.zeros(natoms, int) else: # When on more than 2 cores, make sure that at least one core # (rank=0) has zero entries: lower = 0 if world.size == 2 else 1 rank_a = gen.randint(lower, world.size, natoms) assert (rank_a < world.size).all() serial = AtomPartition(world, np.zeros(natoms, int)) partition = AtomPartition(world, rank_a) even_partition = partition.as_even_partition() def check(atomdict, title): if world.rank == world.size // 2 or world.rank == 0: print('rank %d %s: %s' % (world.rank, title.rjust(10), atomdict)) # Create a normal, "well-behaved" dict against which to test arraydict. ref = dict(atomdict) #print atomdict assert set(atomdict.keys()) == set(ref.keys()) # check keys() for a in atomdict: # check __iter__, __getitem__ #print ref[a].shape, atomdict[a].shape #ref[a].shape, atomdict[a].shape #print ref[a], atomdict[a] #assert 1#ref[a] is atomdict[a] assert ref[a] is atomdict[a] values = atomdict.values() for i, key in enumerate(atomdict): # AtomDict guarantees fixed ordering of keys. Check that # values() ordering is consistent with loop ordering: assert values[i] is atomdict[key] items = list(atomdict.items()) for i, (key, item) in enumerate(atomdict.items()): assert item is atomdict[key] assert item is ref[key] assert items[i][0] == key assert items[i][1] is item # Hopefully this should verify all the complicated stuff ad = ArrayDict(partition, shape, float) for key in ad: ad[key][:] = key array0 = ad.toarray() ad0 = dict(ad) check(ad, 'new') ad.redistribute(even_partition) array1 = ad.toarray() if world.rank > 1: assert array1.shape != array0.shape check(ad, 'even') ad.redistribute(serial) check(ad, 'serial') ad.redistribute(partition) check(ad, 'back') array2 = ad.toarray() assert (array0 == array2).all() gpaw-0.11.0.13004/gpaw/test/parallel/overlap.py0000664000175000017500000000704212553643472021214 0ustar jensjjensj00000000000000from __future__ import print_function from time import time import sys from fractions import gcd import numpy as np from gpaw import parsize_domain, parsize_bands from gpaw.band_descriptor import BandDescriptor from gpaw.grid_descriptor import GridDescriptor from gpaw.kohnsham_layouts import BandLayouts from gpaw.mpi import world, distribute_cpus from gpaw.utilities.lapack import inverse_cholesky from gpaw.hs_operators import MatrixOperator G = 120 # number of grid points (G x G x G) N = 2000 # number of bands repeats = 20 try: N = int(sys.argv[1]) K = int(sys.argv[2]) except (IndexError, ValueError): N = 6 K = 3 repeats = 3 # B: number of band groups # D: number of domains if parsize_bands is None: if parsize_domain is None: B = gcd(N, world.size) D = world.size // B else: B = world.size // np.prod(parsize_domain) D = parsize_domain else: B = parsize_bands D = world.size // B M = N // B # number of bands per group assert M * B == N, 'M=%d, B=%d, N=%d' % (M,B,N) h = 0.2 # grid spacing a = h * G # side length of box assert np.prod(D) * B == world.size, 'D=%s, B=%d, W=%d' % (D,B,world.size) # Set up communicators: comms = distribute_cpus(parsize_domain=D, parsize_bands=B, nspins=1, nibzkpts=1) domain_comm, kpt_comm, band_comm, block_comm = \ [comms[name] for name in ['d', 'k', 'b', 'K']] assert kpt_comm.size == 1 if world.rank == 0: print('MPI: %d domains, %d band groups' % (domain_comm.size, band_comm.size)) # Set up band and grid descriptors: bd = BandDescriptor(N, band_comm, False) gd = GridDescriptor((G, G, G), (a, a, a), True, domain_comm, parsize=D) ksl = BandLayouts(gd, bd, block_comm, float) # Random wave functions: psit_mG = gd.empty(M) for m in range(M): np.random.seed(world.rank * M + m) psit_mG[m] = np.random.uniform(-0.5, 0.5, tuple(gd.n_c)) if world.rank == 0: print('Size of wave function array:', psit_mG.shape) P_ani = {0: psit_mG[:, :2, 0, 0].copy(), 1: psit_mG[:, -1, -1, -3:].copy()} if 0: X = M // K assert K * X == M if G**3 // D // K * K < G**3 // D: X += 1 print(X) work1_xG = gd.empty(X) work2_xG = gd.empty(X) def run(psit_mG): overlap = MatrixOperator(ksl, K) if 0: overlap.work1_xG = work1_xG overlap.work2_xG = work2_xG #S_nn = np.empty((N, N)) def S(x): return x dS_aii = {0: np.ones((2, 2)) * 0.123, 1: np.ones((3, 3)) * 0.321} def dS(a, P_ni): return np.dot(P_ni, dS_aii[a]) S_nn = overlap.calculate_matrix_elements(psit_mG, P_ani, S, dS) t1 = time() if world.rank == 0: print(S_nn.round(5)) inverse_cholesky(S_nn) C_nn = S_nn t2 = time() if world.rank == 0: print('Cholesky Time %f' % (t2-t1)) # Distribute matrix: world.broadcast(C_nn, 0) psit_mG = overlap.matrix_multiply(C_nn, psit_mG, P_ani) if world.rank == 0: print('Made it past matrix multiply') # Check: S_nn = overlap.calculate_matrix_elements(psit_mG, P_ani, S, dS) assert not(P_ani[0] - psit_mG[:, :2, 0, 0]).round(10).any() assert not(P_ani[1] - psit_mG[:, -1, -1, -3:]).round(10).any() if world.rank == 0: for n in range(N): assert abs(S_nn[n, n] - 1.0) < 1e-10 assert not S_nn[n + 1:, n].round(10).any() return psit_mG ta = time() # Do twenty iterations for x in range(repeats): psit_mG = run(psit_mG) tb = time() if world.rank == 0: print('Total Time %f' % (tb -ta)) gpaw-0.11.0.13004/gpaw/test/parallel/lcao_complicated.py0000664000175000017500000000635012553643472023027 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from ase.lattice.surface import fcc111 from gpaw.mpi import world from gpaw import GPAW, PoissonSolver from gpaw.utilities import compiled_with_sl # This test verifies that energy and forces are (approximately) # parallelization independent # # Tests the LCAO energy and forces in non-orthogonal cell with # simultaneous parallelization over bands, domains and k-points (if # enough CPUs are available), both with and without scalapack # (if scalapack is available). # # Run with 1, 2, 4 or 8 (best) CPUs. # # This test covers many cases not caught by lcao_parallel or # lcao_parallel_kpt # # Written November 24, 2011, r8567 system = fcc111('Au', size=(1, 3, 1)) system.numbers[0] = 8 # It is important that the number of atoms is uneven; this # tests the case where the band parallelization does not match # the partitioning of orbitals between atoms (the middle atom has orbitals # on distinct band descriptor ranks) system.center(vacuum=3.5, axis=2) system.rattle(stdev=0.2, seed=17) #from ase.visualize import view #view(system) #system.set_pbc(0) #system.center(vacuum=3.5) from gpaw import FermiDirac, LCAO def calculate(parallel, comm=world, Eref=None, Fref=None): calc = GPAW(mode=LCAO(atomic_correction='scipy'), basis=dict(O='dzp', Au='sz(dzp)'), occupations=FermiDirac(0.1), kpts=(4, 1, 1), #txt=None, communicator=comm, poissonsolver=PoissonSolver(relax='J', eps=1e-8), nbands=16, parallel=parallel, h=0.35) system.set_calculator(calc) E = system.get_potential_energy() F = system.get_forces() if world.rank == 0: print('Results') print('-----------') print(E) print(F) print('-----------') if Eref is not None: Eerr = abs(E - Eref) assert Eerr < 1e-8, 'Bad E: err=%f; parallel=%s' % (Eerr, parallel) if Fref is not None: Ferr = np.abs(F - Fref).max() assert Ferr < 1e-6, 'Bad F: err=%f; parallel=%s' % (Ferr, parallel) return E, F # First calculate reference energy and forces E and F # # If we want to really dumb things down, enable this to force an # entirely serial calculation: if 0: serial = world.new_communicator([0]) E = 0.0 F = np.zeros((len(system), 3)) if world.rank == 0: E, F = calculate({}, serial) E = world.sum(E) world.sum(F) else: # Normally we'll just do it in parallel; # that case is covered well by other tests, so we can probably trust it E, F = calculate({}, world) def check(parallel): return calculate(parallel, comm=world, Eref=E, Fref=F) assert world.size in [1, 2, 4, 8], ('Number of CPUs %d not supported' % world.size) parallel = dict(domain=1, band=1) sl_cpus = world.size if world.size % 2 == 0: parallel['band'] = 2 if world.size % 4 == 0: parallel['domain'] = 2 # If size is 8, this will also use kpt parallelization. This test should # run with 8 CPUs for best coverage of parallelizations if world.size == 8: sl_cpus = 4 if world.size > 1: check(parallel) if compiled_with_sl(): parallel['sl_auto'] = True check(parallel) gpaw-0.11.0.13004/gpaw/test/parallel/lcao_parallel_kpt.py0000664000175000017500000001027112553643472023212 0ustar jensjjensj00000000000000from __future__ import print_function import sys from ase import Atoms from ase.utils import devnull from gpaw import GPAW from gpaw import KohnShamConvergenceError from gpaw.utilities import compiled_with_sl from ase.structure import molecule # Calculates energy and forces for various parallelizations tolerance = 4e-5 parallel = dict() basekwargs = dict(mode='lcao', maxiter=3, #basis='dzp', #nbands=18, nbands=6, kpts=(4,4,4), # 8 kpts in the IBZ parallel=parallel) Eref = None Fref_av = None def run(formula='H2O', vacuum=1.5, cell=None, pbc=1, **morekwargs): print(formula, parallel) system = molecule(formula) kwargs = dict(basekwargs) kwargs.update(morekwargs) calc = GPAW(**kwargs) system.set_calculator(calc) system.center(vacuum) if cell is None: system.center(vacuum) else: system.set_cell(cell) system.set_pbc(pbc) try: system.get_potential_energy() except KohnShamConvergenceError: pass E = calc.hamiltonian.Etot F_av = calc.forces.calculate(calc.wfs, calc.density, calc.hamiltonian) global Eref, Fref_av if Eref is None: Eref = E Fref_av = F_av eerr = abs(E - Eref) ferr = abs(F_av - Fref_av).max() if calc.wfs.world.rank == 0: print('Energy', E) print() print('Forces') print(F_av) print() print('Errs', eerr, ferr) if eerr > tolerance or ferr > tolerance: if calc.wfs.world.rank == 0: stderr = sys.stderr else: stderr = devnull if eerr > tolerance: print('Failed!', file=stderr) print('E = %f, Eref = %f' % (E, Eref), file=stderr) msg = 'Energy err larger than tolerance: %f' % eerr if ferr > tolerance: print('Failed!', file=stderr) print('Forces:', file=stderr) print(F_av, file=stderr) print(file=stderr) print('Ref forces:', file=stderr) print(Fref_av, file=stderr) print(file=stderr) msg = 'Force err larger than tolerance: %f' % ferr print(file=stderr) print('Args:', file=stderr) print(formula, vacuum, cell, pbc, morekwargs, file=stderr) print(parallel, file=stderr) raise AssertionError(msg) # reference: # kpt-parallelization = 8, # state-parallelization = 1, # domain-decomposition = (1,1,1) run() # kpt-parallelization = 2, # state-parallelization = 2, # domain-decomposition = (1,2,1) parallel['band'] = 2 parallel['domain'] = (1, 2, 1) run() if compiled_with_sl(): # kpt-parallelization = 2, # state-parallelization = 2, # domain-decomposition = (1,2,1) # with blacs parallel['sl_default'] = (2, 2, 2) run() # perform spin polarization test parallel = dict() basekwargs = dict(mode='lcao', maxiter=3, nbands=6, kpts=(4,4,4), # 8 kpts in the IBZ parallel=parallel) Eref = None Fref_av = None OH_kwargs = dict(formula='NH2', vacuum=1.5, pbc=1, spinpol=1, width=0.1) # reference: # kpt-parallelization = 4, # spin-polarization = 2, # state-parallelization = 1, # domain-decomposition = (1, 1, 1) run(**OH_kwargs) # kpt-parallelization = 2, # spin-polarization = 2, # state-parallelization = 1, # domain-decomposition = (1, 2, 1) parallel['domain'] = (1, 2, 1) run(**OH_kwargs) # kpt-parallelization = 2, # spin-polarization = 2, # state-parallelization = 2, # domain-decomposition = (1, 1, 1) del parallel['domain'] parallel['band'] = 2 run(**OH_kwargs) # test for forces is failing in this case! if compiled_with_sl(): # kpt-parallelization = 2, # spin-polarization = 2, # state-parallelization = 2, # domain-decomposition = (1, 2, 1) # with blacs parallel['domain'] = (1, 2, 1) parallel['sl_default'] = (2, 1, 2) run(**OH_kwargs) # kpt-parallelization = 2, # spin-polarization = 2, # state-parallelization = 2, # domain-decomposition = (1, 2, 1) # with blacs parallel['sl_default'] = (2, 2, 2) run(**OH_kwargs) gpaw-0.11.0.13004/gpaw/test/parallel/pblas.py0000664000175000017500000001450512553643472020647 0ustar jensjjensj00000000000000"""Test of PBLAS Level 2 & 3 : rk, r2k, gemv, gemm. The test generates random matrices A0, B0, X0, etc. on a 1-by-1 BLACS grid. They are redistributed to a mprocs-by-nprocs BLACS grid, BLAS operations are performed in parallel, and results are compared against BLAS. """ from __future__ import print_function import sys import numpy as np from gpaw.mpi import world, rank from gpaw.test import equal from gpaw.blacs import BlacsGrid, Redistributor, parallelprint from gpaw.utilities import compiled_with_sl from gpaw.utilities.blas import gemm, gemv, r2k, rk from gpaw.utilities.scalapack import pblas_simple_gemm, pblas_simple_gemv, \ pblas_simple_r2k, pblas_simple_rk, pblas_simple_hemm import _gpaw tol = 4.0e-13 # may need to be be increased if the mprocs-by-nprocs \ # BLACS grid becomes larger def main(M=160, N=120, K=140, seed=42, mprocs=2, nprocs=2, dtype=float): gen = np.random.RandomState(seed) grid = BlacsGrid(world, mprocs, nprocs) if (dtype==complex): epsilon = 1.0j else: epsilon = 0.0 # Create descriptors for matrices on master: globA = grid.new_descriptor(M, K, M, K) globB = grid.new_descriptor(K, N, K, N) globC = grid.new_descriptor(M, N, M, N) globZ = grid.new_descriptor(K, K, K, K) globX = grid.new_descriptor(K, 1, K, 1) globY = grid.new_descriptor(M, 1, M, 1) globD = grid.new_descriptor(M, K, M, K) globS = grid.new_descriptor(M, M, M, M) globU = grid.new_descriptor(M, M, M, M) globHEC = grid.new_descriptor(K,K, K, K) # print globA.asarray() # Populate matrices local to master: A0 = gen.rand(*globA.shape) + epsilon * gen.rand(*globA.shape) B0 = gen.rand(*globB.shape) + epsilon * gen.rand(*globB.shape) D0 = gen.rand(*globD.shape) + epsilon * gen.rand(*globD.shape) X0 = gen.rand(*globX.shape) + epsilon * gen.rand(*globX.shape) # HEC = HEA * B HEA0 = gen.rand(*globHEC.shape) + epsilon * gen.rand(*globHEC.shape) if world.rank == 0: HEA0 = HEA0 + HEA0.T.conjugate() # Make H0 hermitean # Local result matrices Y0 = globY.empty(dtype=dtype) C0 = globC.zeros(dtype=dtype) Z0 = globZ.zeros(dtype=dtype) S0 = globS.zeros(dtype=dtype) # zeros needed for rank-updates U0 = globU.zeros(dtype=dtype) # zeros needed for rank-updates HEC0 = globB.zeros(dtype=dtype) # Local reference matrix product: if rank == 0: # C0[:] = np.dot(A0, B0) gemm(1.0, B0, A0, 0.0, C0) #gemm(1.0, A0, A0, 0.0, Z0, transa='t') print(A0.shape, Z0.shape) Z0[:] = np.dot(A0.T, A0) # Y0[:] = np.dot(A0, X0) gemv(1.0, A0, X0.ravel(), 0.0, Y0.ravel()) r2k(1.0, A0, D0, 0.0, S0) rk(1.0, A0, 0.0, U0) HEC0[:] = np.dot(HEA0, B0) sM, sN = HEA0.shape # We don't use upper diagonal for i in range(sM): for j in range(sN): if i 1: H.positions[0, 0] += 0.01 * rank try: e0 = H.get_potential_energy() except ValueError as e: err_ranks = e.args[1] assert (err_ranks == range(1, size)).all() gpaw-0.11.0.13004/gpaw/test/parallel/scalapack_pdlasrt_hang.py0000664000175000017500000000130612553643472024211 0ustar jensjjensj00000000000000# { -1, -1}: On entry to PDLASRT parameter number 9 had an illegal value # works with 'sl_default': (2, 2, 32) from ase.lattice.surface import fcc100, add_adsorbate from gpaw import GPAW, ConvergenceError from gpaw.mpi import world from gpaw.utilities import compiled_with_sl assert world.size == 4 slab = fcc100('Cu', size=(2, 2, 2)) add_adsorbate(slab,'O', 1.1, 'hollow') slab.center(vacuum=3.0, axis=2) calc = GPAW(mode='lcao', kpts=(2, 2, 1), txt='-', maxiter=1,) if compiled_with_sl(): calc.set(parallel={'domain': (1, 1, 4), 'sl_default': (2, 2, 64)}) slab.set_calculator(calc) try: slab.get_potential_energy() except ConvergenceError: pass gpaw-0.11.0.13004/gpaw/test/parallel/__init__.py0000664000175000017500000000000112553643472021267 0ustar jensjjensj00000000000000 gpaw-0.11.0.13004/gpaw/test/parallel/realspace_blacs.py0000664000175000017500000000746512553643472022660 0ustar jensjjensj00000000000000from __future__ import print_function """Test of BLACS Redistributor. Requires at least 8 MPI tasks. """ import sys import numpy as np from gpaw.band_descriptor import BandDescriptor from gpaw.grid_descriptor import GridDescriptor from gpaw.mpi import world, distribute_cpus from gpaw.utilities import compiled_with_sl from gpaw.utilities.scalapack import scalapack_set, scalapack_zero from gpaw.blacs import BlacsGrid, Redistributor, parallelprint from gpaw.kohnsham_layouts import BlacsBandLayouts G = 120 # number of grid points (G x G x G) N = 10 # number of bands # B: number of band groups # D: number of domains B = 2 D = 2 n = N // B # number of bands per group assert n * B == N, 'n=%d, B=%d, N=%d' % (n, B, N) h = 0.2 # grid spacing a = h * G # side length of box # Set up communicators: comms = distribute_cpus(parsize_domain=D, parsize_bands=B, nspins=1, nibzkpts=2) domain_comm, kpt_comm, band_comm, block_comm = \ [comms[name] for name in ['d', 'k', 'b', 'K']] assert world.size == D*B*kpt_comm.size if world.rank == 0: print('MPI: %d domains, %d band groups, %d kpts' % (domain_comm.size, band_comm.size, kpt_comm.size)) # Set up band and grid descriptors: bd = BandDescriptor(N, band_comm, False) gd = GridDescriptor((G, G, G), (a, a, a), True, domain_comm, parsize=D) mcpus, ncpus, blocksize = 2, 2, 6 def blacs_diagonalize(ksl, H_Nn, U_nN, eps_n): # H_Nn must be lower triangular or symmetric, # but not upper triangular. # U_nN will be symmetric # U_Nn needs to be simultaneously compatible with: # 1. outdescriptor # 2. broadcast with gd.comm # We will do this with a dummy buffer U2_nN bmd = ksl.new_descriptor() H_nn = bmd.redistribute_output(H_Nn) ksl.diagonalize(H_nn, eps_n) U_nn = H_nn del H_nn U_nN[:] = bmd.redistribute_input(U_nn) def blacs_inverse_cholesky(ksl, S_Nn, C_nN): # S_Nn must be upper triangular or symmetric, # but not lower triangular. # C_nN will be upper triangular. # S_Nn needs to be simultaneously compatible with: # 1. indescriptor # 2. outdescriptor # 3. broadcast with gd.comm # We will do this with a number of separate buffers. bmd = ksl.new_descriptor() S_nn = bmd.redistribute_output(S_Nn) ksl.inverse_cholesky(S_nn) C_nn = S_nn del S_nn C_nN[:] = bmd.redistribute_input(C_nn) def main(seed=42, dtype=float): ksl = BlacsBandLayouts(gd, bd, block_comm, dtype, mcpus, ncpus, blocksize) nbands = bd.nbands mynbands = bd.mynbands # Diagonalize # We would *not* create H_Nn in the real-space code this way. # This is just for testing purposes. # Note after MPI_Reduce, only meaningful information on gd masters H_Nn = np.zeros((nbands, mynbands), dtype=dtype) U_nN = np.empty((mynbands, nbands), dtype=dtype) if ksl.Nndescriptor: # hack scalapack_set(ksl.Nndescriptor, H_Nn, 0.1, 75.0, 'L') else: assert gd.comm.rank != 0 print("H_Nn") parallelprint(world, H_Nn) eps_n = np.zeros(bd.mynbands) blacs_diagonalize(ksl, H_Nn, U_nN, eps_n) print("U_nN") parallelprint(world, U_nN) print("eps_n") parallelprint(world, eps_n) # Inverse Cholesky S_Nn = np.zeros((nbands, mynbands), dtype=dtype) C_nN = np.empty((mynbands, nbands), dtype=dtype) if ksl.Nndescriptor: # hack scalapack_set(ksl.Nndescriptor, S_Nn, 0.1, 75.0, 'L') else: assert gd.comm.rank != 0 print("S_Nn") parallelprint(world, S_Nn) blacs_inverse_cholesky(ksl, S_Nn, C_nN) print("C_nN") parallelprint(world, C_nN) if __name__ in ['__main__', '__builtin__']: if not compiled_with_sl(): print('Not built with ScaLAPACK. Test does not apply.') else: main(dtype=float) main(dtype=complex) gpaw-0.11.0.13004/gpaw/test/parallel/lcao_hamiltonian.py0000664000175000017500000000214012553643472023037 0ustar jensjjensj00000000000000import numpy as np from ase import Atoms from gpaw import GPAW, restart, setup_paths from gpaw.lcao.tools import get_lcao_hamiltonian from gpaw.mpi import world from gpaw.atom.basis import BasisMaker from gpaw.test import equal if world.rank == 0: basis = BasisMaker('Li', 'szp').generate(1, 1) basis.write_xml() world.barrier() if setup_paths[0] != '.': setup_paths.insert(0, '.') if 1: a = 2.7 bulk = Atoms('Li', pbc=True, cell=[a, a, a]) calc = GPAW(gpts=(8, 8, 8), kpts=(4, 4, 4), mode='lcao', basis='szp') bulk.set_calculator(calc) e = bulk.get_potential_energy() niter = calc.get_number_of_iterations() calc.write('temp.gpw') atoms, calc = restart('temp.gpw') H_skMM, S_kMM = get_lcao_hamiltonian(calc) eigs = calc.get_eigenvalues(kpt=2) if world.rank == 0: eigs2 = sorted(np.linalg.eigvals(np.linalg.solve(S_kMM[2], H_skMM[0, 2])).real) assert abs(sum(eigs - eigs2)) < 1e-8 energy_tolerance = 0.00003 niter_tolerance = 0 equal(e, -1.82847, energy_tolerance) equal(niter, 5, niter_tolerance) gpaw-0.11.0.13004/gpaw/test/parallel/scalapack_diag_simple.py0000664000175000017500000000432212553643472024021 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np # Set-up a simple matrix in parallel, diagonalize using ScaLAPACK # D&C driver then compare *eigenvalues* with serial LAPACK diagonlize from time import time from gpaw.blacs import BlacsGrid, parallelprint from gpaw.mpi import world, rank, size from gpaw.utilities import compiled_with_sl from gpaw.utilities.lapack import diagonalize from gpaw.utilities.scalapack import scalapack_diagonalize_dc, scalapack_set, \ scalapack_zero switch_uplo = {'U': 'L', 'L': 'U'} rank = world.rank # tol tol = 5e-12 # eigenvalue tolerance def main(nbands=1000, mprocs=2, mb=64): # Set-up BlacsGrud grid = BlacsGrid(world, mprocs, mprocs) # Create descriptor nndesc = grid.new_descriptor(nbands, nbands, mb, mb) H_nn = nndesc.empty(dtype=float) # outside the BlacsGrid these are size zero C_nn = nndesc.empty(dtype=float) # outside the BlacsGrid these are size zero eps_N = np.empty((nbands), dtype=float) # replicated array on all MPI tasks # Fill ScaLAPACK array alpha = 0.1 # off-diagonal beta = 75.0 # diagonal uplo = 'L' # lower-triangular scalapack_set(nndesc, H_nn, alpha, beta, uplo) scalapack_zero(nndesc, H_nn, switch_uplo[uplo]) t1 = time() # either interface will work, we recommend use the latter interface # scalapack_diagonalize_dc(nndesc, H_nn.copy(), C_nn, eps_N, 'L') nndesc.diagonalize_dc(H_nn.copy(), C_nn, eps_N) t2 = time() world.broadcast(eps_N, 0) # all MPI tasks now have eps_N world.barrier() # wait for everyone to finish if rank == 0: print('ScaLAPACK diagonalize_dc', t2-t1) # Create replicated NumPy array diagonal = np.eye(nbands,dtype=float) offdiagonal = np.tril(np.ones((nbands,nbands)), -1) H0 = beta*diagonal + alpha*offdiagonal E0 = np.empty((nbands), dtype=float) t1 = time() diagonalize(H0,E0) t2 = time() if rank == 0: print('LAPACK diagonalize', t2-t1) delta = abs(E0-eps_N).max() if rank == 0: print(delta) assert delta < tol if __name__ in ['__main__', '__builtin__']: if not compiled_with_sl(): print('Not built with ScaLAPACK. Test does not apply.') else: main() gpaw-0.11.0.13004/gpaw/test/parallel/fd_parallel_kpt.py0000664000175000017500000001066312553643472022672 0ustar jensjjensj00000000000000from __future__ import print_function import sys from ase import Atoms from ase.utils import devnull from gpaw import GPAW, FermiDirac from gpaw import KohnShamConvergenceError from gpaw.utilities import compiled_with_sl from ase.structure import molecule # Calculates energy and forces for various parallelizations tolerance = 4e-5 parallel = dict() basekwargs = dict(mode='fd', eigensolver='rmm-diis', maxiter=3, #basis='dzp', #nbands=18, nbands=6, kpts=(4,4,4), # 8 kpts in the IBZ parallel=parallel) Eref = None Fref_av = None def run(formula='H2O', vacuum=1.5, cell=None, pbc=1, **morekwargs): print(formula, parallel) system = molecule(formula) kwargs = dict(basekwargs) kwargs.update(morekwargs) calc = GPAW(**kwargs) system.set_calculator(calc) system.center(vacuum) if cell is None: system.center(vacuum) else: system.set_cell(cell) system.set_pbc(pbc) try: system.get_potential_energy() except KohnShamConvergenceError: pass E = calc.hamiltonian.Etot F_av = calc.forces.calculate(calc.wfs, calc.density, calc.hamiltonian) global Eref, Fref_av if Eref is None: Eref = E Fref_av = F_av eerr = abs(E - Eref) ferr = abs(F_av - Fref_av).max() if calc.wfs.world.rank == 0: print('Energy', E) print() print('Forces') print(F_av) print() print('Errs', eerr, ferr) if eerr > tolerance or ferr > tolerance: if calc.wfs.world.rank == 0: stderr = sys.stderr else: stderr = devnull if eerr > tolerance: print('Failed!', file=stderr) print('E = %f, Eref = %f' % (E, Eref), file=stderr) msg = 'Energy err larger than tolerance: %f' % eerr if ferr > tolerance: print('Failed!', file=stderr) print('Forces:', file=stderr) print(F_av, file=stderr) print(file=stderr) print('Ref forces:', file=stderr) print(Fref_av, file=stderr) print(file=stderr) msg = 'Force err larger than tolerance: %f' % ferr print(file=stderr) print('Args:', file=stderr) print(formula, vacuum, cell, pbc, morekwargs, file=stderr) print(parallel, file=stderr) raise AssertionError(msg) # reference: # kpt-parallelization = 8, # state-parallelization = 1, # domain-decomposition = (1,1,1) run() # kpt-parallelization = 2, # state-parallelization = 2, # domain-decomposition = (1,2,1) parallel['band'] = 2 parallel['domain'] = (1, 2, 1) run() if compiled_with_sl(): # kpt-parallelization = 2, # state-parallelization = 2, # domain-decomposition = (1,2,1) # with blacs parallel['sl_default'] = (2, 2, 2) run() # perform spin polarization test parallel = dict() basekwargs = dict(mode='fd', eigensolver='rmm-diis', maxiter=3, nbands=6, kpts=(4,4,4), # 8 kpts in the IBZ parallel=parallel) Eref = None Fref_av = None OH_kwargs = dict(formula='NH2', vacuum=1.5, pbc=1, spinpol=1, occupations=FermiDirac(width=0.1)) # reference: # kpt-parallelization = 4, # spin-polarization = 2, # state-parallelization = 1, # domain-decomposition = (1,1,1) run(**OH_kwargs) # kpt-parallelization = 2, # spin-polarization = 2, # domain-decomposition = (1, 2, 1) parallel['domain'] = (1, 2, 1) run(**OH_kwargs) # kpt-parallelization = 2, # spin-polarization = 2, # state-parallelization = 2, # domain-decomposition = (1, 1, 1) del parallel['domain'] parallel['band'] = 2 run(**OH_kwargs) # do last test plus buffer_size keyword parallel['buffer_size'] = 150 run(**OH_kwargs) if compiled_with_sl(): # kpt-parallelization = 2, # spin-polarization = 2, # state-parallelization = 2, # domain-decomposition = (1, 2, 1) # with blacs del parallel['buffer_size'] parallel['domain'] = (1, 2, 1) parallel['sl_default'] = (2, 1, 2) run(**OH_kwargs) # kpt-parallelization = 2, # state-parallelization = 2, # domain-decomposition = (1, 2, 1) # with blacs parallel['sl_default'] = (2, 2, 2) run(**OH_kwargs) # do last test plus buffer_size keyword parallel['buffer_size'] = 150 run(**OH_kwargs) gpaw-0.11.0.13004/gpaw/test/integral4.py0000664000175000017500000000064412553643471017641 0ustar jensjjensj00000000000000import numpy as np import numpy.random as ra from gpaw.setup import create_setup from gpaw.xc import XC x = 0.000001 ra.seed(8) xc = XC('LDA') s = create_setup('H', xc) ni = s.ni nii = ni * (ni + 1) // 2 D_p = 0.1 * ra.random((1, nii)) + 0.2 H_p = np.zeros(nii) def f(x): return x J_pp = s.xc_correction.four_phi_integrals(D_p, f) # Check integrals using two_phi_integrals function and finite differences: pass gpaw-0.11.0.13004/gpaw/test/ase3k_version.py0000664000175000017500000000032212553643471020514 0ustar jensjjensj00000000000000from gpaw.version import ase_required_version from ase.version import version_base as ase_version assert ([int(v) for v in ase_version.split('.')] >= [int(v) for v in ase_required_version.split('.')]) gpaw-0.11.0.13004/gpaw/test/fermisplit.py0000664000175000017500000000300112553643471020114 0ustar jensjjensj00000000000000# this test should coverage the save and restore of # fermi-levels when using fixmagmom: # # yes, fermi-level-splitting sounds a little bit strange import numpy as np from ase import Atoms from gpaw import GPAW, FermiDirac, MixerSum from gpaw.test import equal modes = ['gpw'] try: import _gpaw_hdf5 modes.append('hdf5') except ImportError: pass calc=GPAW(occupations=FermiDirac(width=0.1, fixmagmom=True), mixer=MixerSum(beta=0.05, nmaxold=3, weight=50.0), convergence={'energy':0.1, 'eigenstates': 1.5e-1, 'density': 1.5e-1}) atoms = Atoms('Cr', pbc=False) atoms.center(vacuum=4) mm = [1] * 1 mm[0] = 6. atoms.set_initial_magnetic_moments(mm) atoms.set_calculator(calc) atoms.get_potential_energy() ef1=calc.occupations.get_fermi_levels_mean() efsplit1=calc.occupations.get_fermi_splitting() ef3=calc.occupations.get_fermi_levels() for mode in modes: calc.write('test.%s' % mode) for mode in modes: # check number one: is the splitting value saved? readtest=GPAW("test.%s" % mode) ef2=readtest.occupations.get_fermi_levels_mean() efsplit2=readtest.occupations.get_fermi_splitting() # numpy arrays ef4=readtest.occupations.get_fermi_levels() # These values should be identic equal(ef1, ef2, 1e-9) equal(efsplit1, efsplit2, 1e-9) equal(ef3.mean(), ef1, 1e-9) equal(ef3.mean(), ef2, 1e-9) equal(ef3.mean(), ef4.mean(), 1e-9) equal(ef3[0] - ef3[1], ef4[0] - ef4[1], 1e-9) equal(efsplit1, ef4[0] - ef4[1], 1e-9) gpaw-0.11.0.13004/gpaw/test/gllbatomic.py0000664000175000017500000000301512553643471020060 0ustar jensjjensj00000000000000from __future__ import print_function from ase import * from gpaw.atom.all_electron import AllElectron from gpaw.test import equal data = [] def out(a,b,c,d,e,f): data.append( (a,b,c,d,e,f) ) ETotal = {'Be': -14.572+0.012, 'Ne': -128.548 -0.029, 'Mg': -199.612 - 0.005 } EX = {'Be': -2.666 - 0.010, 'Ne': -12.107 -0.122, 'Mg': -15.992 -0.092 } EHOMO = {'Be': -0.309 + 0.008, 'Ne': -0.851 + 0.098, 'Mg': -0.253 + 0.006} eignum = {'Be': 0, 'Ne':3, 'Mg':0 } for xcname in ['GLLB','GLLBSC']: atoms = ['Be','Ne','Mg'] for atom in atoms: # Test AllElectron GLLB GLLB = AllElectron(atom, xcname = xcname, scalarrel = False, gpernode = 600) GLLB.run() out("Total energy", xcname+"1D", atom, ETotal[atom] , GLLB.ETotal,"Ha") out("Exchange energy", xcname+"1D", atom, EX[atom], GLLB.Exc,"Ha") out("HOMO Eigenvalue", xcname+"1D", atom, EHOMO[atom], GLLB.e_j[-1],"Ha") if xcname == 'GLLB': equal(GLLB.ETotal, ETotal[atom], tolerance=1e-2) equal(GLLB.Exc, EX[atom], tolerance=1e-2) equal(GLLB.e_j[-1], EHOMO[atom], tolerance=1e-2) print(" Quanity Method Symbol Ref[1] GPAW Unit ") for a,b,c,d,e,f in data: print("%20s %10s %10s %10.3f %10.3f %5s" % (a,b,c,d,e,f)) print("""References: [1] Self-consistent approximation to the Kohn-Sham exchange potential Gritsenko, Oleg; Leeuwen, Robert van; Lenthe, Erik van; Baerends, Evert Jan Phys. Rev. A Vol. 51 p. 1944""") gpaw-0.11.0.13004/gpaw/test/al_chain.py0000664000175000017500000000070312553643471017502 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW from gpaw.mpi import size d = 4.0 / 2**0.5 ndomains = size // 8 + 1 calc = GPAW(h=d / 16, kpts=(17, 1, 1), parallel={'domain': ndomains, 'band': 1}) chain = Atoms('Al', cell=(d, 5, 5), pbc=True, calculator=calc) e = chain.get_potential_energy() assert abs(e - -1.81816) < 0.00005 assert calc.wfs.kd.comm.size * ndomains == size calc.write('al_chain', 'all') gpaw-0.11.0.13004/gpaw/test/ed_shapes.py0000664000175000017500000000652212553643471017704 0ustar jensjjensj00000000000000from ase import Atoms from gpaw.fdtd.poisson_fdtd import QSFDTD from gpaw.fdtd.polarizable_material import PermittivityPlus, PolarizableMaterial, \ PolarizableSphere, PolarizableBox, \ PolarizableEllipsoid, PolarizableRod, \ PolarizableTetrahedron from gpaw.mpi import world from gpaw.tddft import photoabsorption_spectrum, units from gpaw.test import equal import numpy as np # Whole simulation cell (Angstroms) cell = [40, 40, 20]; # Classical subsystem classical_material = PolarizableMaterial() classical_material.add_component(PolarizableSphere(permittivity = PermittivityPlus(data = [[1.20, 0.20, 25.0]]), center = [10, 10, 10], radius = 4.5)) classical_material.add_component(PolarizableBox(permittivity = PermittivityPlus(data = [[1.40, 0.20, 25.0]]), corner1 = [18.1, 5.1, 5.1], corner2 = [22.9, 14.9, 14.9])) classical_material.add_component(PolarizableEllipsoid(permittivity = PermittivityPlus(data = [[1.60, 0.20, 25.0]]), center = [30.0, 10.0, 10.0], radii = [ 3.9, 5.9, 4.9])) classical_material.add_component(PolarizableRod(permittivity = PermittivityPlus(data = [[1.80, 0.20, 25.0]]), corners = [[10.0, 21.5, 10.0], [10.0, 33.5, 10.0]], round_corners = True, radius = 3.9)) classical_material.add_component(PolarizableRod(permittivity = PermittivityPlus(data = [[1.00, 0.20, 25.0]]), corners = [[20.0, 21.5, 10.0], [25.0, 33.5, 10.0]], round_corners = False, radius = 2.9)) classical_material.add_component(PolarizableTetrahedron(permittivity = PermittivityPlus(data = [[0.80, 0.20, 25.0]]), corners = [[24.1, 16.1, 5.1], [30.1, 36.1, 6.1], [36.4, 27.6, 7.1], [30.0, 25.0, 14.9]])) # Wrap calculators qsfdtd = QSFDTD(classical_material = classical_material, atoms = None, cells = (cell, 2.00), spacings = [1.60, 0.40], remove_moments = (1, 1)) # Run energy = qsfdtd.ground_state('gs.gpw', eigensolver = 'cg', nbands = -1) qsfdtd.time_propagation('gs.gpw', kick_strength=[0.000, 0.000, 0.001], time_step=10, iterations=5, dipole_moment_file='dmCl.dat') # Restart and run qsfdtd.write('td.gpw', mode='all') qsfdtd.time_propagation('td.gpw', kick_strength=None, time_step=10, iterations=5, dipole_moment_file='dmCl.dat') # Test ref_cl_dipole_moment = [-1.01218372e-04, -3.03603352e-05, 1.86063694e-01] tol = 0.0001 equal(qsfdtd.td_calc.hamiltonian.poisson.get_classical_dipole_moment(), ref_cl_dipole_moment, tol) gpaw-0.11.0.13004/gpaw/test/scfsic_n2.py0000664000175000017500000000121112553643471017610 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from ase import Atoms from gpaw import GPAW from gpaw.xc.sic import SIC from gpaw.test import equal a = 7.0 atom = Atoms('N', magmoms=[3], cell=(a, a, a)) molecule = Atoms('N2', positions=[(0, 0, 0), (0, 0, 1.14)], cell=(a, a, a)) atom.center() molecule.center() calc = GPAW(xc=SIC(), eigensolver='rmm-diis', h=0.17, txt='n2.sic.new3b.txt', setups='hgh') atom.set_calculator(calc) e1 = atom.get_potential_energy() molecule.set_calculator(calc) e2 = molecule.get_potential_energy() F_ac = molecule.get_forces() print(2 * e1 - e2) print(F_ac) gpaw-0.11.0.13004/gpaw/test/occupations.py0000664000175000017500000000154312553643471020276 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from ase.units import Hartree from gpaw.occupations import FermiDirac, MethfesselPaxton class KPoint: eps_n = np.empty(1) f_n = np.empty(1) weight = 0.2 s = 0 k = KPoint() def f(occ, x): k.eps_n[0] = x n, dnde, x, S = occ.distribution(k, 0.0) return n, dnde, S def test(occ): print(occ) for e in [-0.3 / Hartree, 0, 0.1 / Hartree, 1.2 / Hartree]: n0, d0, S0 = f(occ, e) x = 0.000001 np, dp, Sp = f(occ, e + x) nm, dm, Sm = f(occ, e - x) d = -(np - nm) / (2 * x) dS = Sp - Sm dn = np - nm print(d - d0, dS - e * dn) assert abs(d - d0) < 3e-5 assert abs(dS - e * dn) < 1e-13 for w in [0.1, 0.5]: test(FermiDirac(w)) for n in range(4): test(MethfesselPaxton(w, n)) gpaw-0.11.0.13004/gpaw/test/ralda_C6_He.py0000664000175000017500000000120412553643471017770 0ustar jensjjensj00000000000000from ase import * from ase.structure import molecule from gpaw import * from gpaw.mpi import serial_comm from gpaw.test import equal from gpaw.xc.fxc_correlation_energy import FXCCorrelation ecut = 50 He = Atoms('He') He.center(vacuum=1.0) calc = GPAW(mode='pw', dtype=complex, xc='PBE', communicator=serial_comm) He.set_calculator(calc) He.get_potential_energy() calc.diagonalize_full_hamiltonian() ralda = FXCCorrelation(calc, xc='rALDA') C6_ralda, C6_0 = ralda.get_C6_coefficient(ecut=ecut, direction=2) equal(C6_0, 1.772, 0.01) equal(C6_ralda, 1.609, 0.01) gpaw-0.11.0.13004/gpaw/test/ofdft_pbc.py0000664000175000017500000000144012553643472017672 0ustar jensjjensj00000000000000from ase.lattice import bulk from gpaw import GPAW from gpaw.mixer import Mixer from gpaw.test import equal from gpaw.test import gen from gpaw.eigensolvers import CG symbol = 'C' result = -224.200276535 electrons = 48 xcname = 'LDA_K_TF+LDA_X' g = gen(symbol, xcname=xcname, scalarrel=False, orbital_free=True) h = 0.14 a = 2.8 atoms = bulk(symbol, 'diamond', a=a, cubic=True) # Generate diamond mixer = Mixer(0.1, 5) calc = GPAW(h=h, xc=xcname, maxiter=120, eigensolver = 'cg', mixer=mixer) atoms.set_calculator(calc) e = atoms.get_potential_energy() n = calc.get_all_electron_density() dv = atoms.get_volume() / calc.get_number_of_grid_points().prod() I = n.sum() * dv / 2**3 equal(I, electrons, 1.0e-6) equal(result, e, 1.0e-3) gpaw-0.11.0.13004/gpaw/test/dipole.py0000664000175000017500000000571512553643471017230 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from ase.structure import molecule from ase.units import Hartree from gpaw import GPAW from gpaw.dipole_correction import DipoleCorrection from gpaw.poisson import PoissonSolver from gpaw.mpi import rank from gpaw.utilities import h2gpts """ Test the dipole correction code by comparing this system: H z1 O z2 H (where z1 and z2 denote points where the potential is probed) Expected potential: ----- / / ---- to this system: H H z1 O z2 O H H Expected potential: ------- / \ / \ ----- ------ The height of the two potentials are tested to be the same. Enable if-statement in the bottom for nice plots """ system1 = molecule('H2O') system1.set_pbc((True, True, False)) system1.cell = 4.0 * np.array([[1.0, -1.5, 0.0], [1.0, 1.0, 0.0], [0., 0., 1.]]) system1.center(vacuum=10.0, axis=2) system2 = system1.copy() system2.positions *= [1.0, 1.0, -1.0] system2 += system1 system2.center(vacuum=6.0, axis=2) convergence = dict(density=1e-5) calc1 = GPAW(mode='lcao', convergence=convergence, gpts=h2gpts(0.25, system1.cell, idiv=8), poissonsolver=DipoleCorrection(PoissonSolver(relax='GS', eps=1e-11), 2)) system1.set_calculator(calc1) system1.get_potential_energy() v1 = calc1.get_effective_potential(pad=False) calc2 = GPAW(mode='lcao', convergence=convergence, gpts=h2gpts(0.25, system2.cell, idiv=8), poissonsolver=PoissonSolver(relax='GS', eps=1e-11)) system2.set_calculator(calc2) system2.get_potential_energy() v2 = calc2.get_effective_potential(pad=False) def get_avg(v): nx, ny, nz = v.shape vyz = v.sum(axis=0) / nx vz = vyz.sum(axis=0) / ny return vz, vyz if rank == 0: vz1, vyz1 = get_avg(v1) vz2, vyz2 = get_avg(v2) # Compare values that are not right at the end of the array # (at the end of the array things can "oscillate" a bit) dvz1 = vz1[-5] - vz1[4] dvz2 = vz2[4] - vz2[len(vz2) // 2] print(dvz1, dvz2) err1 = abs(dvz1 - dvz2) correction = calc1.hamiltonian.poisson.corrector.correction correction_err = abs(2.0 * correction * Hartree + dvz1) print('correction error %s' % correction_err) assert correction_err < 3e-5 # Comparison to what the values were when this test was last modified: ref_value = 2.07342988218 err2 = abs(dvz1 - ref_value) if 0: import pylab as pl pl.imshow(vyz1) pl.figure() pl.imshow(vyz2) pl.figure() pl.plot(vz1) pl.plot(vz2) pl.show() print('Ref value of previous calculation', ref_value) print('Value in this calculation', dvz1) # fine grid needed to achieve convergence! print('Error', err1, err2) assert err1 < 5e-3, err1 assert err2 < 2e-4, err2 gpaw-0.11.0.13004/gpaw/test/second_derivative.py0000664000175000017500000000235512553643472021447 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from gpaw.lfc import LocalizedFunctionsCollection as LFC from gpaw.grid_descriptor import GridDescriptor from gpaw.spline import Spline gd = GridDescriptor([20, 16, 16], [(4, 2, 0), (0, 4, 0), (0, 0, 4)]) spos_ac = np.array([[0.252, 0.15, 0.35], [0.503, 0.5, 0.5]]) s = Spline(l=0, rmax=2.0, f_g=np.array([1, 0.9, 0.1, 0.0])) spline_aj = [[s], [s]] c = LFC(gd, spline_aj) c.set_positions(spos_ac) c_ai = c.dict(zero=True) if 1 in c_ai: c_ai[1][0] = 2.0 psi = gd.zeros() c.add(psi, c_ai) d_avv = dict([(a, np.zeros((3, 3))) for a in c.my_atom_indices]) c.second_derivative(psi, d_avv) if 0 in d_avv: print(d_avv[0]) eps = 0.000001 d_aiv = c.dict(derivative=True) pos_av = np.dot(spos_ac, gd.cell_cv) for v in range(3): pos_av[0, v] += eps c.set_positions(np.dot(pos_av, gd.icell_cv.T)) c.derivative(psi, d_aiv) if 0 in d_aiv: d0_v = d_aiv[0][0].copy() pos_av[0, v] -= 2 * eps c.set_positions(np.dot(pos_av, gd.icell_cv.T)) c.derivative(psi, d_aiv) if 0 in d_aiv: d0_v -= d_aiv[0][0] d0_v /= -2 * eps print(d0_v) d_avv[0][v] -= d0_v pos_av[0, v] += eps if 0 in d_avv: assert np.abs(d_avv[0]).max() < 1e-10 gpaw-0.11.0.13004/gpaw/test/wannierk.py0000664000175000017500000000341712553643471017567 0ustar jensjjensj00000000000000'Test ase.dft.wannier module with k-points.' from __future__ import print_function from ase.lattice import bulk from ase.dft.wannier import Wannier from gpaw import GPAW from gpaw.mpi import world, serial_comm si = bulk('Si', 'diamond', a=5.43) k = 4 if 1: si.calc = GPAW(kpts=(k, k, k), txt='Si-ibz.txt') e1 = si.get_potential_energy() si.calc.write('Si-ibz', mode='all') si.calc.set(symmetry={'point_group': False, 'time_reversal': False}, txt='Si-bz.txt') e2 = si.get_potential_energy() si.calc.write('Si-bz', mode='all') print((e1, e2)) def wan(calc): centers = [([0.125, 0.125, 0.125], 0, 1.5), ([0.125, 0.625, 0.125], 0, 1.5), ([0.125, 0.125, 0.625], 0, 1.5), ([0.625, 0.125, 0.125], 0, 1.5)] w = Wannier(4, calc, nbands=4, verbose=1, initialwannier=centers) w.localize() x = w.get_functional_value() centers = (w.get_centers(1) * k) % 1 c = (centers - 0.125) * 2 print(w.get_radii()) # broken! XXX assert abs(c.round() - c).max() < 0.03 c = sorted(c.round().astype(int).tolist()) assert c == [[0, 0, 0], [0, 0, 1], [0, 1, 0], [1, 0, 0]] if 0: from ase.visualize import view from ase import Atoms watoms = calc.atoms + Atoms(symbols='X4', scaled_positions=centers, cell=calc.atoms.cell) view(watoms) return x calc1 = GPAW('Si-bz.gpw', txt=None, communicator=serial_comm) x1 = wan(calc1) calc2 = GPAW('Si-ibz.gpw', txt=None, communicator=serial_comm) calc2.wfs.ibz2bz(si) x2 = wan(calc2) if world.rank == 0: print((x1, x2)) assert abs(x1 - x2) < 0.001 assert abs(x1 - 9.71) < 0.01 world.barrier() gpaw-0.11.0.13004/gpaw/test/wannier_ethylene.py0000664000175000017500000000423412553643471021307 0ustar jensjjensj00000000000000from __future__ import print_function import os from ase import Atom, Atoms from gpaw import GPAW from gpaw.test import equal from gpaw.wannier import Wannier import numpy as np # GPAW wannier example for ethylene corresponding to the ASE Wannier # tutorial. a = 6.0 # Size of unit cell (Angstrom) ethylene = Atoms([Atom('H', (-1.235,-0.936 , 0 )), Atom('H', (-1.235, 0.936 , 0 )), Atom('C', (-0.660, 0.000 , 0 )), Atom('C', ( 0.660, 0.000 , 0 )), Atom('H', ( 1.235,-0.936 , 0 )), Atom('H', ( 1.235, 0.936 , 0 ))], cell=(a, a, a), pbc=True) ethylene.center() calc = GPAW(nbands=8, gpts=(32, 32, 32), convergence={'eigenstates': 3.3e-5}) ethylene.set_calculator(calc) e = ethylene.get_potential_energy() niter = calc.get_number_of_iterations() energy_tolerance = 0.0002 niter_tolerance = 0 equal(e, -33.3232491, energy_tolerance) def check(calc): wannier = Wannier(calc, nbands=6) wannier.localize() centers = wannier.get_centers() print(centers) expected = [[1.950, 2.376, 3.000], [1.950, 3.624, 3.000], [3.000, 3.000, 2.671], [3.000, 3.000, 3.329], [4.050, 2.376, 3.000], [4.050, 3.624, 3.000]] equal(13.7995, wannier.value, 0.016) for center in centers: i = 0 while np.sum((expected[i] - center)**2) > 0.01: i += 1 if i == len(expected): raise RuntimeError('Correct center not found') expected.pop(i) check(calc) calc.write('ethylene.gpw', 'all') check(GPAW('ethylene.gpw', txt=None)) try: from gpaw.io.etsf import ETSFWriter except ImportError: pass # Scientific.IO.NetCDF was not installed else: if calc.wfs.world.size == 1: ETSFWriter().write(calc) ## for i in range(6): ## wannier.write_cube(i, 'ethylene%s.cube' % i, real=True) ## from ASE.Visualization.PrimiPlotter import PrimiPlotter, X11Window ## ethylene.extend(wannier.get_centers_as_atoms()) ## plot = PrimiPlotter(ethylene) ## plot.set_output(X11Window()) ## plot.set_radii(.2) ## plot.set_rotation([15, 0, 0]) ## plot.plot() gpaw-0.11.0.13004/gpaw/test/gp2.py0000664000175000017500000000074712553643471016444 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from gpaw.grid_descriptor import GridDescriptor from gpaw.localized_functions import create_localized_functions from gpaw.spline import Spline s=Spline(0, 1.2, [1, 0.6, 0.1, 0.0]) a = 4.0 n = 24 gd = GridDescriptor((n, n, n), (a, a, a)) print(gd.get_boxes((0, 0, 0), 1.2, 0)) if 0: p = create_localized_functions([s], gd, (0.0, 0.0, 0.0), cut=True) a = np.zeros((n, n, n)) p.add(a, np.array([2.0])) print(a[1,0]) gpaw-0.11.0.13004/gpaw/test/poisson_extended.py0000664000175000017500000001112312553643471021314 0ustar jensjjensj00000000000000import numpy as np from gpaw.poisson import PoissonSolver from gpaw.poisson_extended import ExtendedPoissonSolver from gpaw.grid_descriptor import GridDescriptor from gpaw.test import equal # def equal(x, y, tol=0): # print '%.10e vs %.10e at %.10e' % (x, y, tol) # Model grid N_c = (16, 16, 3 * 16) cell_cv = (1, 1, 3) gd = GridDescriptor(N_c, cell_cv, False) # Construct model density coord_vg = gd.get_grid_point_coordinates() x_g = coord_vg[0, :] y_g = coord_vg[1, :] z_g = coord_vg[2, :] rho_g = gd.zeros() for z0 in [1, 2]: rho_g += 10 * (z_g - z0) * \ np.exp(-20 * np.sum((coord_vg.T - np.array([.5, .5, z0])).T**2, axis=0)) poissoneps = 1e-20 do_plot = False if do_plot: big_rho_g = gd.collect(rho_g) if gd.comm.rank == 0: import matplotlib.pyplot as plt fig, ax_ij = plt.subplots(3, 4, figsize=(20, 10)) ax_i = ax_ij.ravel() ploti = 0 Ng_c = gd.get_size_of_global_array() plt.sca(ax_i[ploti]) ploti += 1 plt.pcolormesh(big_rho_g[Ng_c[0] / 2]) plt.sca(ax_i[ploti]) ploti += 1 plt.plot(big_rho_g[Ng_c[0] / 2, Ng_c[1] / 2]) def plot_phi(phi_g): if do_plot: big_phi_g = gd.collect(phi_g) if gd.comm.rank == 0: global ploti plt.sca(ax_i[ploti]) ploti += 1 plt.pcolormesh(big_phi_g[Ng_c[0] / 2]) plt.sca(ax_i[ploti]) ploti += 1 plt.plot(big_phi_g[Ng_c[0] / 2, Ng_c[1] / 2]) plt.ylim(np.array([-1, 1]) * 0.15) def poisson_solve(gd, rho_g, poisson): phi_g = gd.zeros() npoisson = poisson.solve(phi_g, rho_g) return phi_g, npoisson def compare(phi1_g, phi2_g, val): big_phi1_g = gd.collect(phi1_g) big_phi2_g = gd.collect(phi2_g) if gd.comm.rank == 0: equal(np.max(np.absolute(big_phi1_g - big_phi2_g)), val, np.sqrt(poissoneps)) # Get reference from default poissonsolver poisson = PoissonSolver(eps=poissoneps) poisson.set_grid_descriptor(gd) poisson.initialize() phiref_g, npoisson = poisson_solve(gd, rho_g, poisson) # Test agreement with default poisson = ExtendedPoissonSolver(eps=poissoneps) poisson.set_grid_descriptor(gd) poisson.initialize() phi_g, npoisson = poisson_solve(gd, rho_g, poisson) plot_phi(phi_g) compare(phi_g, phiref_g, 0.0) # Test moment_corrections=int poisson = ExtendedPoissonSolver(eps=poissoneps, moment_corrections=4) poisson.set_grid_descriptor(gd) poisson.initialize() phi_g, npoisson = poisson_solve(gd, rho_g, poisson) plot_phi(phi_g) compare(phi_g, phiref_g, 4.1182101206e-02) # Test moment_corrections=list poisson = ExtendedPoissonSolver(eps=poissoneps, moment_corrections=[{'moms': range(4), 'center': [.5, .5, 1]}, {'moms': range(4), 'center': [.5, .5, 2]}]) poisson.set_grid_descriptor(gd) poisson.initialize() phi_g, npoisson = poisson_solve(gd, rho_g, poisson) plot_phi(phi_g) compare(phi_g, phiref_g, 2.7569628594e-02) # Test extendedgpts poisson = ExtendedPoissonSolver(eps=poissoneps, extended={'gpts': (24, 24, 3 * 24), 'useprev': False}) poisson.set_grid_descriptor(gd) poisson.initialize() phi_g, npoisson = poisson_solve(gd, rho_g, poisson) plot_phi(phi_g) compare(phi_g, phiref_g, 2.5351851105e-02) # Test extendedgpts + moment_corrections, extendedhistory=False poisson = ExtendedPoissonSolver(eps=poissoneps, extended={'gpts': (24, 24, 3 * 24), 'useprev': False}, moment_corrections=[{'moms': range(4), 'center': [.5, .5, 1]}, {'moms': range(4), 'center': [.5, .5, 2]}]) poisson.set_grid_descriptor(gd) poisson.initialize() phi_g, npoisson = poisson_solve(gd, rho_g, poisson) plot_phi(phi_g) phi2_g, npoisson2 = poisson_solve(gd, rho_g, poisson) equal(npoisson, npoisson2) compare(phi_g, phi2_g, 0.0) compare(phi_g, phiref_g, 2.75205170866e-02) # Test extendedgpts + moment_corrections, # extendedhistory=True poisson = ExtendedPoissonSolver(eps=poissoneps, extended={'gpts': (24, 24, 3 * 24), 'useprev': True}, moment_corrections=[{'moms': range(4), 'center': [.5, .5, 1]}, {'moms': range(4), 'center': [.5, .5, 2]}]) poisson.set_grid_descriptor(gd) poisson.initialize() phi_g, npoisson = poisson_solve(gd, rho_g, poisson) phi2_g, npoisson2 = poisson_solve(gd, rho_g, poisson) # The second run should use the old value -> niter=1 equal(npoisson2, 1) # There is a slight difference in values # because one more iteration in phi2_g compare(phi_g, phi2_g, 0.0) if do_plot: if gd.comm.rank == 0: plt.show() gpaw-0.11.0.13004/gpaw/test/ut_tddft.py0000664000175000017500000002550712553643471017572 0ustar jensjjensj00000000000000from __future__ import print_function import os, sys, time import numpy as np try: # Matplotlib is not a dependency import matplotlib as mpl mpl.use('Agg') # force the antigrain backend except (ImportError, RuntimeError): mpl = None from ase import Atoms from ase.structure import molecule from ase.parallel import paropen from ase.units import Bohr, Hartree from ase.io import Trajectory from ase.calculators.singlepoint import SinglePointCalculator from ase.utils import devnull from gpaw import GPAW, debug from gpaw.mpi import world from gpaw.tddft import TDDFT from gpaw.tddft.units import attosec_to_autime # ------------------------------------------------------------------- from gpaw.test.ut_common import ase_svnversion, shapeopt, TestCase, \ TextTestRunner, CustomTextTestRunner, defaultTestLoader, \ initialTestLoader, create_random_atoms, create_parsize_maxbands # ------------------------------------------------------------------- class UTGroundStateSetup(TestCase): """ Setup a simple calculation starting from ground state.""" # Number of bands nbands = 1 # Spin-paired, single kpoint nspins = 1 nibzkpts = 1 # Mean spacing and number of grid points per axis (G x G x G) h = 0.25 / Bohr def setUp(self): for virtvar in []: assert getattr(self,virtvar) is not None, 'Virtual "%s"!' % virtvar parsize_domain, parsize_bands = create_parsize_maxbands(self.nbands, world.size) self.parallel = {'domain': parsize_domain, 'band': parsize_bands} self.atoms = molecule('Na2') self.atoms.center(vacuum=4.0) self.atoms.set_pbc(False) cell_c = np.sum(self.atoms.get_cell()**2, axis=1)**0.5 / Bohr ngpts = 16 * np.round(cell_c / (self.h * 16)) self.gsname = 'ut_tddft_gs' self.gscalc = GPAW(gpts=ngpts, nbands=self.nbands, basis='dzp', setups={'Na': '1'}, spinpol=(self.nspins==2), parallel=self.parallel, txt=self.gsname + '.txt') def tearDown(self): del self.atoms, self.gscalc # ================================= def verify_comm_sizes(self): if world.size == 1: return rem = world.size // (self.parallel['band'] * self.parallel['domain']) comm_sizes = (world.size, self.parallel['band'], self.parallel['domain'], rem) self._parinfo = '%d world, %d band, %d domain, %d kpt' % comm_sizes self.assertEqual(self.nbands % self.parallel['band'], 0) self.assertEqual((self.nspins * self.nibzkpts) % rem, 0) def verify_ground_state(self): #XXX DEBUG START if debug and os.path.isfile(self.gsname + '.gpw'): return #XXX DEBUG END self.atoms.set_calculator(self.gscalc) self.assertAlmostEqual(self.atoms.get_potential_energy(), -1.0621, 4) self.gscalc.write(self.gsname + '.gpw', mode='all') self.assertTrue(os.path.isfile(self.gsname + '.gpw')) # ------------------------------------------------------------------- class UTStaticPropagatorSetup(UTGroundStateSetup): __doc__ = UTGroundStateSetup.__doc__ + """ Propagate electrons with fixed nuclei and verify results.""" #TODO duration = 10.0 #24.0 timesteps = None propagator = None def setUp(self): UTGroundStateSetup.setUp(self) for virtvar in ['timesteps', 'propagator']: assert getattr(self,virtvar) is not None, 'Virtual "%s"!' % virtvar self.tdname = 'ut_tddft_td_' + self.propagator.lower() self.tdcalc = TDDFT(self.gsname + '.gpw', propagator=self.propagator, txt=self.tdname + '.txt') def tearDown(self): del self.tdcalc # ================================= def _test_timestepping(self, t): #XXX DEBUG START if debug and os.path.isfile('%s_%d.gpw' % (self.tdname, t)): return #XXX DEBUG END timestep = self.timesteps[t] self.assertAlmostEqual(self.duration % timestep, 0.0, 12) niter = int(self.duration / timestep) ndiv = 1 #XXX traj = Trajectory('%s_%d.traj' % (self.tdname, t), 'w', self.tdcalc.get_atoms()) t0 = time.time() f = paropen('%s_%d.log' % (self.tdname, t), 'w') print('propagator: %s, duration: %6.1f as, timestep: %5.2f as, ' \ 'niter: %d' % (self.propagator, self.duration, timestep, niter), file=f) for i in range(1, niter+1): # XXX bare bones propagation without all the nonsense self.tdcalc.propagator.propagate(self.tdcalc.time, timestep * attosec_to_autime) self.tdcalc.time += timestep * attosec_to_autime self.tdcalc.niter += 1 if i % ndiv == 0: rate = 60 * ndiv / (time.time()-t0) ekin = self.tdcalc.atoms.get_kinetic_energy() epot = self.tdcalc.get_td_energy() * Hartree F_av = np.zeros((len(self.tdcalc.atoms), 3)) print('i=%06d, time=%6.1f as, rate=%6.2f min^-1, ' \ 'ekin=%13.9f eV, epot=%13.9f eV, etot=%13.9f eV' \ % (i, timestep * i, rate, ekin, epot, ekin + epot), file=f) t0 = time.time() # Hack to prevent calls to GPAW::get_potential_energy when saving spa = self.tdcalc.get_atoms() spc = SinglePointCalculator(epot, F_av, None, None, spa) spa.set_calculator(spc) traj.write(spa) f.close() traj.close() self.tdcalc.write('%s_%d.gpw' % (self.tdname, t), mode='all') # Save density and wavefunctions to binary gd, finegd = self.tdcalc.wfs.gd, self.tdcalc.density.finegd if world.rank == 0: big_nt_g = finegd.collect(self.tdcalc.density.nt_g) np.save('%s_%d_nt.npy' % (self.tdname, t), big_nt_g) del big_nt_g big_psit_nG = gd.collect(self.tdcalc.wfs.kpt_u[0].psit_nG) np.save('%s_%d_psit.npy' % (self.tdname, t), big_psit_nG) del big_psit_nG else: finegd.collect(self.tdcalc.density.nt_g) gd.collect(self.tdcalc.wfs.kpt_u[0].psit_nG) world.barrier() def test_timestepping_ref(self): # Reference values for density and wavefunctions (assumed stationary) nt0_g = self.tdcalc.density.nt_g phases_n = self.tdcalc.wfs.kpt_u[0].eps_n * self.duration * attosec_to_autime psit0_nG = np.exp(-1j * phases_n) * self.tdcalc.wfs.kpt_u[0].psit_nG f = paropen('%s_ref.log' % self.tdname, 'w') niters = np.round(self.duration / self.timesteps).astype(int) print('propagator: %s, duration: %6.1f as, niters: %s, ' \ % (self.propagator, self.duration, niters.tolist()), file=f) for t,timestep in enumerate(self.timesteps): self.assertTrue(os.path.isfile('%s_%d.gpw' % (self.tdname, t))) # Load density and wavefunctions from binary gd, finegd = self.tdcalc.wfs.gd, self.tdcalc.density.finegd nt_g, psit_nG = finegd.empty(), gd.empty(self.nbands, dtype=complex) if world.rank == 0: big_nt_g = np.load('%s_%d_nt.npy' % (self.tdname, t)) finegd.distribute(big_nt_g, nt_g) del big_nt_g big_psit_nG = np.load('%s_%d_psit.npy' % (self.tdname, t)) gd.distribute(big_psit_nG, psit_nG) del big_psit_nG else: finegd.distribute(None, nt_g) gd.distribute(None, psit_nG) # Check loaded density and wavefunctions against reference values dnt = finegd.comm.max(np.abs(nt_g - nt0_g).max()) dpsit = gd.comm.max(np.abs(psit_nG - psit0_nG).max()) print('t=%d, timestep: %5.2f as, dnt: %16.13f, ' \ 'dpsit: %16.13f' % (t, timestep, dnt, dpsit), file=f) snt, spsit = {'SITE': (5,4)}.get(self.propagator, (7,5)) #self.assertAlmostEqual(dnt, 0, snt, 't=%d, timestep: ' \ # '%5.2f as, dnt: %g, digits: %d' % (t, timestep, dnt, snt)) #self.assertAlmostEqual(dpsit, 0, spsit, 't=%d, timestep: ' \ # '%5.2f as, dpsit=%g, digits: %d' % (t, timestep, dpsit, spsit)) f.close() def UTStaticPropagatorFactory(timesteps, propagator): sep = '_' classname = 'UTStaticPropagatorSetup' \ + sep + propagator class MetaPrototype(UTStaticPropagatorSetup, object): __doc__ = UTStaticPropagatorSetup.__doc__ timesteps = timesteps propagator = propagator for t,timestep in enumerate(timesteps): func = lambda _self, _t=t: _self._test_timestepping(_t) method = func#new.instancemethod(func, None, MetaPrototype) method_name = 'test_timestepping_%02.0fas' % timestep setattr(MetaPrototype, method_name, method) MetaPrototype.__name__ = classname return MetaPrototype # ------------------------------------------------------------------- if __name__ in ['__main__', '__builtin__']: # We may have been imported by test.py, if so we should redirect to logfile if __name__ == '__builtin__': testrunner = CustomTextTestRunner('ut_tddft.log', verbosity=2) else: stream = (world.rank == 0) and sys.stdout or devnull testrunner = TextTestRunner(stream=stream, verbosity=2) parinfo = [] for test in [UTGroundStateSetup]: info = ['', test.__name__, test.__doc__.strip('\n'), ''] testsuite = initialTestLoader.loadTestsFromTestCase(test) list(map(testrunner.stream.writeln, info)) testresult = testrunner.run(testsuite) assert testresult.wasSuccessful(), 'Initial verification failed!' parinfo.extend([' Parallelization options: %s' % tci._parinfo for \ tci in testsuite._tests if hasattr(tci, '_parinfo')]) parinfo = np.unique(np.sort(parinfo)).tolist() # Try all timesteps between 1 and 10 that factor the duration nicely timesteps = np.arange(1, min(10, UTStaticPropagatorSetup.duration) + 1) timesteps = timesteps[UTStaticPropagatorSetup.duration % timesteps == 0] testcases = [] for propagator in ['ECN', 'SICN', 'SITE', 'SIKE', 'ETRSCN']: testcases.append(UTStaticPropagatorFactory(timesteps, propagator)) for test in testcases: info = ['', test.__name__, test.__doc__.strip('\n')] + parinfo + [''] testsuite = defaultTestLoader.loadTestsFromTestCase(test) list(map(testrunner.stream.writeln, info)) testresult = testrunner.run(testsuite) # Provide feedback on failed tests if imported by test.py if __name__ == '__builtin__' and not testresult.wasSuccessful(): raise SystemExit('Test failed. Check ut_tddft.log for details.') gpaw-0.11.0.13004/gpaw/test/relax.py0000664000175000017500000000575412553643471017072 0ustar jensjjensj00000000000000from __future__ import print_function import os from ase import Atom, Atoms from ase.optimize import BFGS from ase.io import read from gpaw import GPAW from gpaw.test import equal a = 4. # Size of unit cell (Angstrom) c = a / 2 d = 0.74 # Experimental bond length molecule = Atoms('H2', [(c - d / 2, c, c), (c + d / 2, c, c)], cell=(a, a, a), pbc=False) calc = GPAW(h=0.2, nbands=1, xc='PBE', txt=None) molecule.set_calculator(calc) e1 = molecule.get_potential_energy() niter1 = calc.get_number_of_iterations() calc.write('H2.gpw') calc.write('H2a.gpw', mode='all') molecule.get_forces() calc.write('H2f.gpw') calc.write('H2fa.gpw', mode='all') from time import time def timer(func, *args, **kwargs): t0 = time() ret = func(*args, **kwargs) return ret, time()-t0 molecule = GPAW('H2.gpw', txt=None).get_atoms() f1, t1 = timer(molecule.get_forces) molecule = GPAW('H2a.gpw', txt=None).get_atoms() f2, t2 = timer(molecule.get_forces) molecule = GPAW('H2f.gpw', txt=None).get_atoms() f3, t3 = timer(molecule.get_forces) molecule = GPAW('H2fa.gpw', txt=None).get_atoms() f4, t4 = timer(molecule.get_forces) print('timing:', t1, t2, t3, t4) assert t2 < 0.6 * t1 assert t3 < 0.5 assert t4 < 0.5 print(f1) print(f2) print(f3) print(f4) assert sum((f1 - f4).ravel()**2) < 1e-6 assert sum((f2 - f4).ravel()**2) < 1e-6 assert sum((f3 - f4).ravel()**2) < 1e-6 positions = molecule.get_positions() # x-coordinate x-coordinate # v v d0 = positions[1, 0] - positions[0, 0] # ^ ^ # second atom first atom print('experimental bond length:') print('hydrogen molecule energy: %7.3f eV' % e1) print('bondlength : %7.3f Ang' % d0) # Find the theoretical bond length: relax = BFGS(molecule) relax.run(fmax=0.05) e2 = molecule.get_potential_energy() niter2 = calc.get_number_of_iterations() positions = molecule.get_positions() # x-coordinate x-coordinate # v v d0 = positions[1, 0] - positions[0, 0] # ^ ^ # second atom first atom print('PBE energy minimum:') print('hydrogen molecule energy: %7.3f eV' % e2) print('bondlength : %7.3f Ang' % d0) molecule = GPAW('H2fa.gpw', txt='H2.txt').get_atoms() relax = BFGS(molecule) relax.run(fmax=0.05) e2q = molecule.get_potential_energy() niter2q = calc.get_number_of_iterations() positions = molecule.get_positions() d0q = positions[1, 0] - positions[0, 0] assert abs(e2 - e2q) < 2e-6 assert abs(d0q - d0) < 4e-4 f0 = molecule.get_forces() del relax, molecule from gpaw.mpi import world world.barrier() # syncronize before reading text output file f = read('H2.txt').get_forces() assert abs(f - f0).max() < 5e-6 # 5 digits in txt file energy_tolerance = 0.00005 niter_tolerance = 0 equal(e1, -6.287873, energy_tolerance) equal(e2, -6.290744, energy_tolerance) equal(e2q, -6.290744, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/eigh_perf.py0000664000175000017500000000173012553643472017676 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from time import time from gpaw.utilities.lapack import diagonalize, diagonalize_mr3 seed = 43 gen = np.random.RandomState(seed) def main(i,seed=42,dtype=float): if (dtype==complex): epsilon = 0.1j else: epsilon = 0.1 x = i + 1 N = x*100 print("N =",N) H0 = np.zeros((N,N),dtype=dtype) + gen.rand(*(N,N)) H1 = H0 + epsilon*np.tri(N,N, k=-1) W0 = np.zeros((N)) Z0 = np.zeros_like(H0) t0 = time() diagonalize(H1.copy(), W0) t1 = time() - t0 print(dtype) print("diagonalize", t1) t2 = time() diagonalize_mr3(H1.copy(), W0, Z0) t3 = time() - t2 print("diagonalize_mr3",t3) print("---------------") # diagonalize_mr3 must be faster than diagonalize assert(t3 < t1) if __name__ in ['__main__', '__builtin__']: for i in range(8): # Check matrix sizes only up to 800 main(i,dtype=float) main(i,dtype=complex) gpaw-0.11.0.13004/gpaw/test/LDA_unstable.py0000664000175000017500000000144412553643471020244 0ustar jensjjensj00000000000000# http://listserv.fysik.dtu.dk/pipermail/gpaw-developers/2014-February/004374.html from __future__ import print_function from ase import Atom, Atoms from gpaw import GPAW from gpaw.test import equal for i in range(40): a = 6. b = a / 2 mol = Atoms([Atom('O',(b, b, 0.1219 + b)), Atom('H',(b, 0.7633 + b, -0.4876 + b)), Atom('H',(b, -0.7633 + b, -0.4876 + b))], pbc=False, cell=[a, a, a]) calc = GPAW(gpts=(24, 24, 24), nbands=4, mode='lcao', txt=None, xc='LDA') def stop(): calc.scf.converged = True calc.attach(stop, 1) mol.set_calculator(calc) e = mol.get_potential_energy() if i == 0: eref = e if calc.wfs.world.rank == 0: print(repr(e)) equal(e - eref, 0, 1.e-12) gpaw-0.11.0.13004/gpaw/test/gwsi.py0000664000175000017500000000314012553643471016713 0ustar jensjjensj00000000000000"""Test band-gaps for Si.""" from ase.lattice import bulk import numpy as np from gpaw.test import equal from gpaw import GPAW, PW, FermiDirac from gpaw.response.g0w0 import G0W0 def run(atoms, symm, name): atoms.calc = GPAW(mode=PW(250), eigensolver='rmm-diis', occupations=FermiDirac(0.01), symmetry=symm, kpts={'size': (2, 2, 2), 'gamma': True}, txt=name + '.txt') e = atoms.get_potential_energy() scalapack = atoms.calc.wfs.bd.comm.size atoms.calc.diagonalize_full_hamiltonian(nbands=8, scalapack=scalapack) atoms.calc.write(name, mode='all') gw = G0W0(name, 'gw-' + name, nbands=8, kpts=[(0, 0, 0), (0.5, 0.5, 0)], # Gamma, X ecut=40, domega0=0.1, eta=0.2, bands=(3, 7), # homo, lumo, lumo+1, lumo+2 ) results = gw.calculate() return e, results a = 5.43 si1 = bulk('Si', 'diamond', a=a) si2 = si1.copy() si2.positions -= a / 8 i = 0 results = [] for si in [si1, si2]: for symm in [{}, 'off', {'time_reversal': False}, {'point_group': False}]: e, r = run(si, symm, str(i)) G, X = r['eps'][0] results.append([e, G[0], G[1] - G[0], X[1] - G[0], X[2] - X[1]]) G, X = r['qp'][0] results[-1].extend([G[0], G[1] - G[0], X[1] - G[0], X[2] - X[1]]) i += 1 equal(abs(np.array(results[0]) - [-9.25, 5.44, 2.39, 0.40, 0, 6.26, 3.57, 1.32, 0]).max(), 0, 0.01) equal(np.ptp(results, 0).max(), 0, 0.005) gpaw-0.11.0.13004/gpaw/test/screened_poisson.py0000664000175000017500000000344412553643471021313 0ustar jensjjensj00000000000000from __future__ import print_function from math import pi, sqrt import numpy as np from gpaw.utilities.tools import coordinates from gpaw.utilities.gauss import Gaussian from gpaw.grid_descriptor import GridDescriptor from gpaw.test import equal from gpaw.mpi import world from gpaw.helmholtz import HelmholtzSolver, ScreenedPoissonGaussian # Initialize classes a = 20 # Size of cell inv_width = 31 # inverse width of the gaussian N = 48 # Number of grid points coupling = -0.4 # dampening Nc = (N, N, N) # Number of grid points along each axis gd = GridDescriptor(Nc, (a,a,a), 0) # Grid-descriptor object solver = HelmholtzSolver(k2=coupling, nn=3) # Numerical poisson solver # solver = PoissonSolver(nn=3) # Numerical poisson solver # solver = HelmholtzSolver(0.16) # Numerical poisson solver solver.set_grid_descriptor(gd) solver.initialize() xyz, r2 = coordinates(gd) # Matrix with the square of the radial coordinate gauss = Gaussian(gd, a=inv_width) # An instance of Gaussian test_screened_poisson = ScreenedPoissonGaussian(gd, a=inv_width) # /-------------------------------------------------\ # | Check if Gaussian potentials are made correctly | # \-------------------------------------------------/ # Array for storing the potential pot = gd.zeros(dtype=float, global_array=False) solver.load_gauss() vg = test_screened_poisson.get_phi(-coupling) # esp. for dampening # Get analytic functions ng = gauss.get_gauss(0) # vg = solver.phi_gauss # Solve potential numerically niter = solver.solve(pot, ng, charge=None, zero_initial_phi=True) # Determine residual # residual = norm(pot - vg) residual = gd.integrate((pot - vg)**2)**0.5 # print result print('residual %s'%( residual)) assert residual < 0.003 # mpirun -np 2 python gauss_func.py --gpaw-parallel --gpaw-debug gpaw-0.11.0.13004/gpaw/test/bse_diamond.py0000664000175000017500000000400412553643471020206 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from ase import Atom, Atoms from ase.lattice import bulk from ase.units import Hartree, Bohr from gpaw import GPAW, FermiDirac from gpaw.eigensolvers.rmm_diis_old import RMM_DIIS from gpaw.mixer import Mixer from gpaw.response.bse import BSE GS = 1 bse = 1 df = 1 check_spectrum = 1 if GS: a = 6.75 * Bohr atoms = bulk('C', 'diamond', a=a) calc = GPAW(h=0.2, eigensolver=RMM_DIIS(), mixer=Mixer(0.1,3), kpts=(2,2,2), occupations=FermiDirac(0.001), nbands=8, convergence={'bands':'all'}) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('C_kpt8.gpw','all') if bse: bse = BSE('C_kpt8.gpw', w=np.linspace(0,20,201), mode='RPA', nc=[0,8], nv=[0,8], coupling=True, q=np.array([0.0001,0,0.]), optical_limit=True, ecut=50., nbands=8) bse.get_dielectric_function('C_bse.dat') if df: from gpaw.response.df0 import DF df = DF('C_kpt8.gpw', w=np.linspace(0,20,201), q=np.array([0.0001,0,0.]), optical_limit=True, ecut=50., hilbert_trans=False) df.get_absorption_spectrum(filename='C.dat') if check_spectrum: d = np.loadtxt('C_bse.dat')[:,2] Nw1 = 96 Nw2 = 109 if d[Nw1] > d[Nw1-1] and d[Nw1] > d[Nw1+1] and \ d[Nw2] > d[Nw2-1] and d[Nw2] > d[Nw2+1] : pass else: print(d[Nw1], d[Nw2]) raise ValueError('Absorption peak not correct ! ') if np.abs(d[Nw1] - 67.1975750304) > 1e-5 or \ np.abs(d[Nw2] - 90.9851151994) > 1e-5 : print(d[Nw1], d[Nw2]) raise ValueError('Please check spectrum strength ! ') d2 = np.loadtxt('C.dat.x') print(np.abs(d - d2[:200, 4]).sum()) if np.abs(d - d2[:200, 4]).sum() > 1e-3: raise ValueError('Please compare two spectrum') gpaw-0.11.0.13004/gpaw/test/neb.py0000664000175000017500000000177012553643472016516 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atom from ase.neb import SingleCalculatorNEB from ase.optimize import FIRE from gpaw import GPAW from gpaw.cluster import Cluster txt=None mol = Cluster([Atom('H'), Atom('H',[1,0,0]), Atom('H',[.5,.5,.5])], cell = [2,2,2], pbc=True) def set_calculators(all=False): c=GPAW(h=.3, convergence={'eigenstates':0.1, 'energy' : 0.1, 'density' : 0.01}, symmetry='off', txt=txt) # c = EMT() n = len(images) if not all: n -= 2 neb.set_calculators([c] * n) images = [mol] for i in range(4): images.append(images[0].copy()) images[-1].positions[2, 1] = 2 - images[0].positions[2, 1] neb = SingleCalculatorNEB(images) neb.interpolate() for image in images: print(image[2].position) set_calculators(True) dyn = FIRE(neb, trajectory='mep.traj') dyn.insert_observer(set_calculators) print(dyn.run(fmax=8.)) gpaw-0.11.0.13004/gpaw/test/ofdft_scale.py0000664000175000017500000000202412553643471020213 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW from gpaw.mixer import Mixer from gpaw.test import equal from gpaw.test import gen from gpaw.eigensolvers import CG h = 0.18 a = 10 c = a / 2 d = 1.8 elements = ['C'] results = [0.0168960169771] electrons = [6] lambda_coeff=2.0 for symbol in elements: xcname = '1.0_LDA_K_TF+1.0_LDA_X' g = gen(symbol, xcname=xcname, scalarrel=False, orbital_free=True, tw_coeff=lambda_coeff) for element, result, e in zip(elements, results, electrons): atom = Atoms(element, positions=[(c, c, c)], cell=(a, a, a)) mixer = Mixer(0.3, 5, 1) eigensolver = CG(tw_coeff=lambda_coeff) calc = GPAW(h=h, txt='-', xc=xcname, maxiter=240, mixer=mixer, eigensolver=eigensolver) atom.set_calculator(calc) E = atom.get_total_energy() n = calc.get_all_electron_density() dv = atom.get_volume() / calc.get_number_of_grid_points().prod() I = n.sum() * dv / 2**3 equal(I, e, 1.0e-6) equal(result, E, 1.0e-3) gpaw-0.11.0.13004/gpaw/test/timing.py0000664000175000017500000000113112553643472017230 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. from __future__ import print_function from gpaw.grid_descriptor import GridDescriptor from gpaw.transformers import Transformer import time n = 6 gda = GridDescriptor((n,n,n)) gdb = gda.refine() gdc = gdb.refine() a = gda.zeros() b = gdb.zeros() c = gdc.zeros() inter = Transformer(gdb, gdc, 2).apply restr = Transformer(gdb, gda, 2).apply t = time.clock() for i in range(8*300): inter(b, c) print(time.clock() - t) t = time.clock() for i in range(8*3000): restr(b, a) print(time.clock() - t) gpaw-0.11.0.13004/gpaw/test/yukawa_radial.py0000664000175000017500000001144612553643471020567 0ustar jensjjensj00000000000000"""Small test for local parts using yukawa potential""" from math import factorial as fac from numpy import exp, sqrt, pi, absolute from gpaw.atom.radialgd import AERadialGridDescriptor #Values from Rico, Lopez, Ramirez, Ema, Theor Chem Acc (2013) 132:1304 # Table 1 and 2. # # Normalized STO: N = n + L : lambda (gamma) = 0.34 # n n' L Zeta Zeta' I(n,n',L,Zeta,Zeta') # 8 6 4 8.4 3.5 0.793087136533672 # 2 1 5 8.4 3.5 0.271337849250231 # 3 4 6 8.4 3.5 0.170346973782779 # 3 2 8 8.4 3.5 0.141826311951003 # 2 1 10 8.4 3.5 9.005003835363871(-2) # # Zeta = lambda (gamma) # n = 3, L=5, n'=2, L'=5, zeta'=3.5 # 0.10 9.503545229396430(-6) # 0.25 5.869262722600324(-4) # 0.50 1.194846721531269(-2) # 0.75 5.829196062489732(-2) # 1.00 0.153003818405446 basic_sto_list = [ # See table 1 of Rico, Lopez, Ramirez, Ema, # Theor Chem Acc (2013) 132:1304 # { # 'n': [8, 6], # n, n' # 'Zeta': [8.4, 3.5], # Z, Z' # 'L': 4, # L # 'I': 0.793087136533672 # [X_LM^n|X_LM^n'] # }, # { # 'n': [2, 1], # 'Zeta': [8.4, 3.5], # 'L': 5, # 'I': 0.271337849250231 # }, # { # values are completely of # 'n': [3, 4], # 'Zeta': [8.4, 3.5], # 'L': 6, # 'I': 0.170346973782779 # }, # { # 'n': [3, 2], # n, n' # 'Zeta': [8.4, 3.5], # Z, Z' # 'L': 8, # L # 'I': 0.141826311951003 # [X_LM^n|X_LM^n'] # }, { 'n': [2, 1], 'Zeta': [8.4, 3.5], 'L': 10, 'I': 9.005003835363871e-2 } ] gamma_sto_list = [ # See table 2 of Rico, Lopez, Ramirez, Ema, # Theor Chem Acc (2013) 132:1304 # { # 'zeta': 0.10, # 'I': 9.503545229396430e-6 # }, # { # 'zeta': 0.25, # 'I': 5.869262722600324e-4 # }, # { # 'zeta': 0.50, # 'I': 1.194846721531269e-2 # }, # { # 'zeta': 0.75, # 'I': 5.829196062489732e-2 # }, { 'zeta': 1.00, 'I': 0.153003818405446 }, ] def radial_sto(n, zeta, l, r): """Build radial part of slater type orbital""" # Stolen from gpaw all_electron.py (intialize_wave_functions) # # STOs are defined as # # N Y_l^m r^{n-1} exp(-zeta * r) # # N = (2 zeta)^n sqrt(2 zeta / (2n)!) assert n > 0 radial = r**(n + l + 0.5) radial *= exp(-zeta * r) N = (2 * zeta)**(n + l) * sqrt(2 * zeta / fac(2 * (n + l))) radial *= N # perhaps also do Y_l^m normalization return radial def test_different_sto(rgd): """Check integration of two different STO.""" gamma = 0.34 for test_sto in basic_sto_list: wave_functions = [] l_sto = test_sto['L'] for n, zeta in zip(test_sto['n'], test_sto['Zeta']): radial = radial_sto(n, zeta, l_sto, rgd.r_g) norm = sqrt((2 * l_sto + 1) / (4 * pi)) # m = 0 radial *= norm wave_functions.append([radial]) I = rgd.integrate_yukawa(wave_functions[0], wave_functions[1], l_sto, gamma) scale = 16 * pi**2 / (2 * l_sto + 1) I *= scale # print(u"{:7.5e}||{:7.5e}||{:7.5e}".format(test_sto['I'], I, # absolute(I - test_sto['I']) * 100.0 / test_sto['I'])) assert (absolute(I - test_sto['I'])/test_sto['I'] < 0.001) def test_same_sto(rgd): """Check integration of nearly identical STO.""" n = 3 l_sto = 5 np = 2 zetap = 3.5 for test_sto in gamma_sto_list: zeta = test_sto['zeta'] radial = radial_sto(n, zeta, l_sto, rgd.r_g) norm = sqrt((2 * l_sto + 1) / (4 * pi)) # m = 0 radial *= norm radial2 = radial_sto(np, zetap, l_sto, rgd.r_g) radial2 *= norm I = rgd.integrate_yukawa(radial, radial2, l_sto, zeta) scale = 16 * pi**2 / (2 * l_sto + 1) I *= scale # print(u"{:7.5e}||{:7.5e}||{:7.5e}".format(test_sto['I'], I, # absolute(I - test_sto['I']) * 100.0 / test_sto['I'])) assert (absolute(I - test_sto['I'])/test_sto['I'] < 0.001) def main(): """Work on it.""" N = 1200 beta = 0.4 * 600 / N rgd = AERadialGridDescriptor(beta / N, 1.0 / N, N) test_same_sto(rgd) test_different_sto(rgd) if __name__ == '__main__': main() gpaw-0.11.0.13004/gpaw/test/lcao_restart.py0000664000175000017500000000157212553643471020433 0ustar jensjjensj00000000000000from __future__ import print_function # Test that LCAO wavefunctions are available and equal after restarts # in normal as well as 'all' mode import numpy as np from ase.structure import molecule from gpaw import GPAW # setting number of decimals globally makes numpy.test() tests # which use docstrings fail #np.set_printoptions(precision=3, suppress=1) system = molecule('H2') system.center(vacuum=2.5) calc = GPAW(mode='lcao', basis='sz(dzp)', h=0.3, nbands=1, txt=None) system.set_calculator(calc) system.get_potential_energy() wf = calc.get_pseudo_wave_function(0) for mode in ['normal', 'all']: fname = 'lcao-restart.%s.gpw' % mode calc.write(fname, mode=dict(normal='', all='all')[mode]) calc2 = GPAW(fname, txt=None) wf2 = calc2.get_pseudo_wave_function(0) err = np.abs(wf2 - wf).max() print('%s: err=%s' % (mode, repr(err))) assert err == 0.0 gpaw-0.11.0.13004/gpaw/test/laplace.py0000664000175000017500000000632712553643471017355 0ustar jensjjensj00000000000000from __future__ import print_function, division from math import sin, cos, pi import numpy as np from gpaw.fd_operators import GUCLaplace as Laplace from gpaw.fd_operators import Gradient from gpaw.grid_descriptor import GridDescriptor from gpaw.mpi import size cells = [ ('distorted hexagonal', 4, [(1, 0, 0), (1.02 * cos(pi / 3 - 0.02), 1.02 * sin(pi / 3 - 0.02), 0), (0, 0, 1.0)]), ('hexagonal', 4, [(1, 0, 0), (0.5, 3**0.5 / 2, 0), (0, 0, 1.1)]), ('fcc', 6, [(0, 1, 1), (1, 0, 1), (1, 1, 0)]), ('fcc-alternative', 6, [(1, 0, 0), (0.5, 3**0.5 / 2, 0), (0.5, 3**0.5 / 6, (2 / 3)**0.5)]), ('bcc', 4, [(-1, 1, 1), (1, -1, 1), (1, 1, -1)]), ('sc', 3, [1.1, 1.02, 1.03]), ('distorted sc', 6, [(1, 0, 0), (0.01, 1, 0), (0, 0.02, 1)]), ('rocksalt', 6, [(2 * np.sqrt(1 / 3), np.sqrt(1 / 8), -np.sqrt(1 / 24)), (2 * np.sqrt(1 / 3), -np.sqrt(1 / 8), -np.sqrt(1 / 24)), (2 * np.sqrt(1 / 3), 0, np.sqrt(1 / 6))]), ('nasty', 6, [(1, 0, 0), (0.0001, 1.03, 0), (0.0001, 0.0001, 1.0)]), ('Mike', 6, 5 * np.array([(5.565 / 28, 0, 0), (0.0001 / 28, 5.565 / 28, 0), (0.0001 / 24, 0.0001 / 24, 4.684 / 24)])), ('MnO', 6, [(1, 0.5, 0.5), (0.5, 1, 0.5), (0.5, 0.5, 1)]), ('Jelver', 6, [[6.658433626216136, 0.1711724130951983, -0.04300038284455887], [3.4774564712755938, 5.843379292501022, 0.01599293966594096], [-0.10777038306906983 * 0.43, 0.10850460815311265 * 0.43, 15.26098014321118 * 0.43]])] if size == 1: for name, D, cell in cells: if name == 'Jelver': # Strange one! continue print('------------------') print(name, D) print(cell[0]) print(cell[1]) print(cell[2]) for n in range(1, 6): N = 2 * n + 2 gd = GridDescriptor((N, N, N), cell) b_g = gd.zeros() r_gv = gd.get_grid_point_coordinates().transpose((1, 2, 3, 0)) c_v = gd.cell_cv.sum(0) / 2 r_gv -= c_v lap = Laplace(gd, n=n) grad_v = [Gradient(gd, v, n=n) for v in range(3)] assert lap.npoints == D * 2 * n + 1 for m in range(0, 2 * n + 1): for ix in range(m + 1): for iy in range(m - ix + 1): iz = m - ix - iy a_g = (r_gv**(ix, iy, iz)).prod(3) if ix + iy + iz == 2 and max(ix, iy, iz) == 2: r = 2.0 else: r = 0.0 lap.apply(a_g, b_g) e = b_g[n + 1, n + 1, n + 1] - r assert abs(e) < 2e-12, e for v in range(3): grad_v[v].apply(a_g, b_g) if m == 1 and [ix, iy, iz][v] == 1: r = 1 else: r = 0 e = b_g[n + 1, n + 1, n + 1] - r assert abs(e) < 4e-12, (n, ix, iy, iz, r, v, e) gpaw-0.11.0.13004/gpaw/test/lcao_h2o.py0000664000175000017500000000126312553643471017434 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW from gpaw.test import equal a = 6.0 b = a / 2 mol = Atoms('OHH', [(b, b, 0.1219 + b), (b, 0.7633 + b, -0.4876 + b), (b, -0.7633 + b, -0.4876 + b)], pbc=False, cell=[a, a, a]) calc = GPAW(gpts=(32, 32, 32), nbands=4, mode='lcao') mol.set_calculator(calc) e = mol.get_potential_energy() niter = calc.get_number_of_iterations() equal(e, -10.266984, 1e-4) equal(niter, 8, 1) # Check that complex wave functions are allowed with gamma point calculations calc = GPAW(gpts=(32, 32, 32), nbands=4, mode='lcao', dtype=complex) mol.set_calculator(calc) ec = mol.get_potential_energy() equal(e, ec, 1e-5) gpaw-0.11.0.13004/gpaw/test/tpss.py0000664000175000017500000000523112553643471016736 0ustar jensjjensj00000000000000from __future__ import print_function from ase.structure import molecule from ase.parallel import paropen from gpaw import GPAW from gpaw.utilities.tools import split_formula from gpaw.test import equal cell = [10.,10.,10.] data = paropen('data.txt', 'w') ##Reference from J. Chem. Phys. Vol 120 No. 15, 15 April 2004, page 6898 tpss_de = { 'Li2': 22.5, } tpss_old = { 'Li2': 22.7, } exp_bonds_dE = { 'Li2': (2.673,24.4), } niters_ref = {'Li2': 21, 'Li': 14} niter_tolerance = 0 systems = ['Li2'] # Add atoms for formula in systems: temp = split_formula(formula) for atom in temp: if atom not in systems: systems.append(atom) energies = {} niters = {} # Calculate energies for formula in systems: loa = molecule(formula) loa.set_cell(cell) loa.center() calc = GPAW(h=0.3, nbands=-2, xc='PBE', #fixmom=True, txt=formula + '.txt') if len(loa) == 1: calc.set(hund=True) else: pos = loa.get_positions() pos[1,:] = pos[0,:] + [0.0, 0.0, exp_bonds_dE[formula][0]] loa.set_positions(pos) loa.center() loa.set_calculator(calc) try: energy = loa.get_potential_energy() niters[formula] = calc.get_number_of_iterations() diff = calc.get_xc_difference('TPSS') energies[formula] = (energy, energy + diff) except: raise#print >> data, formula, 'Error' else: print(formula, energy, energy + diff, file=data) data.flush() #calculate atomization energies file = paropen('tpss.txt', 'w') print('formula\tGPAW\tRef\tGPAW-Ref\tGPAW-exp', file=file) mae_ref, mae_exp, mae_pbe, count = 0.0, 0.0, 0.0, 0 for formula in tpss_de.keys(): try: atoms_formula = split_formula(formula) de_tpss = -1.0 * energies[formula][1] de_pbe = -1.0 * energies[formula][0] for atom_formula in atoms_formula: de_tpss += energies[atom_formula][1] de_pbe += energies[atom_formula][0] except: raise#print >>file, formula, 'Error' else: de_tpss *= 627.5/27.211 de_pbe *= 627.5/27.211 mae_ref += abs(de_tpss-tpss_de[formula]) mae_exp += abs(de_tpss-exp_bonds_dE[formula][1]) mae_pbe += abs(de_pbe-exp_bonds_dE[formula][1]) count += 1 out = "%s\t%.1f\t%.1f\t%.1f\t%.1f kcal/mol"%(formula,de_tpss,tpss_de[formula], de_tpss-tpss_de[formula],de_tpss-exp_bonds_dE[formula][1]) print(out, file=file) file.flush() #comparison to gpaw revision 5450 version value in kcal/mol (note the grid:0.3 Ang) equal(de_tpss, tpss_old[formula], 0.15) gpaw-0.11.0.13004/gpaw/test/gga_atom.py0000664000175000017500000000403212553643471017521 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np import numpy.random as ra from gpaw.test import equal from gpaw.setup import create_setup from gpaw.grid_descriptor import GridDescriptor from gpaw.localized_functions import create_localized_functions from gpaw.spline import Spline from gpaw.xc import XC from gpaw.utilities import pack from gpaw.mpi import serial_comm ra.seed(8) for name in ['LDA', 'PBE']: xc = XC(name) s = create_setup('N', xc) ni = s.ni nao = s.nao wt0_j = s.phit_j rcut = s.xc_correction.rgd.r_g[-1] wt_j = [] for wt0 in wt0_j: data = [wt0(r) for r in np.arange(121) * rcut / 100] data[-1] = 0.0 l = wt0.get_angular_momentum_number() wt_j.append(Spline(l, 1.2 * rcut, data)) a = rcut * 1.2 * 2 + 1.0 ## n = 120 n = 70 n = 90 gd = GridDescriptor((n, n, n), (a, a, a), comm=serial_comm) pr = create_localized_functions(wt_j, gd, (0.5, 0.5, 0.5)) coefs = np.identity(nao, float) psit_ig = np.zeros((nao, n, n, n)) pr.add(psit_ig, coefs) nii = ni * (ni + 1) // 2 D_p = np.zeros(nii) H_p = np.zeros(nii) e_g = np.zeros((n, n, n)) n_g = np.zeros((1, n, n, n)) v_g = np.zeros((1, n, n, n)) P_ni = 0.2 * ra.random((20, ni)) P_ni[:, nao:] = 0.0 D_ii = np.dot(np.transpose(P_ni), P_ni) D_p = pack(D_ii) p = 0 for i1 in range(nao): for i2 in range(i1, nao): n_g += D_p[p] * psit_ig[i1] * psit_ig[i2] p += 1 p += ni - nao p = create_localized_functions([s.nct], gd, (0.5, 0.5, 0.5)) p.add(n_g[0], np.ones(1)) e_g = gd.zeros() xc.calculate(gd, n_g, v_g, e_g) r2_g = np.sum((np.indices((n, n, n)) - n / 2)**2, axis=0) dv_g = gd.dv * np.less(r2_g, (rcut / a * n)**2) E2 = -np.dot(e_g.ravel(), dv_g.ravel()) s.xc_correction.n_qg[:] = 0.0 s.xc_correction.nc_g[:] = 0.0 E1 = (xc.calculate_paw_correction(s, D_p.reshape(1, -1)) + s.xc_correction.Exc0) print(name, E1, E2, E1 - E2) equal(E1, E2, 0.0013) gpaw-0.11.0.13004/gpaw/test/lcao_bulk.py0000664000175000017500000000212712553643471017701 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from ase import Atoms from gpaw import GPAW from gpaw.test import equal bulk = Atoms('Li', pbc=True) k = 4 g = 8 calc = GPAW(gpts=(g, g, g), kpts=(k, k, k), mode='lcao', basis='dzp') bulk.set_calculator(calc) e = [] niter = [] A = [2.6, 2.65, 2.7, 2.75, 2.8] for a in A: bulk.set_cell((a, a, a)) e.append(bulk.get_potential_energy()) niter.append(calc.get_number_of_iterations()) a = np.roots(np.polyder(np.polyfit(A, e, 2), 1))[0] print('a =', a) equal(a, 2.63781, 0.0001) e_ref = [-1.8677343236247692, -1.8690343169380492, -1.8654175796625045, -1.8566274574918875, -1.8432374955346396] niter_ref = [6, 6, 6, 6, 6] print(e) energy_tolerance = 0.00003 niter_tolerance = 0 for i in range(len(A)): equal(e[i], e_ref[i], energy_tolerance) equal(niter[i], niter_ref[i], niter_tolerance) wf1 = calc.get_pseudo_wave_function(kpt=3, band=0) calc.write('Li', mode='all') calc2 = GPAW('Li') calc2.initialize_positions() wf2 = calc2.get_pseudo_wave_function(kpt=3, band=0) equal(abs(wf1 - wf2).max(), 0, 1e-9) gpaw-0.11.0.13004/gpaw/test/lrtddft2.py0000664000175000017500000000261012553643472017471 0ustar jensjjensj00000000000000import os import numpy as np from ase import Atom, Atoms from gpaw import GPAW from gpaw.test import equal from gpaw.lrtddft import LrTDDFT txt = '-' txt = None load = True load = False xc = 'LDA' R = 0.7 # approx. experimental bond length a = 4.0 c = 5.0 H2 = Atoms([Atom('H', (a / 2, a / 2, (c - R) / 2)), Atom('H', (a / 2, a / 2, (c + R) / 2))], cell=(a, a, c)) calc = GPAW(xc=xc, nbands=2, spinpol=False, eigensolver='rmm-diis', txt=txt) H2.set_calculator(calc) H2.get_potential_energy() calc.write('H2saved_wfs.gpw', 'all') calc.write('H2saved.gpw') wfs_error = calc.wfs.eigensolver.error #print "-> starting directly after a gs calculation" lr = LrTDDFT(calc, txt='-') lr.diagonalize() #print "-> reading gs with wfs" gs = GPAW('H2saved_wfs.gpw', txt=txt) # check that the wfs error is read correctly, # but take rounding errors into account assert( abs(calc.wfs.eigensolver.error/gs.wfs.eigensolver.error - 1) < 1e-8) lr1 = LrTDDFT(gs, xc=xc, txt='-') lr1.diagonalize() # check the oscillator strrength assert (abs(lr1[0].get_oscillator_strength()[0] / lr[0].get_oscillator_strength()[0] -1) < 1e-10) #print "-> reading gs without wfs" gs = GPAW('H2saved.gpw', txt=None) lr2 = LrTDDFT(gs, txt='-') lr2.diagonalize() # check the oscillator strrength d = abs(lr2[0].get_oscillator_strength()[0] / lr[0].get_oscillator_strength()[0] - 1) assert (d < 2e-3), d gpaw-0.11.0.13004/gpaw/test/pygga.py0000664000175000017500000000207412553643472017057 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW import numpy as np # spin paired H2 d = 0.75 h2 = Atoms('H2', [[0, 0, 0], [0, 0, d]]) h2.center(vacuum=2.) e = np.array([]) f = np.array([]) for XC in ['pyPBE', 'pyRPBE']: e = np.array([]) f = np.array([]) for i in [2, 0]: xc = XC[i:] calc = GPAW(nbands=-1, xc=xc, txt=None) h2.set_calculator(calc) e = np.append(e, h2.get_potential_energy()) f = np.append(f, h2.get_forces()) del calc assert np.abs(e[0] - e[1]) < 1.e-4 assert np.sum(np.abs(f[0] - f[1])) < 1.e-10 # spin polarized O2 d = 1.2 o2 = Atoms('O2', [[0, 0, 0], [0, 0, d]], magmoms=[1., 1.]) o2.center(vacuum=2.) for XC in ['pyPBE', 'pyRPBE']: e = np.array([]) f = np.array([]) for i in [2, 0]: xc = XC[i:] calc = GPAW(nbands=-2, xc=xc, txt=None) o2.set_calculator(calc) e = np.append(e, o2.get_potential_energy()) f = np.append(f, o2.get_forces()) del calc assert np.abs(e[0] - e[1]) < 5.e-3 assert np.sum(np.abs(f[0] - f[1])) < 1.e-4 gpaw-0.11.0.13004/gpaw/test/gw_ppa.py0000664000175000017500000000267412553643472017233 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from time import time, ctime from datetime import timedelta from ase.lattice import bulk from ase.units import Hartree from gpaw import GPAW, FermiDirac from gpaw.response.gw import GW starttime = time() a = 3.567 atoms = bulk('C', 'diamond', a=a) kpts = (2,2,2) calc = GPAW( h=0.20, kpts=kpts, xc='LDA', txt='C_gs.txt', nbands=30, symmetry='off', convergence={'bands':25}, eigensolver='cg', occupations=FermiDirac(0.001) ) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('C_gs.gpw','all') file='C_gs.gpw' gw = GW( file=file, nbands=25, bands=np.array([3,4]), w=np.array([75., 100., 0.05]), ecut=25., eta=0.2, ppa=False, hilbert_trans=False, ) gw.get_exact_exchange() gw.get_QP_spectrum() QP_False = gw.QP_skn * Hartree gw = GW( file=file, nbands=25, bands=np.array([3,4]), w=np.array([75., 100., 0.05]), ecut=25., eta=0.2, ppa=True, hilbert_trans=False, ) gw.get_QP_spectrum() QP_True = gw.QP_skn * Hartree if not (np.abs(QP_False - QP_True) < 0.05).all(): raise AssertionError("dynamic GW not equal to PPA") totaltime = round(time() - starttime) print("GW test finished in %s " %(timedelta(seconds=totaltime))) gpaw-0.11.0.13004/gpaw/test/au02_absorption.py0000664000175000017500000000446012553643471020757 0ustar jensjjensj00000000000000import numpy as np from ase import Atoms from gpaw import GPAW, FermiDirac from gpaw.response.df import DielectricFunction from gpaw.test import equal, findpeak GS = 1 ABS = 1 if GS: cluster = Atoms('Au2', [(0, 0, 0), (0, 0, 2.564)]) cluster.set_cell((6, 6, 6), scale_atoms=False) cluster.center() calc = GPAW(mode='pw', dtype=complex, xc='RPBE', nbands=16, eigensolver='rmm-diis', occupations=FermiDirac(0.01)) cluster.set_calculator(calc) cluster.get_potential_energy() calc.diagonalize_full_hamiltonian(nbands=24, scalapack=True) calc.write('Au2.gpw', 'all') if ABS: df = DielectricFunction('Au2.gpw', frequencies=np.linspace(0, 14, 141), hilbert=not True, eta=0.1, ecut=10) b0, b = df.get_dielectric_function(filename=None, direction='z') a0, a = df.get_polarizability(filename=None, direction='z') df_ws = DielectricFunction('Au2.gpw', frequencies=np.linspace(0, 14, 141), hilbert=not True, eta=0.1, ecut=10, truncation='wigner-seitz') a0_ws, a_ws = df_ws.get_polarizability(filename=None, direction='z') w0_ = 5.60491055 I0_ = 244.693028 w_ = 5.696528390 I_ = 207.8 w, I = findpeak(np.linspace(0, 14., 141), b0.imag) equal(w, w0_, 0.05) equal(6**3 * I / (4 * np.pi), I0_, 0.5) w, I = findpeak(np.linspace(0, 14., 141), a0.imag) equal(w, w0_, 0.05) equal(I, I0_, 0.5) w, I = findpeak(np.linspace(0, 14., 141), a0_ws.imag) equal(w, w0_, 0.05) equal(I, I0_, 0.5) w, I = findpeak(np.linspace(0, 14., 141), b.imag) equal(w, w_, 0.05) equal(6**3 * I / (4 * np.pi), I_, 0.5) w, I = findpeak(np.linspace(0, 14., 141), a.imag) equal(w, w_, 0.05) equal(I, I_, 0.5) # The Wigner-Seitz truncation does not give exactly the same for small cell w, I = findpeak(np.linspace(0, 14., 141), a_ws.imag) equal(w, w_, 0.2) equal(I, I_, 8.0) gpaw-0.11.0.13004/gpaw/test/partitioning.py0000664000175000017500000000503112553643471020452 0ustar jensjjensj00000000000000from ase.structure import molecule from ase.parallel import parprint from gpaw import GPAW from gpaw.cluster import Cluster from gpaw.analyse.hirshfeld import HirshfeldDensity, HirshfeldPartitioning from gpaw.analyse.wignerseitz import WignerSeitz from gpaw.test import equal from gpaw.mpi import rank h = 0.4 gpwname = 'H2O' + str(h) + '.gpw' def run(lastres=[]): results = [] # Hirshfeld ---------------------------------------- if 1: hd = HirshfeldDensity(calc) # check for the number of electrons expected = [[None, 10], [[0, 1, 2], 10], [[1, 2], 2], [[0], 8], ] #expected = [[[0, 2], 9], ] #expected = [[None, 10], ] for gridrefinement in [1, 2, 4]: #Test for all gridrefinements for get_all_electron_density parprint('grid refinement', gridrefinement) for result in expected: indicees, result = result full, gd = hd.get_density(indicees, gridrefinement) parprint('indicees', indicees, end=': ') parprint('result, expected:', gd.integrate(full), result) if gridrefinement < 4: #The highest level of gridrefinement gets wrong electron numbers equal(gd.integrate(full), result, 1.e-8) else: equal(gd.integrate(full), result, 1.e-4) hp = HirshfeldPartitioning(calc) vr = hp.get_effective_volume_ratios() parprint('Hirshfeld:', vr) if len(lastres): equal(vr, lastres.pop(0), 1.e-10) results.append(vr) # Wigner-Seitz ---------------------------------------- if 1: ws = WignerSeitz(calc.density.finegd, mol, calc) vr = ws.get_effective_volume_ratios() parprint('Wigner-Seitz:', vr) if len(lastres): equal(vr, lastres.pop(0), 1.e-10) results.append(vr) return results mol = Cluster(molecule('H2O')) mol.minimal_box(2.5, h=h) # calculate if 1: parprint('### fresh:') calc = GPAW(nbands=6, h = h, txt=None) if 1: calc.calculate(mol) calc.write(gpwname) lastres = run() # load previous calculation if 1: parprint('### reloaded:') calc = GPAW(gpwname, txt=None) mol = calc.get_atoms() run(lastres) # periodic modulo test parprint('### periodic:') mol.set_pbc(True) mol.translate(-mol[0].position) mol.translate([-1.e-24, 0, 0]) calc.calculate(mol) run() gpaw-0.11.0.13004/gpaw/test/transformations.py0000664000175000017500000000233312553643471021176 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. import numpy as np from gpaw.grid_descriptor import GridDescriptor from gpaw.transformers import Transformer n = 20 gd = GridDescriptor((n,n,n)) np.random.seed(8) a = gd.empty() a[:] = np.random.random(a.shape) gd2 = gd.refine() b = gd2.zeros() for k in [2, 4, 6, 8]: inter = Transformer(gd, gd2, k // 2).apply inter(a, b) assert abs(gd.integrate(a) - gd2.integrate(b)) < 1e-14 gd2 = gd.coarsen() b = gd2.zeros() for k in [2, 4, 6, 8]: restr = Transformer(gd, gd2, k // 2).apply restr(a, b) assert abs(gd.integrate(a) - gd2.integrate(b)) < 1e-14 # complex versions a = gd.empty(dtype=complex) a.real = np.random.random(a.shape) a.imag = np.random.random(a.shape) phase = np.ones((3, 2), complex) gd2 = gd.refine() b = gd2.zeros(dtype=complex) for k in [2, 4, 6, 8]: inter = Transformer(gd, gd2, k // 2, complex).apply inter(a, b, phase) assert abs(gd.integrate(a) - gd2.integrate(b)) < 1e-14 gd2 = gd.coarsen() b = gd2.zeros(dtype=complex) for k in [2, 4, 6, 8]: restr = Transformer(gd, gd2, k // 2, complex).apply restr(a, b, phase) assert abs(gd.integrate(a) - gd2.integrate(b)) < 1e-14 gpaw-0.11.0.13004/gpaw/test/h2o_xas.py0000664000175000017500000000313512553643471017311 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from math import pi, cos, sin from ase import Atom, Atoms # from ase.parallel import rank, barrier from gpaw import GPAW, PoissonSolver from gpaw.xas import XAS from gpaw.test import equal, gen # Generate setup for oxygen with half a core-hole: gen('O', name='hch1s', corehole=(1, 0, 0.5)) a = 5.0 d = 0.9575 t = pi / 180 * 104.51 H2O = Atoms([Atom('O', (0, 0, 0)), Atom('H', (d, 0, 0)), Atom('H', (d * cos(t), d * sin(t), 0))], cell=(a, a, a), pbc=False) H2O.center() calc = GPAW(nbands=10, h=0.2, setups={'O': 'hch1s'}, poissonsolver=PoissonSolver(use_charge_center=True)) H2O.set_calculator(calc) e = H2O.get_potential_energy() niter = calc.get_number_of_iterations() import gpaw.mpi as mpi if mpi.size == 1: xas = XAS(calc) x, y = xas.get_spectra() e1_n = xas.eps_n de1 = e1_n[1] - e1_n[0] calc.write('h2o-xas.gpw') if mpi.size == 1: calc = GPAW('h2o-xas.gpw', txt=None, poissonsolver=PoissonSolver(use_charge_center=True)) calc.initialize() xas = XAS(calc) x, y = xas.get_spectra() e2_n = xas.eps_n w_n = np.sum(xas.sigma_cn.real**2, axis=0) de2 = e2_n[1] - e2_n[0] print(de2) print(de2 - 2.0705) assert abs(de2 - 2.0705) < 0.001 print(w_n[1] / w_n[0]) assert abs(w_n[1] / w_n[0] - 2.22) < 0.01 if mpi.size == 1: assert de1 == de2 if 0: import pylab as p p.plot(x, y[0]) p.plot(x, sum(y)) p.show() print(e, niter) energy_tolerance = 0.00009 niter_tolerance = 0 equal(e, -17.9772, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/exx_acdf.py0000664000175000017500000000166112553643471017531 0ustar jensjjensj00000000000000from __future__ import print_function from ase import * from ase.dft.kpoints import monkhorst_pack from ase.lattice import bulk from gpaw import * from gpaw.test import equal import numpy as np from gpaw.mpi import serial_comm, size, rank, world atoms = bulk('Al', 'fcc') kpts = monkhorst_pack((4,4,4)) kpts += np.array([1/8., 1/8., 1/8.]) calc = GPAW(h=0.18, kpts=kpts, occupations=FermiDirac(0.1)) atoms.set_calculator(calc) E = atoms.get_potential_energy() calc.write('Al.gpw','all') calc = GPAW('Al.gpw',txt=None) E = calc.get_potential_energy() from gpaw.xc.hybridk import HybridXC exx = HybridXC('EXX',acdf=True) E_k = E + calc.get_xc_difference(exx) if 0:#size == 1: calc = GPAW('Al.gpw',txt=None, communicator=serial_comm) from gpaw.xc.hybridq import HybridXC exx = HybridXC('EXX') E_q = E + calc.get_xc_difference(exx) print(E_q, E_k) equal(E_q, E_k, 0.001) equal(E_k, -15.6, 0.1) gpaw-0.11.0.13004/gpaw/test/guc_force.py0000664000175000017500000000356712553643472017714 0ustar jensjjensj00000000000000from __future__ import print_function # This tests calculates the force on the atoms of a # slightly distorted Silicon primitive cell. # # If the test fails, set the fd boolean below to enable a (costly) finite # difference check. import numpy as np from ase import Atoms from gpaw import GPAW from gpaw.atom.basis import BasisMaker from gpaw.test import equal sibasis = BasisMaker('Si').generate(2, 1, energysplit=0.3, tailnorm=0.03**.5) basis = {'Si' : sibasis} a = 5.475 system = Atoms(symbols='Si2', pbc=True, cell=0.5 * a * np.array([(1, 1, 0), (1, 0, 1), (0, 1, 1)]), scaled_positions=[(0.0, 0.0, 0.0), (0.23, 0.23, 0.23)]) calc = GPAW(h=0.2, mode='lcao', basis=basis, kpts=(2,2,2), convergence={'density':1e-5, 'energy': 1e-6} ) system.set_calculator(calc) F_ac = system.get_forces() # Previous FD result, generated by disabled code below F_ac_ref = np.array([[-1.39639348, -1.39424322, -1.39424321], [ 1.40435678, 1.4016253 , 1.4016297 ]]) err_ac = np.abs(F_ac - F_ac_ref) err = err_ac.max() print('Force') print(F_ac) print() print('Reference result') print(F_ac_ref) print() print('Error') print(err_ac) print() print('Max error') print(err) # ASE uses dx = [+|-] 0.001 by default, # error should be around 2e-3. In fact 4e-3 would probably be acceptable equal(err, 0, 6e-3) # Set boolean to run new FD check fd = False if fd: from ase.calculators.test import numeric_forces calc.set(symmetry='off') F_ac_fd = numeric_forces(system) print('Self-consistent forces') print(F_ac) print('FD') print(F_ac_fd) print(repr(F_ac_fd)) print(F_ac - F_ac_fd, np.abs(F_ac - F_ac_fd).max()) assert np.abs(F_ac - F_ac_fd).max() < 4e-3 gpaw-0.11.0.13004/gpaw/test/elf.py0000664000175000017500000000657512553643471016527 0ustar jensjjensj00000000000000from __future__ import print_function import sys import numpy as np from ase.structure import molecule from ase.io import write from ase.parallel import parprint from gpaw import GPAW, restart from gpaw.elf import ELF from gpaw.test import equal from gpaw.mpi import rank, world atoms = molecule('CO') atoms.center(2.0) txt=sys.stdout txt=None try: atoms, calc = restart('CO.gpw', txt=txt) energy = atoms.get_potential_energy() except: calc = GPAW(h=0.24, txt=txt) atoms.set_calculator(calc) energy = atoms.get_potential_energy() calc.write('CO.gpw', 'all') elf = ELF(calc) elf.update() elf_G = elf.get_electronic_localization_function(gridrefinement=1) elf_g = elf.get_electronic_localization_function(gridrefinement=2) nt_G = calc.density.nt_sG[0] taut_G = elf.taut_sG[0] nt_grad2_G = elf.nt_grad2_sG[0] nt_grad2_g = elf.nt_grad2_sg[0] # integrate the CO bond if rank == 0: # bond area x0 = (atoms.positions[0][0] - 1.0)/atoms.get_cell()[0,0] x1 = 1 - x0 y0 = (atoms.positions[0][1] -1.0)/atoms.get_cell()[1,1] y1 = 1 - y0 z0 = atoms.positions[1][2]/atoms.get_cell()[2,2] z1 = atoms.positions[0][2]/atoms.get_cell()[2,2] gd = calc.wfs.gd Gx0, Gx1 = int(gd.N_c[0]*x0), int(gd.N_c[0] * x1) Gy0, Gy1 = int(gd.N_c[1]*y0), int(gd.N_c[1] * y1) Gz0, Gz1 = int(gd.N_c[2]*z0), int(gd.N_c[2] * z1) finegd = calc.density.finegd gx0, gx1 = int(finegd.N_c[0]*x0), int(finegd.N_c[0] * x1) gy0, gy1 = int(finegd.N_c[1]*y0), int(finegd.N_c[1] * y1) gz0, gz1 = int(finegd.N_c[2]*z0), int(finegd.N_c[2] * z1) int1 = elf_G[Gx0:Gx1,Gy0:Gy1,Gz0:Gz1].sum() * gd.dv int2 = elf_g[gx0:gx1,gy0:gy1,gz0:gz1].sum() * finegd.dv parprint("Ints", int1, int2) parprint("Min, max G", np.min(elf_G), np.max(elf_G)) parprint("Min, max g", np.min(elf_g), np.max(elf_g)) # The tested values (< r7887) do not seem to be correct # equal(int1, 14.8078, 0.0001) # equal(int2, 13.0331, 0.0001) # check spin-polarized version try: atoms, calc = restart('COspin.gpw', txt=None, parallel={'domain': world.size}) energy_spinpol = atoms.get_potential_energy() except: calc.set(spinpol=True, parallel={'domain': world.size}) energy_spinpol = atoms.get_potential_energy() calc.write('COspin.gpw', 'all') def check_diff(g1, g2, gd, txt): # print rank, txt, "shapes", g1.shape, g2.shape intd = gd.integrate(np.abs(g1 - g2)) parprint(txt, 'integrated diff=', intd, end='') maxd = np.max(np.abs(g1 - g2)) parprint('max diff=', maxd) equal(intd, 0, 1.e-8) equal(maxd, 0, 1.e-9) nt_spinpol_G = calc.density.nt_sG.sum(axis=0) check_diff(nt_G, nt_spinpol_G, elf.finegd, 'nt_G') equal(energy, energy_spinpol, 0.0001) elf_spinpol = ELF(calc) elf_spinpol.update() elf_spinpol_G = elf_spinpol.get_electronic_localization_function(gridrefinement=1) elf_spinpol_g = elf_spinpol.get_electronic_localization_function(gridrefinement=2) taut_spinpol_G = elf_spinpol.taut_sG.sum(axis=0) check_diff(taut_G, taut_spinpol_G, elf.gd, 'taut_G') nt_grad2_spinpol_G = 2 * elf_spinpol.nt_grad2_sG.sum(axis=0) check_diff(nt_grad2_G, nt_grad2_spinpol_G, elf.gd, 'nt_grad2_G') nt_grad2_spinpol_g = 2 * elf_spinpol.nt_grad2_sg.sum(axis=0) check_diff(nt_grad2_g, nt_grad2_spinpol_g, elf.finegd, 'nt_grad2_g') check_diff(elf_G, elf_spinpol_G, elf.gd, 'elf_G') check_diff(elf_g, elf_spinpol_g, elf.finegd, 'elf_g') gpaw-0.11.0.13004/gpaw/test/nscfsic.py0000664000175000017500000000145712553643471017403 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atoms from gpaw import GPAW from gpaw.utilities.sic import NSCFSIC atoms = ['He','Be'] #,'Ne'] # Ne deviates already 2.5 eV EE = [] EREF = [-79.4,-399.8,-3517.6] for a in atoms: s = Atoms(a) s.center(vacuum=4.0) calc = GPAW(h=0.15, txt=a + '.txt') s.set_calculator(calc) E = s.get_potential_energy() EE.append(NSCFSIC(calc).calculate()) print("Difference to table VI of Phys. Rev. B 23, 5048 in eV") #http://prola.aps.org/abstract/PRB/v23/i10/p5048_1 print("%10s%10s%10s%10s" % ("atom", "ref.", "gpaw", "diff")) for a, er, e in zip(atoms, EREF, EE): print("%10s%10.2f%10.2f%10.2f" % (a, er, e, er-e)) assert abs(er-e)<0.1 # Arbitary 0.1 eV tolerance for non-self consistent SIC # Note that Ne already deviates 2.5 eV gpaw-0.11.0.13004/gpaw/test/spinpol.py0000664000175000017500000000126312553643471017432 0ustar jensjjensj00000000000000from ase import Atom, Atoms from gpaw import GPAW, FermiDirac from gpaw.test import equal a = 4.0 n = 16 hydrogen = Atoms([Atom('H')], cell=(a, a, a), pbc=True) hydrogen.center() calc = GPAW(gpts=(n, n, n), nbands=1, convergence={'energy': 1e-5}, occupations=FermiDirac(0.0)) hydrogen.set_calculator(calc) e1 = hydrogen.get_potential_energy() niter1 = calc.get_number_of_iterations() hydrogen.set_initial_magnetic_moments([1.0]) e2 = hydrogen.get_potential_energy() niter2 = calc.get_number_of_iterations() de = e1 - e2 print(de) equal(de, 0.7871, 1.e-4) energy_tolerance = 0.00006 niter_tolerance = 0 equal(e1, -0.499854, energy_tolerance) equal(e2, -1.287, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/hyd_chain_response.py0000664000175000017500000000251712553643472021616 0ustar jensjjensj00000000000000# Test of the handling of degenerate bands in response code from ase import Atoms from gpaw import GPAW, PW from gpaw.response.df import DielectricFunction from gpaw.test import findpeak, equal import numpy as np def get_hydrogen_chain_dielectric_function(NH, NK): a = Atoms('H', cell=[1, 1, 1], pbc=True) a.center() a = a.repeat((1, 1, NH)) a.calc = GPAW(mode=PW(200), kpts={'size': (1, 1, NK), 'gamma': True}, parallel={'band': 1}, dtype=complex, gpts=(10, 10, 10 * NH)) a.get_potential_energy() a.calc.diagonalize_full_hamiltonian(nbands=2 * NH) a.calc.write('H_chain.gpw', 'all') DF = DielectricFunction('H_chain.gpw', ecut=1e-3, hilbert=False, omega2=np.inf, intraband=False) eps_NLF, eps_LF = DF.get_dielectric_function(direction='z') omega_w = DF.get_frequencies() return omega_w, eps_LF NH_i = [2**n for n in [0, 4]] NK_i = [2**n for n in [6, 2]] opeak_old = np.nan peak_old = np.nan for NH, NK in zip(NH_i, NK_i): omega_w, eps_w = get_hydrogen_chain_dielectric_function(NH, NK) eels_w = -(1. / eps_w).imag opeak, peak = findpeak(omega_w, eels_w) # Test for consistency if not np.isnan(opeak_old): equal(opeak, opeak_old, tolerance=1e-3) equal(peak, peak_old, tolerance=1e-3) opeak_old = opeak peak_old = peak gpaw-0.11.0.13004/gpaw/test/fixmom.py0000664000175000017500000000163312553643471017246 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW, FermiDirac from gpaw.eigensolvers.rmm_diis_old import RMM_DIIS from gpaw.mixer import MixerSum from gpaw.test import equal a = 2.87 bulk = Atoms('Fe2', scaled_positions=[(0, 0, 0), (0.5, 0.5, 0.5)], magmoms=[2.20, 2.20], cell=(a, a, a), pbc=True) mom0 = sum(bulk.get_initial_magnetic_moments()) h = 0.2 conv = {'eigenstates': 0.1, 'density':0.1, 'energy':0.01} calc = GPAW(h=h, eigensolver=RMM_DIIS(), mixer=MixerSum(0.1,3), nbands=11, kpts=(3, 3, 3), convergence=conv, occupations=FermiDirac(0.1, fixmagmom=True)) bulk.set_calculator(calc) e = bulk.get_potential_energy() niter = calc.get_number_of_iterations() mom = calc.get_magnetic_moment() equal(mom, mom0, 1e-5) energy_tolerance = 0.0002 niter_tolerance = 0 equal(e, -20.3251, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/exx_q.py0000664000175000017500000000226712553643472017100 0ustar jensjjensj00000000000000from __future__ import print_function from ase import * from ase.dft.kpoints import monkhorst_pack from ase.lattice import bulk from gpaw import * from gpaw.test import equal import numpy as np a0 = 5.43 cell = bulk('Si', 'fcc', a=a0).get_cell() Si = Atoms('Si2', cell=cell, pbc=True, scaled_positions=((0,0,0), (0.25,0.25,0.25))) kpts = monkhorst_pack((2,2,2)) kpts += np.array([1/4., 1/4., 1/4.]) calc = GPAW(h=0.18, kpts=kpts, # parallel={'domain':1}, idiotproof=False, occupations=FermiDirac(0.001)) Si.set_calculator(calc) E = Si.get_potential_energy() #from gpaw.xc.hybridq import HybridXC #exx = HybridXC('EXX') #E_q = E + calc.get_xc_difference(exx) from gpaw.xc.hybridk import HybridXC exx = HybridXC('EXX', acdf=True, etotflag=True) E_k1 = E + calc.get_xc_difference(exx) from gpaw.xc.hybridk import HybridXC exx = HybridXC('EXX', acdf=False, etotflag=True) E_k2 = E + calc.get_xc_difference(exx) #print 'Hartree-Fock ACDF method (hybridq.py) :', E_q print('Hartree-Fock ACDF method (hybridk.py) :', E_k1) print('Hartree-Fock Standard method :', E_k2) equal(E_k2, E_k1, 0.001) #equal(E_q, E_k1, 0.001) equal(E_k1, -27.71, 0.01) gpaw-0.11.0.13004/gpaw/test/fractional_translations_med.py0000664000175000017500000000223512553643471023516 0ustar jensjjensj00000000000000from ase.lattice.spacegroup import crystal from gpaw import GPAW from gpaw import PW from gpaw.test import equal name = 'quartz' # no. 152 - trigonal a = 5.032090 c = a * 1.0968533 p0 = (0.4778763, 0.0, 1. / 3.) p1 = (0.4153076, 0.2531340, 0.2029893) atoms = crystal(['Si', 'O'], basis=[p0, p1], spacegroup=152, cellpar=[a, a, c, 90, 90, 120]) ## with fractional translations calc = GPAW(mode=PW(), xc='LDA', kpts=(3, 3, 3), nbands=42, symmetry={'symmorphic': False}, gpts=(20, 20, 24), eigensolver='rmm-diis') atoms.set_calculator(calc) energy_fractrans = atoms.get_potential_energy() assert(len(calc.wfs.kd.ibzk_kc) == 7) assert(len(calc.wfs.kd.symmetry.op_scc) == 6) ## without fractional translations calc = GPAW(mode=PW(), xc='LDA', kpts=(3, 3, 3), nbands=42, gpts=(20, 20, 24), eigensolver='rmm-diis') atoms.set_calculator(calc) energy_no_fractrans = atoms.get_potential_energy() assert(len(calc.wfs.kd.ibzk_kc) == 10) assert(len(calc.wfs.kd.symmetry.op_scc) == 2) equal(energy_fractrans, energy_no_fractrans, 1e-3) gpaw-0.11.0.13004/gpaw/test/poisson_asym.py0000664000175000017500000000272012553643471020470 0ustar jensjjensj00000000000000"""Test poisson solver for asymmetric charges.""" from __future__ import print_function from gpaw.utilities.gauss import Gaussian from gpaw.grid_descriptor import GridDescriptor from gpaw.poisson import PoissonSolver # Initialize classes a = 20 # Size of cell inv_width = 19 # inverse width of the gaussian N = 48 # Number of grid points center_of_charge = (a / 2, a / 2, 3 * a / 4) # off center charge Nc = (N, N, N) # Number of grid points along each axis gd = GridDescriptor(Nc, (a, a, a), 0) # Grid-descriptor object solver = PoissonSolver(nn=3, use_charge_center=True) solver.set_grid_descriptor(gd) solver.initialize() gauss = Gaussian(gd, a=inv_width, center=center_of_charge) test_poisson = Gaussian(gd, a=inv_width, center=center_of_charge) # /-------------------------------------------------\ # | Check if Gaussian potentials are made correctly | # \-------------------------------------------------/ # Array for storing the potential pot = gd.zeros(dtype=float, global_array=False) solver.load_gauss() vg = test_poisson.get_gauss_pot(0) # Get analytic functions ng = gauss.get_gauss(0) # vg = solver.phi_gauss # Solve potential numerically niter = solver.solve(pot, ng, charge=1.0, zero_initial_phi=False) # Determine residual # residual = norm(pot - vg) residual = gd.integrate((pot - vg)**2)**0.5 print('residual %s' % ( residual)) assert residual < 1e-5 # Better than 5.x # mpirun -np 2 python gauss_func.py --gpaw-parallel --gpaw-debug gpaw-0.11.0.13004/gpaw/test/numpy_test.py0000664000175000017500000000067212553643471020160 0ustar jensjjensj00000000000000from __future__ import print_function import sys from numpy import test from gpaw.mpi import rank _stdout = sys.stdout _stderr = sys.stderr # numpy tests write to stderr sys.stderr = open("numpy_test%02d.out" % rank, "w") result = test(verbose=10) sys.stdout = _stdout sys.stderr = _stderr if not result.wasSuccessful(): print("numpy_test%02d.out" % rank, result.errors, result.failures, file=sys.stderr) assert result.wasSuccessful() gpaw-0.11.0.13004/gpaw/test/rpa_C6_He.py0000664000175000017500000000115412553643471017473 0ustar jensjjensj00000000000000from ase import * from ase.structure import molecule from gpaw import * from gpaw.mpi import serial_comm from gpaw.test import equal from gpaw.xc.rpa_correlation_energy import RPACorrelation ecut = 50 He = Atoms('He') He.center(vacuum=1.0) calc = GPAW(mode='pw', dtype=complex, xc='PBE', communicator=serial_comm) He.set_calculator(calc) He.get_potential_energy() calc.diagonalize_full_hamiltonian() rpa = RPACorrelation(calc) C6_rpa, C6_0 = rpa.get_C6_coefficient(ecut=ecut, direction=2) equal(C6_0, 1.772, 0.01) equal(C6_rpa, 1.387, 0.01) gpaw-0.11.0.13004/gpaw/test/revPBE.py0000664000175000017500000000133612553643471017072 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW from gpaw.test import equal from ase.units import Bohr, Hartree a = 7.5 * Bohr n = 16 atoms = Atoms('He', [(0.0, 0.0, 0.0)], cell=(a, a, a), pbc=True) calc = GPAW(gpts=(n, n, n), nbands=1, xc='PBE') atoms.set_calculator(calc) e1 = atoms.get_potential_energy() niter1 = calc.get_number_of_iterations() e1a = calc.get_reference_energy() calc.set(xc='revPBE') e2 = atoms.get_potential_energy() niter2 = calc.get_number_of_iterations() e2a = calc.get_reference_energy() equal(e1a, -2.893 * Hartree, 8e-3) equal(e2a, -2.908 * Hartree, 9e-3) equal(e1, e2, 4e-3) energy_tolerance = 0.00005 niter_tolerance = 0 equal(e1, -0.0790449962, energy_tolerance) equal(e2, -0.08147563, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/restart2.py0000664000175000017500000000212212553643471017507 0ustar jensjjensj00000000000000"""Test automatically write out of restart files""" import os from glob import glob from gpaw import GPAW from ase import Atom, Atoms from gpaw.test import equal restart = 'gpaw-restart' result = 'gpaw-result' # H atom: H = Atoms([Atom('H')]) H.center(vacuum=3.0) calc = GPAW(gpts=(32, 32, 32), nbands=1) calc.attach(calc.write, 4, restart) H.set_calculator(calc) e = H.get_potential_energy() niter = calc.get_number_of_iterations() calc.write(result) # the two files should be equal from gpaw.mpi import rank if rank == 0: for f in ['gpaw-restart', 'gpaw-result']: os.system('rm -rf %s; mkdir %s; cd %s; tar xf ../%s.gpw' % (f, f, f, f)) # make a list of the files to compare files_restart = glob(restart+'/*') files_result = glob(result+'/*') for f1, f2 in zip(files_restart, files_result): # cmp is a byte-by-byte comparison, more portable than diff assert os.system('cmp %s %s' % (f1, f2)) == 0 os.system('rm -rf gpaw-restart gpaw-result') energy_tolerance = 0.00006 niter_tolerance = 0 equal(e, 0.0451789, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/vdw/0000775000175000017500000000000012553644063016170 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/vdw/ar2.py0000664000175000017500000000177112553643471017236 0ustar jensjjensj00000000000000from math import sqrt from ase import Atoms from gpaw import GPAW from gpaw.test import equal from gpaw.xc.vdw import VDWFunctional energy_tolerance = 0.002 def test(): vdw = VDWFunctional('vdW-DF', verbose=1) d = 3.9 x = d / sqrt(3) L = 3.0 + 2 * 4.0 dimer = Atoms('Ar2', [(0, 0, 0), (x, x, x)], cell=(L, L, L)) dimer.center() calc = GPAW(h=0.2, xc='revPBE') dimer.set_calculator(calc) e2 = dimer.get_potential_energy() calc.write('Ar2.gpw') e2vdw = calc.get_xc_difference(vdw) e2vdwb = GPAW('Ar2.gpw').get_xc_difference(vdw) print(e2vdwb - e2vdw) assert abs(e2vdwb - e2vdw) < 1e-9 del dimer[1] e = dimer.get_potential_energy() evdw = calc.get_xc_difference(vdw) E = 2 * e - e2 Evdw = E + 2 * evdw - e2vdw print(E, Evdw) assert abs(E - -0.0048) < 6e-3, abs(E) assert abs(Evdw - +0.0223) < 3e-2, abs(Evdw) print(e2, e) equal(e2, -0.001581923, energy_tolerance) equal(e, -0.003224226, energy_tolerance) test() gpaw-0.11.0.13004/gpaw/test/vdw/potential.py0000664000175000017500000000235012553643471020543 0ustar jensjjensj00000000000000"""Test correctness of vdW-DF potential.""" from math import pi from gpaw.grid_descriptor import GridDescriptor import numpy as np from gpaw.test import equal from gpaw.xc import XC from gpaw.mpi import world N = 8 a = 2.0 gd = GridDescriptor((N, N, N), (a, a, a)) def paired(): xc = XC('vdW-DF') n = 0.3 * np.ones((1, N, N, N)) n += 0.01 * np.cos(np.arange(N) * 2 * pi / N) v = 0.0 * n xc.calculate(gd, n, v) n2 = 1.0 * n i = 1 n2[0, i, i, i] += 0.00002 x = v[0, i, i, i] * gd.dv E2 = xc.calculate(gd, n2, v) n2[0, i, i, i] -= 0.00004 E2 -= xc.calculate(gd, n2, v) x2 = E2 / 0.00004 print(i, x, x2, x - x2, x / x2) equal(x, x2, 2e-11) def polarized(): xc = XC('vdW-DF') n = 0.04 * np.ones((2, N, N, N)) n[1] = 0.3 n[0] += 0.02 * np.sin(np.arange(N) * 2 * pi / N) n[1] += 0.2 * np.cos(np.arange(N) * 2 * pi / N) v = 0.0 * n xc.calculate(gd, n, v) n2 = 1.0 * n i = 1 n2[0, i, i, i] += 0.00002 x = v[0, i, i, i] * gd.dv E2 = xc.calculate(gd, n2, v) n2[0, i, i, i] -= 0.00004 E2 -= xc.calculate(gd, n2, v) x2 = E2 / 0.00004 print(i, x, x2, x - x2, x / x2) equal(x, x2, 1e-10) if world.size == 1: polarized() paired() gpaw-0.11.0.13004/gpaw/test/vdw/quick_spin.py0000664000175000017500000000105612553643471020713 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW, FermiDirac L = 2.5 a = Atoms('H', cell=(L, L, L), pbc=True) calc = GPAW(xc='vdW-DF', occupations=FermiDirac(width=0.001), txt='H.vdW-DF.txt') a.set_calculator(calc) e1 = a.get_potential_energy() calc.set(txt='H.vdW-DF.spinpol.txt', spinpol=True, occupations=FermiDirac(width=0.001, fixmagmom=True)) e2 = a.get_potential_energy() assert abs(calc.get_eigenvalues(spin=0)[0] - calc.get_eigenvalues(spin=1)[0]) < 1e-10 assert abs(e1 - e2) < 5e-8, abs(e1 - e2) gpaw-0.11.0.13004/gpaw/test/vdw/quick.py0000664000175000017500000000047612553643471017667 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW from gpaw.xc.vdw import VDWFunctional vdw = VDWFunctional('vdW-DF', verbose=1) L = 2.5 a = Atoms('H', cell=(L, L, L), pbc=True, calculator=GPAW(nbands=1)) e = a.get_potential_energy() e2 = a.calc.get_xc_difference(vdw) print(e, e2) assert (vdw.shape == (24, 24, 24)).all() gpaw-0.11.0.13004/gpaw/test/vdw/__init__.py0000664000175000017500000000000112553643471020272 0ustar jensjjensj00000000000000 gpaw-0.11.0.13004/gpaw/test/2Al.py0000664000175000017500000000160112553643472016361 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atom, Atoms from gpaw import GPAW from gpaw.test import equal a = 4.05 d = a / 2**0.5 bulk = Atoms([Atom('Al', (0, 0, 0)), Atom('Al', (0, 0, d))], cell=(4*d, 4*d, 2*d), pbc=1) n = 16 calc = GPAW(gpts=(2*n, 2*n, 1*n), nbands=1*8, kpts=(1, 1, 4), convergence={'eigenstates': 2.3e-9}, xc='LDA') bulk.set_calculator(calc) e2 = bulk.get_potential_energy() niter2 = calc.get_number_of_iterations() bulk = bulk.repeat((1, 1, 2)) bulk.set_calculator(calc) calc.set(nbands=16, kpts=(1, 1, 2), gpts=(2*n, 2*n, 2*n)) e4 = bulk.get_potential_energy() niter4 = calc.get_number_of_iterations() # checks energy_tolerance = 0.00007 niter_tolerance = 0 print(e2, e4) equal(e4 / 2, e2, 48e-6) equal(e2, -3.41595, energy_tolerance) equal(e4, -6.83191, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/parunittest.py0000664000175000017500000003111212553643471020324 0ustar jensjjensj00000000000000""" Python unit testing framework, based on Erich Gamma's JUnit and Kent Beck's Smalltalk testing framework. Parallel support by Christian Glinsvad. For further information please consult the documentation for the Unittest module, from which this module is derived. Online reference manual at: http://docs.python.org/dev/library/unittest.html Copyright (c) 1999-2003 Steve Purcell This module is free software, and you may redistribute it and/or modify it under the same terms as Python itself, so long as this copyright message and disclaimer are retained in their original form. IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. """ from __future__ import print_function import sys import numpy as np from unittest import TestResult, TestCase, TestSuite, \ _TextTestResult, TextTestRunner, TestLoader, \ FunctionTestCase, TestProgram, defaultTestLoader from ase.utils import devnull from gpaw import debug from gpaw.mpi import world, broadcast_string # ------------------------------------------------------------------- # Exported classes and functions # ------------------------------------------------------------------- __all__ = ['ParallelTestResult', 'ParallelTestCase', 'ParallelTestSuite', 'ParallelTextTestRunner', 'ParallelTestLoader', 'ParallelFunctionTestCase', 'main', 'defaultParallelTestLoader'] # ------------------------------------------------------------------- # Limited backward compatibility # ------------------------------------------------------------------- if sys.version_info[:2] < (2, 3): raise RuntimeError('Python 2.3 or greater required!') try: from unittest import __version__ except ImportError: unittest_version = (2, 0) else: unittest_version = tuple(map(int, __version__.split('.'))) # User interface should at least comply with Unittest version 1.56 rev. 34209 if unittest_version < (1,56): _TestCase = TestCase class TestCase(_TestCase): assertTrue = _TestCase.assertTrue assertFalse = _TestCase.assertFalse # ------------------------------------------------------------------- # Test framework core # ------------------------------------------------------------------- class ParallelTestResult(TestResult): __doc__ = TestResult.__doc__ def __init__(self, comm=None): if comm is None: comm = world self.comm = comm self.outcomes = [] self.last_errors = np.empty(self.comm.size, dtype=bool) self.last_failed = np.empty(self.comm.size, dtype=bool) TestResult.__init__(self) def startTest(self, test): "Called when the given test is about to be run. Resets global flags." self.last_errors.fill(False) self.last_failed.fill(False) TestResult.startTest(self, test) def stopTest(self, test): """Called when the given test has been run. If the stop flag was raised beforehand, will broadcast to raise flags for global stop.""" stop_flags = np.empty(self.comm.size, dtype=bool) self.comm.all_gather(np.array([self.shouldStop]), stop_flags) self.shouldStop = stop_flags.any() TestResult.stopTest(self, test) def _exc_info_to_string(self, err, test): # Includes second argument as of Unittest version 1.63 rev. 34859 if unittest_version < (1,63): return TestResult._exc_info_to_string(self, err) else: return TestResult._exc_info_to_string(self, err, test) def addStatus(self, test, err=None, error=False, failure=False): """Negotiate global status immediately after a test has been run. Called on all processor with the local test status (i.e. error, failure or success). 'err' is a tuple of values as returned by sys.exc_info(). """ if error and failure: raise RuntimeError('Parallel unittest can\'t handle simultaneous' \ + ' errors and failures within a single test.') self.comm.all_gather(np.array([error]), self.last_errors) if self.last_errors.any(): all_texts = [] for rank in np.argwhere(self.last_errors).ravel(): if rank == self.comm.rank: assert self.last_errors[self.comm.rank] text = self._exc_info_to_string(err, test) else: text = None text = broadcast_string(text, root=rank, comm=self.comm) all_texts.append((rank,text)) self.errors.append((test, all_texts)) self.comm.all_gather(np.array([failure]), self.last_failed) if self.last_failed.any(): all_texts = [] for rank in np.argwhere(self.last_failed).ravel(): if rank == self.comm.rank: assert self.last_failed[self.comm.rank] text = self._exc_info_to_string(err, test) else: text = None text = broadcast_string(text, root=rank, comm=self.comm) all_texts.append((rank,text)) self.failures.append((test, all_texts)) def addError(self, test, err): """Negotiate global status. Called when an error has occurred on a processor. 'err' is a tuple of values as returned by sys.exc_info(). """ self.addStatus(test, err, error=True) def addFailure(self, test, err): """Negotiate global status. Called when an failure has occurred on a processor. 'err' is a tuple of values as returned by sys.exc_info(). """ self.addStatus(test, err, failure=True) def addSuccess(self, test): """Probe global status for potential errors by passive negotiation. Called when a test has completed successfully on a processor. """ self.addStatus(test) def addSkip(self, test, reason): """Called when a test is skipped. Not ready!""" raise NotImplementedError def addExpectedFailure(self, test, err): """Called when an expected failure/error occured. Not ready!""" raise NotImplementedError def addUnexpectedSuccess(self, test): """Called when a test was expected to fail, but succeed. Not ready!""" raise NotImplementedError class ParallelTestCase(TestCase): __doc__ = TestCase.__doc__ def defaultTestResult(self): return ParallelTestResult() def debug(self): """Run the test without collecting errors in a TestResult""" print('WARNING: Test case is strictly serial in debug mode!') TestCase.debug(self) # No point in implementing these as the originals work just fine ParallelTestSuite = TestSuite ParallelFunctionTestCase = FunctionTestCase # ------------------------------------------------------------------- # Locating and loading tests # ------------------------------------------------------------------- # No point in implementing these as the originals work just fine ParallelTestLoader = TestLoader defaultParallelTestLoader = ParallelTestLoader() # ------------------------------------------------------------------- # Text UI # ------------------------------------------------------------------- class _ParallelTextTestResult(ParallelTestResult, _TextTestResult): __doc__ = _TextTestResult.__doc__ allErrors = False def __init__(self, comm, *args, **kwargs): ParallelTestResult.__init__(self, comm) _TextTestResult.__init__(self, *args, **kwargs) # use new-style? def startTest(self, test): ParallelTestResult.startTest(self, test) if self.showAll: self.stream.write(self.getDescription(test)) self.stream.write(" ... ") self.stream.flush() def addSuccess(self, test): ParallelTestResult.addSuccess(self, test) def addError(self, test, err): ParallelTestResult.addError(self, test, err) def addFailure(self, test, err): ParallelTestResult.addFailure(self, test, err) def shortRanks(self, ranks): if len(ranks) == 0: return 'none' elif isinstance(ranks, np.ndarray) and ranks.dtype == bool: if ranks.all(): return 'all' ranks = np.argwhere(ranks).ravel() ranks = np.sort(ranks) if np.all(ranks == range(self.comm.size)): return 'all' return 'rank ' + ','.join(map(str,ranks)) def stopTest(self, test): self.stream.flush() self.comm.barrier() if self.last_errors.any() and self.last_failed.any(): if not debug: raise RuntimeError('Parallel unittest can\'t handle ' \ 'simultaneous errors and failures within a single test.') if self.showAll: error_rankinfo = self.shortRanks(self.last_errors) fail_rankinfo = self.shortRanks(self.last_failed) self.stream.writeln("ERROR (%s) / FAIL (%s)" \ % (error_rankinfo, fail_rankinfo)) elif self.dots: self.stream.writeln('M') elif self.last_errors.any(): if self.showAll: rankinfo = self.shortRanks(self.last_errors) self.stream.writeln("ERROR (%s)" % rankinfo) elif self.dots: self.stream.writeln('E') elif self.last_failed.any(): if self.showAll: rankinfo = self.shortRanks(self.last_failed) self.stream.writeln("FAIL (%s)" % rankinfo) elif self.dots: self.stream.writeln('F') else: if self.showAll: self.stream.writeln("ok") else: self.stream.writeln('.') def printErrorList(self, flavour, errors): for test, all_texts in errors: description = self.getDescription(test) if all_texts: self.stream.writeln(self.separator1) if self.allErrors: for rank, text2 in all_texts: rankinfo = self.shortRanks([rank]).upper() text1 = '%s-%s: %s' % (flavour, rankinfo, description) self.stream.writeln(text1) self.stream.writeln(self.separator2) self.stream.writeln(text2) else: text_ranks = {} for rank, text2 in all_texts: if text2 not in text_ranks: text_ranks[text2] = [] text_ranks[text2].append(rank) for text2, ranks in text_ranks.items(): rankinfo = self.shortRanks(ranks).upper() text1 = '%s-%s: %s' % (flavour, rankinfo, description) self.stream.writeln(text1) self.stream.writeln(self.separator2) self.stream.writeln(text2) class ParallelTextTestRunner(TextTestRunner): __doc__ = TextTestRunner.__doc__ logfile = None def __init__(self, comm=None, stream=sys.stderr, **kwargs): if comm is None: comm = world self.comm = comm if self.comm.rank != 0: stream = devnull elif isinstance(stream, str): self.logfile = stream stream = open(self.logfile, 'w', buffering=0) TextTestRunner.__init__(self, stream=stream, **kwargs) def _makeResult(self): return _ParallelTextTestResult(self.comm, self.stream, \ self.descriptions, self.verbosity) def run(self, test): stderr_old = sys.stderr try: sys.stderr = self.stream testresult = TextTestRunner.run(self, test) finally: sys.stderr = stderr_old return testresult # ------------------------------------------------------------------- # Facilities for running tests from the command line # ------------------------------------------------------------------- class ParallelTestProgram(TestProgram): __doc__ = TestProgram.__doc__ def runTests(self): if self.testRunner is None: self.testRunner = ParallelTextTestRunner(verbosity=self.verbosity) TestProgram.runTests(self) main = ParallelTestProgram gpaw-0.11.0.13004/gpaw/test/blocked_rmm_diis.py0000664000175000017500000000157012553643471021235 0ustar jensjjensj00000000000000import numpy as np from ase import Atom, Atoms from gpaw import GPAW, Mixer, RMM_DIIS from gpaw.test import equal a = 4.0 n = 20 d = 1.0 x = d / 3**0.5 atoms = Atoms([Atom('C', (0.0, 0.0, 0.0)), Atom('H', (x, x, x)), Atom('H', (-x, -x, x)), Atom('H', (x, -x, -x)), Atom('H', (-x, x, -x))], cell=(a, a, a), pbc=True) calc = GPAW(gpts=(n, n, n), nbands=4, txt='a.txt', mixer=Mixer(0.25, 3, 1), eigensolver='rmm-diis') atoms.set_calculator(calc) e0 = atoms.get_potential_energy() niter0 = calc.get_number_of_iterations() es = RMM_DIIS(blocksize=3) calc = GPAW(gpts=(n, n, n), nbands=4, txt='b.txt', mixer=Mixer(0.25, 3, 1), eigensolver=es) atoms.set_calculator(calc) e1 = atoms.get_potential_energy() niter1 = calc.get_number_of_iterations() equal(e0, e1, 0.000001) equal(niter0, niter1, 0) gpaw-0.11.0.13004/gpaw/test/plt.py0000664000175000017500000000241112553643471016541 0ustar jensjjensj00000000000000import os import numpy as np #numpy.seterr(all='raise') from ase import Atom from ase.io.plt import write_plt, read_plt from gpaw.test import equal from gpaw import GPAW from gpaw.cluster import Cluster txt='-' txt='/dev/null' load = False #load = True R=0.7 # approx. experimental bond length a = 4. c = 4. H2 = Cluster([Atom('H', (a/2,a/2,(c-R)/2)), Atom('H', (a/2,a/2,(c+R)/2))], cell=(a,a,c)) H2.rotate([1.,1.,1.]) ##H2.write('H2.xyz') fname = 'H2.gpw' if (not load) or (not os.path.exists(fname)): calc = GPAW(xc='PBE', nbands=2, spinpol=False, txt=txt) H2.set_calculator(calc) H2.get_potential_energy() if load: calc.write(fname, 'all') else: calc = GPAW(fname, txt=txt) calc.initialize_wave_functions() import gpaw.mpi as mpi fname = 'aed.plt' cell = calc.get_atoms().get_cell() #aed = calc.get_all_electron_density(1, pad=False) aed = calc.get_pseudo_density(1, pad=False) #aed = calc.wfs.gd.collect(aed) if mpi.size == 1: data_org = [aed, cell] write_plt(fname, calc.get_atoms(), aed) # check if read arrays match the written ones data = read_plt(fname) for d, do in zip(data, data_org): dd2 = (d - do)**2 norm = dd2.sum() print(norm) assert(norm < 1e-10) gpaw-0.11.0.13004/gpaw/test/usesymm2.py0000664000175000017500000000175512553643471017540 0ustar jensjjensj00000000000000from math import sqrt from ase import Atoms from gpaw import GPAW a = 2.4437 # Set up graphene structure vacuum = 3 atoms = Atoms(symbols='C2', positions=[(0.5 * a, -sqrt(3) / 6 * a, vacuum), (0.5 * a, +sqrt(3) / 6 * a, vacuum)], cell=[(0.5 * a, -0.5 * 3**0.5 * a, 0), (0.5 * a, +0.5 * 3**0.5 * a, 0), (0.0, 0.0, 2 * vacuum)]) atoms.pbc = True # Gamma-point calculation of graphene calc = GPAW(h=0.2, width=0.15, kpts=(1, 1, 1), xc='LDA') atoms.set_calculator(calc) atoms.get_potential_energy() kpts = [(1 / 2.0, 1 / 3.0, 0)] # Calculate one K-point with symmetry: calc.set(kpts=kpts, fixdensity=True) calc.get_potential_energy() eigs_True = calc.get_eigenvalues(kpt=0) # Redo with the same K-point without symmetry: calc.set(kpts=kpts, symmetry='off', fixdensity=True) calc.get_potential_energy() eigs_False = calc.get_eigenvalues(kpt=0) assert abs(eigs_True[0] - eigs_False[0]) < 1e-4 gpaw-0.11.0.13004/gpaw/test/gw_method.py0000664000175000017500000000270612553643472017727 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from time import time, ctime from datetime import timedelta from ase.lattice import bulk from ase.units import Hartree from gpaw import GPAW, FermiDirac from gpaw.response.gw import GW from gpaw.mpi import serial_comm starttime = time() a = 5.431 atoms = bulk('Si', 'diamond', a=a) kpts = (2,2,2) calc = GPAW( h=0.24, kpts=kpts, xc='LDA', txt='Si_gs.txt', nbands=10, convergence={'bands':8}, occupations=FermiDirac(0.001) ) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('Si_gs.gpw','all') file='Si_gs.gpw' nbands=8 bands=np.array([3,4]) ecut=25./Hartree gw = GW( file=file, nbands=8, bands=np.array([3,4]), w=np.array([10., 30., 0.05]), ecut=25., eta=0.1, hilbert_trans=False ) gw.get_exact_exchange(communicator=serial_comm) gw.get_QP_spectrum() QP_False = gw.QP_skn * Hartree gw = GW( file=file, nbands=8, bands=np.array([3,4]), w=np.array([10., 30., 0.05]), ecut=25., eta=0.1, hilbert_trans=True ) gw.get_QP_spectrum() QP_True = gw.QP_skn * Hartree if not (np.abs(QP_False - QP_True) < 0.01).all(): raise AssertionError("method 1 not equal to method 2") totaltime = round(time() - starttime) print("GW test finished in %s " %(timedelta(seconds=totaltime))) gpaw-0.11.0.13004/gpaw/test/diamond_absorption.py0000664000175000017500000000403412553643471021620 0ustar jensjjensj00000000000000import numpy as np from ase.units import Bohr from ase.lattice import bulk from gpaw import GPAW, FermiDirac from gpaw.response.df import DielectricFunction from gpaw.test import equal, findpeak a = 6.75 * Bohr atoms = bulk('C', 'diamond', a=a) calc = GPAW(mode='pw', kpts=(3, 3, 3), eigensolver='rmm-diis', occupations=FermiDirac(0.001)) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('C.gpw', 'all') # Macroscopic dielectric constant calculation df = DielectricFunction('C.gpw', frequencies=(0.,), eta=0.001, ecut=200, hilbert=False) eM1, eM2 = df.get_macroscopic_dielectric_constant() eM1_ = 9.725 eM2_ = 9.068 equal(eM1, eM1_, 0.01) equal(eM2, eM2_, 0.01) # Absorption spectrum calculation df = DielectricFunction('C.gpw', eta=0.25, ecut=200, frequencies=np.linspace(0, 24., 241), hilbert=False) b0, b = df.get_dielectric_function(filename=None) df.check_sum_rule(b.imag) equal(b0[0].real, eM1_, 0.01) equal(b[0].real, eM2_, 0.01) a0, a = df.get_polarizability(filename=None) df_ws = DielectricFunction('C.gpw', eta=0.25, ecut=200, frequencies=np.linspace(0, 24., 241), hilbert=False, truncation='wigner-seitz') a0_ws, a_ws = df_ws.get_polarizability(filename=None) w0_ = 10.778232265664668 I0_ = 5.5467658790816268 w_ = 10.9530497246 I_ = 6.09704008088 w, I = findpeak(np.linspace(0, 24., 241), b0.imag) equal(w, w0_, 0.05) equal(I / (4 * np.pi), I0_, 0.05) w, I = findpeak(np.linspace(0, 24., 241), a0.imag) equal(w, w0_, 0.05) equal(I, I0_, 0.05) w, I = findpeak(np.linspace(0, 24., 241), a0_ws.imag) equal(w, w0_, 0.05) equal(I, I0_, 0.05) w, I = findpeak(np.linspace(0, 24., 241), b.imag) equal(w, w_, 0.05) equal(I / (4 * np.pi), I_, 0.05) w, I = findpeak(np.linspace(0, 24., 241), a.imag) equal(w, w_, 0.05) equal(I, I_, 0.05) # The Wigner-Seitz truncation does not give exactly the same for kpts=(3,3,3) w, I = findpeak(np.linspace(0, 24., 241), a_ws.imag) equal(w, w_, 0.1) equal(I, I_, 0.1) gpaw-0.11.0.13004/gpaw/test/muffintinpot.py0000664000175000017500000000150712553643471020471 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atoms from gpaw import GPAW, restart from gpaw.test import equal from gpaw.utilities.kspot import AllElectronPotential if 1: be = Atoms(symbols='Be',positions=[(0,0,0)]) be.center(vacuum=5) calc = GPAW(gpts=(64,64,64), xc='LDA', nbands=1) #0.1 required for accuracy be.set_calculator(calc) e = be.get_potential_energy() niter = calc.get_number_of_iterations() #calc.write("be.gpw") energy_tolerance = 0.00001 niter_tolerance = 0 equal(e, 0.00246471, energy_tolerance) #be, calc = restart("be.gpw") AllElectronPotential(calc).write_spherical_ks_potentials('bepot.txt') f = open('bepot.txt') lines = f.readlines() f.close() mmax = 0 for l in lines: mmax = max(abs(eval(l.split(' ')[3])), mmax) print("Max error: ", mmax) assert mmax<0.009 gpaw-0.11.0.13004/gpaw/test/Cl_minus.py0000664000175000017500000000057512553643471017524 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atoms from gpaw import GPAW from gpaw.test import equal s = Atoms('Cl') s.center(vacuum=3) c = GPAW(xc='PBE', nbands=-4, charge=-1, h=0.3) s.set_calculator(c) e = s.get_potential_energy() niter = c.get_number_of_iterations() print(e, niter) energy_tolerance = 0.0003 niter_tolerance = 0 equal(e, -2.89336, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/spinFe3plus.py0000664000175000017500000000135512553643471020163 0ustar jensjjensj00000000000000from ase import Atoms, Atom import numpy as np from gpaw import GPAW, FermiDirac from gpaw.test import equal h=.4 q=3 spin=True s = Atoms([Atom('Fe')]) s.center(vacuum=2.5) convergence={'eigenstates':0.01, 'density':0.1, 'energy':0.1} # use Hunds rules c = GPAW(charge=q, h=h, nbands=5, hund=True, eigensolver='rmm-diis', occupations=FermiDirac(width=0.1), convergence=convergence ) c.calculate(s) equal(c.get_magnetic_moment(0), 5, 0.1) # set magnetic moment mm = [5] s.set_initial_magnetic_moments(mm) c = GPAW(charge=q, h=h, nbands=5, occupations=FermiDirac(width=0.1, fixmagmom=True), convergence=convergence ) c.calculate(s) equal(c.get_magnetic_moment(0), 5, 0.1) gpaw-0.11.0.13004/gpaw/test/harmonic.py0000664000175000017500000000177512553643471017556 0ustar jensjjensj00000000000000from math import pi import numpy as np from ase import Atoms from ase.units import Hartree, Bohr from gpaw import GPAW from gpaw.xc import XC from gpaw.test import equal from gpaw.xc.kernel import XCNull from gpaw.poisson import NoInteractionPoissonSolver a = 4.0 x = Atoms(cell=(a, a, a)) # no atoms class HarmonicPotential: def __init__(self, alpha): self.alpha = alpha self.vext_g = None def get_potential(self, gd): if self.vext_g is None: r_vg = gd.get_grid_point_coordinates() self.vext_g = self.alpha * ((r_vg - a / Bohr / 2)**2).sum(0) return self.vext_g calc = GPAW(charge=-8, nbands=4, h=0.2, xc=XC(XCNull()), external=HarmonicPotential(0.5), poissonsolver=NoInteractionPoissonSolver(), eigensolver='cg') x.calc = calc x.get_potential_energy() eigs = calc.get_eigenvalues() equal(eigs[0], 1.5 * Hartree, 0.002) equal(abs(eigs[1:] - 2.5 * Hartree).max(), 0, 0.003) gpaw-0.11.0.13004/gpaw/test/colinear.py0000664000175000017500000000105212553643471017536 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW, FermiDirac, Mixer #from gpaw.xc.noncolinear import NonColinearLDA, NonColinearLCAOEigensolver, \ # NonColinearMixer h = Atoms('H', magmoms=[1]) h.center(vacuum=2) xc = 'LDA' c = GPAW(txt='c.txt', mode='lcao', basis='dz(dzp)', #setups='ncpp', h=0.25, xc=xc, #occupations=FermiDirac(0.01), mixer=Mixer(), #noncolinear=[(2,0,0)], )#eigensolver=NonColinearLCAOEigensolver()) c.set(nbands=1) h.calc = c h.get_potential_energy() gpaw-0.11.0.13004/gpaw/test/eed.py0000664000175000017500000000115512553643471016503 0ustar jensjjensj00000000000000import os from ase import Atom from gpaw import GPAW from gpaw.cluster import Cluster from gpaw.test import equal from gpaw.analyse.eed import ExteriorElectronDensity fwfname='H2_kpt441_wf.gpw' txt = None #txt = '-' # write first if needed try: c = GPAW(fwfname, txt=txt) s = c.get_atoms() except: s = Cluster([Atom('H'), Atom('H', [0,0,1])], pbc=[1,1,0]) s.minimal_box(3.) c = GPAW(xc='PBE', h=.3, kpts=(4,4,1), convergence={'density':1e-3, 'eigenstates':1e-3}) c.calculate(s) c.write(fwfname, 'all') eed = ExteriorElectronDensity(c.wfs.gd, s) eed.write_mies_weights(c.wfs) gpaw-0.11.0.13004/gpaw/test/kpt.py0000664000175000017500000000161512553643471016545 0ustar jensjjensj00000000000000import numpy as np from ase.dft.kpoints import monkhorst_pack from gpaw.kpt_descriptor import KPointDescriptor, to1bz k = 70 k_kc = monkhorst_pack((k, k, 1)) kd = KPointDescriptor(k_kc + (0.5 / k, 0.5 / k, 0)) assert (kd.N_c == (k, k, 1)).all() assert abs(kd.offset_c - (0.5 / k, 0.5 / k, 0)).sum() < 1e-9 bzk_kc = np.array([[0.5, 0.5, 0], [0.50000000001, 0.5, 0], [0.49999999999, 0.5, 0], [0.55, -0.275, 0]]) cell_cv = np.array([[1, 0, 0], [-0.5, 3**0.5 / 2, 0], [0, 0, 5]]) bz1k_kc = to1bz(bzk_kc, cell_cv) error_kc = bz1k_kc - np.array([[0.5, -0.5, 0], [0.50000000001, -0.5, 0], [0.49999999999, -0.5, 0], [0.55, -0.275, 0]]) assert abs(error_kc).max() == 0.0 assert KPointDescriptor(np.zeros((1, 3)) + 1e-14).gamma gpaw-0.11.0.13004/gpaw/test/inducedfield_lrtddft.py0000664000175000017500000000353112553643472022111 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW from gpaw.lrtddft import LrTDDFT, photoabsorption_spectrum from gpaw.inducedfield.inducedfield_lrtddft import LrTDDFTInducedField import numpy as np # 1) Ground state calculation with empty states atoms = Atoms(symbols='Na2', positions=[(0, 0, 0), (3.0, 0, 0)], pbc=False) atoms.center(vacuum=3.0) calc = GPAW(nbands=20, h=0.6, setups={'Na': '1'}) atoms.set_calculator(calc) energy = atoms.get_potential_energy() calc.write('na2_gs_casida.gpw', mode='all') # 2) Casida calculation calc = GPAW('na2_gs_casida.gpw') istart = 0 jend = 20 lr = LrTDDFT(calc, xc='LDA', istart=istart, jend=jend) lr.diagonalize() lr.write('na2_lr.dat.gz') # 3) Calculate induced field frequencies = [1.0, 2.08] # Frequencies of interest in eV folding = 'Gauss' # Folding function width = 0.1 # Line width for folding in eV kickdir = 0 # Kick field direction 0, 1, 2 for x, y, z ind = LrTDDFTInducedField(paw=calc, lr=lr, frequencies=frequencies, folding=folding, width=width, kickdir=kickdir) ind.calculate_induced_field(gridrefinement=2, from_density='comp') # Test from gpaw.test import equal tol = 0.0001 val1 = ind.fieldgd.integrate(ind.Ffe_wg[0]) val2 = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[0][0])) val3 = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[0][1])) val4 = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[0][2])) val5 = ind.fieldgd.integrate(ind.Ffe_wg[1]) val6 = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[1][0])) val7 = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[1][1])) val8 = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[1][2])) equal(val1, 3175.76177761, tol) equal(val2, 1700.43442519, tol) equal(val3, 1187.26249225, tol) equal(val4, 1187.26249225, tol) equal(val5, 10956.9813196, tol) equal(val6, 6574.58868754, tol) equal(val7, 4589.74440108, tol) equal(val8, 4589.74440108, tol) gpaw-0.11.0.13004/gpaw/test/bse_aluminum.py0000664000175000017500000000352412553643471020430 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from ase.units import Bohr, Hartree from ase.lattice import bulk from gpaw import GPAW from gpaw.eigensolvers.rmm_diis_old import RMM_DIIS from gpaw.mixer import Mixer from gpaw.response.df0 import DF from gpaw.response.bse import BSE GS = 1 df = 1 bse = 1 check_spectrum = 1 if GS: a = 4.043 atoms = bulk('Al', 'fcc', a=a) atoms.center() calc = GPAW(h=0.2, eigensolver=RMM_DIIS(), mixer=Mixer(0.1,3), kpts=(4,2,2), xc='LDA', nbands=4, convergence={'bands':'all'}) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('Al.gpw','all') if bse: bse = BSE('Al.gpw', w=np.linspace(0,24,241), nv=[0,4], nc=[0,4], coupling=True, mode='RPA', q=np.array([0.25, 0, 0]), ecut=50., eta=0.2) bse.get_dielectric_function('Al_bse.dat') if df: # Excited state calculation q = np.array([1/4.,0.,0.]) w = np.linspace(0, 24, 241) df = DF(calc='Al.gpw', q=q, w=w, eta=0.2, ecut=50, hilbert_trans=False) df.get_EELS_spectrum(filename='Al_df.dat') df.write('Al.pckl') df.check_sum_rule() if check_spectrum: d = np.loadtxt('Al_bse.dat')[:,2] wpeak = 16.4 Nw = 164 if d[Nw] > d[Nw-1] and d[Nw] > d[Nw+1]: pass else: raise ValueError('Plasmon peak not correct ! ') if np.abs(d[Nw] - 27.4958893542) > 1e-5: print(d[Nw]) raise ValueError('Please check spectrum strength ! ') d2 = np.loadtxt('Al_df.dat') if np.abs(d[:240] - d2[:240, 2]).sum() > 0.003: raise ValueError('Please compare two spectrum') gpaw-0.11.0.13004/gpaw/test/degeneracy.py0000664000175000017500000000227012553643471020053 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atom, Atoms from gpaw import GPAW from gpaw.test import equal a = 5.0 d = 1.0 x = d / 3**0.5 atoms = Atoms([Atom('C', (0.0, 0.0, 0.0)), Atom('H', (x, x, x)), Atom('H', (-x, -x, x)), Atom('H', (x, -x, -x)), Atom('H', (-x, x, -x))], cell=(a, a, a), pbc=False) atoms.positions[:] += a / 2 calc = GPAW(h=0.25, nbands=4, convergence={'eigenstates': 7.8e-10}) atoms.calc = calc energy = atoms.get_potential_energy() niter = calc.get_number_of_iterations() # The three eigenvalues e[1], e[2], and e[3] must be degenerate: e = calc.get_eigenvalues() print(e[1] - e[3]) equal(e[1], e[3], 9.3e-8) energy_tolerance = 0.0003 niter_tolerance = 0 equal(energy, -23.6277, energy_tolerance) # Calculate non-selfconsistent PBE eigenvalues: from gpaw.xc.tools import vxc epbe0 = e - vxc(calc)[0, 0] + vxc(calc, 'PBE')[0, 0] # Calculate selfconsistent PBE eigenvalues: calc.set(xc='PBE') energy = atoms.get_potential_energy() epbe = calc.get_eigenvalues() de = epbe[1] - epbe[0] de0 = epbe0[1] - epbe0[0] print(de, de0) equal(de, de0, 0.001) gpaw-0.11.0.13004/gpaw/test/revPBE_Li.py0000664000175000017500000000174412553643472017522 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atoms from ase.units import Hartree from gpaw import GPAW, PoissonSolver, FermiDirac from gpaw.test import equal a = 5.0 n = 24 li = Atoms('Li', magmoms=[1.0], cell=(a, a, a), pbc=True) calc = GPAW(gpts=(n, n, n), nbands=1, xc='PBE', poissonsolver=PoissonSolver(nn='M'), convergence=dict(eigenstates=4.5e-8), occupations=FermiDirac(0.0)) li.set_calculator(calc) e = li.get_potential_energy() + calc.get_reference_energy() niter_PBE = calc.get_number_of_iterations() equal(e, -7.462 * Hartree, 1.4) calc.set(xc='revPBE') erev = li.get_potential_energy() + calc.get_reference_energy() niter_revPBE = calc.get_number_of_iterations() equal(erev, -7.487 * Hartree, 1.3) equal(e - erev, 0.025 * Hartree, 0.002 * Hartree) print(e, erev) energy_tolerance = 0.0001 niter_tolerance = 0 equal(e, -204.381098849, energy_tolerance) # svnversion 5252 equal(erev, -205.012303379, energy_tolerance) # svnversion 5252 gpaw-0.11.0.13004/gpaw/test/cluster.py0000664000175000017500000000440612553643471017431 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from ase import Atoms, Atom from ase.parallel import barrier, rank, size from gpaw.cluster import Cluster from gpaw.test import equal from ase.structure import molecule from math import pi, sqrt R = 2.0 CO = Atoms([Atom('C', (1, 0, 0)), Atom('O', (1, 0, R))]) CO.rotate('y', pi/2) equal(CO.positions[1, 0], R, 1e-10) # translate CO.translate(-CO.get_center_of_mass()) p = CO.positions.copy() for i in range(2): equal(p[i, 1], 0, 1e-10) equal(p[i, 2], 0, 1e-10) # rotate the nuclear axis to the direction (1,1,1) CO.rotate(p[1] - p[0], (1, 1, 1)) q = CO.positions.copy() for c in range(3): equal(q[0, c], p[0, 0] / sqrt(3), 1e-10) equal(q[1, c], p[1, 0] / sqrt(3), 1e-10) # minimal box b=4.0 CO = Cluster([Atom('C', (1, 0, 0)), Atom('O', (1, 0, R))]) CO.minimal_box(b) cc = CO.get_cell() for c in range(3): width = 2*b if c==2: width += R equal(cc[c, c], width, 1e-10) # minimal box, ensure multiple of 4 h = .13 b = [2, 3, 4] CO.minimal_box(b, h=h) cc = CO.get_cell() for c in range(3): # print "cc[c,c], cc[c,c] / h % 4 =", cc[c, c], cc[c, c] / h % 4 for a in CO: print(a.symbol, b[c], a.position[c], cc[c, c] - a.position[c]) assert(a.position[c] > b[c]) equal(cc[c, c] / h % 4, 0.0, 1e-10) # ............................................. # connected atoms assert(len(CO.find_connected(0, 1.1 * R)) == 2) assert(len(CO.find_connected(0, 0.9 * R)) == 1) H2O = Cluster(molecule('H2O')) assert (len(H2O.find_connected(0)) == 3) assert (len(H2O.find_connected(0, scale=0.9)) == 1) # ............................................. # I/O fxyz='CO.xyz' fpdb='CO.pdb' cell = [2.,3.,R+2.] CO.set_cell(cell, scale_atoms=True) barrier() CO.write(fxyz) barrier() CO_b = Cluster(filename=fxyz) assert(len(CO) == len(CO_b)) #for a, b in zip(cell, CO_b.get_cell().diagonal()): # assert(a == b) offdiagonal = CO_b.get_cell().sum() - CO_b.get_cell().diagonal().sum() assert(offdiagonal == 0.0) barrier() CO.write(fpdb) # read xyz files with additional info read_with_additional = True if read_with_additional: if rank == 0: f = open(fxyz, 'w') print("""2 C 0 0 0. 1 2 3 O 0 0 1. 6. 7. 8.""", file=f) f.close() barrier() CO = Cluster(filename=fxyz) gpaw-0.11.0.13004/gpaw/test/wannierk_lcao.py0000664000175000017500000000360612553643471020565 0ustar jensjjensj00000000000000'Test ase.dft.wannier module with k-points.' from __future__ import print_function from ase.lattice import bulk from ase.dft.wannier import Wannier from gpaw import GPAW from gpaw.mpi import world, serial_comm si = bulk('Si', 'diamond', a=5.43) k = 2 if 1: si.calc = GPAW(kpts=(k, k, k), mode='lcao', txt='Si-ibz.txt') #si.calc = GPAW(kpts=(k, k, k), mode='lcao') e1 = si.get_potential_energy() si.calc.write('Si-ibz', mode='all') #si.calc.set(symmetry='off', txt='Si-bz.txt') #si.calc.set(symmetry='off') #e2 = si.get_potential_energy() #si.calc.write('Si-bz', mode='all') #print e1, e2 def wan(calc): centers = [([0.125, 0.125, 0.125], 0, 1.5), ([0.125, 0.625, 0.125], 0, 1.5), ([0.125, 0.125, 0.625], 0, 1.5), ([0.625, 0.125, 0.125], 0, 1.5)] w = Wannier(4, calc, nbands=4, verbose=False, initialwannier=centers) w.localize() x = w.get_functional_value() centers = (w.get_centers(1) * k) % 1 c = (centers - 0.125) * 2 #print w.get_radii() # broken! XXX assert abs(c.round() - c).max() < 0.03 c = sorted(c.round().astype(int).tolist()) assert c == [[0, 0, 0], [0, 0, 1], [0, 1, 0], [1, 0, 0]] if 0: from ase.visualize import view from ase import Atoms watoms = calc.atoms + Atoms(symbols='X4', scaled_positions=centers, cell=calc.atoms.cell) view(watoms) return x calc1 = GPAW('Si-bz.gpw', txt=None, communicator=serial_comm) # do full lcao initialization #print('Re-Init LCAO calc') _s = calc1.get_atoms() calc1.set_positions(_s) calc1.wfs.eigensolver.iterate(calc1.hamiltonian, calc1.wfs) x1 = wan(calc1) #print x1 x2 = 5.76962685681 # from FD mode assert abs(x1 - x2) < 0.001 #assert abs(x1 - 9.71) < 0.01 world.barrier() gpaw-0.11.0.13004/gpaw/test/diamond_eps.py0000664000175000017500000000362212553643471020231 0ustar jensjjensj00000000000000import numpy as np import sys import time from ase.units import Bohr from ase.lattice import bulk from ase.utils import devnull from gpaw import GPAW, FermiDirac from gpaw.atom.basis import BasisMaker from gpaw.response.df0 import DF from gpaw.mpi import serial_comm, rank, size if rank != 0: sys.stdout = devnull # GS Calculation One a = 6.75 * Bohr atoms = bulk('C', 'diamond', a=a) nbands = 8 calc = GPAW(h=0.2, kpts=(2,2,2), nbands = nbands+5, eigensolver='cg', occupations=FermiDirac(0.001), convergence={'bands':nbands}) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('C2.gpw','all') # Macroscopic dielectric constant calculation q = np.array([0.0, 0.00001, 0.]) w = np.linspace(0,15,150) df = DF(calc='C2.gpw', q=q, w=(0.,), eta=0.001, nbands=nbands, ecut=50, hilbert_trans=False, optical_limit=True) eM1, eM2 = df.get_macroscopic_dielectric_constant(xc='ALDA') if np.abs(eM2 - 7.914302) > 1e-3: raise ValueError("Incorrect value for Diamond dielectric constant with ALDA Kernel %.4f" % (eM2)) # Dielectric function df = DF(calc='C2.gpw', q=q, w=w, eta=0.40, nbands=nbands, xc='Bootstrap', ecut=100, hilbert_trans=False, optical_limit=True) df.get_absorption_spectrum(filename='C2.dat') spect = np.loadtxt('C2.dat.y') eps2_max = spect[0][spect[6].argmax()] if np.abs(eps2_max - 8.92972)>1e-3: raise ValueError("Incorrect position for Diamond dielectric function peak with Bootstrap Kernel %.4f" % (eps2_max)) # RPA: # With kpts=(12,12,12) and bands=64, ecut=250eV, this script gives 5.56 # Value from PRB 73, 045112 with kpts=(12,12,12) and bands=64: 5.55 # ALDA: # With kpts=(12,12,12) and bands=64, ecut=250eV, this script gives 5.82 # Value from PRB 73, 045112 with kpts=(12,12,12) and bands=64: 5.82 gpaw-0.11.0.13004/gpaw/test/erf.py0000664000175000017500000000174112553643471016523 0ustar jensjjensj00000000000000from __future__ import print_function from gpaw.utilities import erf, cerf # Mathematica says: # z erf(z) # 1 0.842701 # 3 0.999978 # I 0. + 1.65043 I # 1 + I 1.31615 + 0.190453 I # 0.3 + 3*I 1467.69 - 166.561 I # 3 - 0.3*I 1.00001 - 0.0000228553 I values = [ [ 1, 0.84270079295+0j], [ 3, 0.999977909503+0j], [ 1j, 1.6504257588j], [ 1+1j, 1.3161512816979477+0.19045346923783471j ], [ 0.3 + 3j, 1467.69028322-166.560924526j ], [ 3 + 0.3j, 0.99997602085736015+2.1863701577230078e-06j]] maxerror = 1.e-10 for test in values: z, res = test try: r = z.real except: r = z error = abs(res / cerf(z) - 1.) if error < maxerror: print('z=', z, ' ok (error=', error, ')') else: print(z, res, cerf(z), erf(r), error) string = ('error for erf(' + str(z) +') = ' + str(error) + ' > ' + str(maxerror)) assert(error < maxerror), string gpaw-0.11.0.13004/gpaw/test/broydenmixer.py0000664000175000017500000000077612553643471020465 0ustar jensjjensj00000000000000from ase import Atom, Atoms from gpaw import GPAW from gpaw.mixer import BroydenMixer from gpaw.test import equal a = 2.7 bulk = Atoms([Atom('Li')], pbc=True, cell=(a, a, a)) k = 2 g = 16 calc = GPAW(gpts=(g, g, g), kpts=(k, k, k), nbands=2, mixer=BroydenMixer()) bulk.set_calculator(calc) e = bulk.get_potential_energy() niter = calc.get_number_of_iterations() calc.write('Li.gpw') calc2 = GPAW('Li.gpw') energy_tolerance = 0.00005 niter_tolerance = 0 equal(e, -1.20258, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/lrtddft.py0000664000175000017500000001063412553643471017413 0ustar jensjjensj00000000000000import os from ase import Atom, Atoms from ase.units import Bohr from ase.parallel import parprint from gpaw import GPAW from gpaw.test import equal from gpaw.lrtddft import LrTDDFT from gpaw.mpi import world from gpaw.lrtddft.excited_state import ExcitedState txt='-' txt='/dev/null' io_only=False #io_only=True load=False #load=True if not io_only: R=0.7 # approx. experimental bond length a = 3.0 c = 4.0 H2 = Atoms([Atom('H', (a / 2, a / 2, (c - R) / 2)), Atom('H', (a / 2, a / 2, (c + R) / 2))], cell=(a, a, c)) calc = GPAW(xc='PBE', nbands=3, spinpol=False, txt=txt) H2.set_calculator(calc) H2.get_potential_energy() xc='LDA' # without spin lr = LrTDDFT(calc, xc=xc) lr.diagonalize() t1 = lr[0] lr_calc = lr ex = ExcitedState(lr, 0) den = ex.get_pseudo_density() * Bohr**3 # velocity from for ozr, ozv in zip(t1.get_oscillator_strength(), t1.get_oscillator_strength('v')): equal(ozr, ozv, 0.1) # course grids for finegrid in [1,0]: lr = LrTDDFT(calc, xc=xc, finegrid=finegrid) lr.diagonalize() t3 = lr[0] parprint('finegrid, t1, t3=', finegrid, t1 ,t3) equal(t1.get_energy(), t3.get_energy(), 5.e-4) # with spin lr_vspin = LrTDDFT(calc, xc=xc, nspins=2) singlet, triplet = lr_vspin.singlets_triplets() lr_vspin.diagonalize() # the triplet is lower, so that the second is the first singlet # excited state t2 = lr_vspin[1] ex_vspin = ExcitedState(lr_vspin, 1) den_vspin = ex_vspin.get_pseudo_density() * Bohr**3 parprint('with virtual/wo spin t2, t1=', t2.get_energy(), t1 .get_energy()) equal(t1.get_energy(), t2.get_energy(), 5.e-7) gd = lr.calculator.density.gd finegd = lr.calculator.density.finegd ddiff = gd.integrate(abs(den - den_vspin)) parprint(' density integral, difference=', gd.integrate(den), gd.integrate(den_vspin), ddiff) parprint(' aed density integral', finegd.integrate(ex.get_all_electron_density() * Bohr**3), finegd.integrate(ex_vspin.get_all_electron_density() * Bohr**3)) assert(ddiff < 1.e-4) if not load: c_spin = GPAW(xc='PBE', nbands=2, spinpol=True, parallel={'domain': world.size}, txt=txt) H2.set_calculator(c_spin) c_spin.calculate(H2) ## c_spin.write('H2spin.gpw', 'all') else: c_spin = GPAW('H2spin.gpw', txt=txt) lr_spin = LrTDDFT(c_spin, xc=xc) lr_spin.diagonalize() for i in range(2): parprint('i, real, virtual spin: ', i, lr_vspin[i], lr_spin[i]) equal(lr_vspin[i].get_energy(), lr_spin[i].get_energy(), 6.e-6) ex_vspin = ExcitedState(lr_vspin, i) den_vspin = ex_vspin.get_pseudo_density() * Bohr**3 ex_spin = ExcitedState(lr_spin, i) den_spin = ex_spin.get_pseudo_density() * Bohr**3 ddiff = gd.integrate(abs(den_vspin - den_spin)) parprint(' density integral, difference=', gd.integrate(den_vspin), gd.integrate(den_spin), ddiff) parprint(' aed density integral', finegd.integrate(ex_vspin.get_all_electron_density() * Bohr**3), finegd.integrate(ex_spin.get_all_electron_density() * Bohr**3)) assert(ddiff < 3.e-3), ddiff # singlet/triplet separation precision = 1.e-5 singlet.diagonalize() equal(singlet[0].get_energy(), lr_spin[1].get_energy(), precision) equal(singlet[0].get_oscillator_strength()[0], lr_spin[1].get_oscillator_strength()[0], precision) triplet.diagonalize() equal(triplet[0].get_oscillator_strength()[0], 0) equal(triplet[0].get_energy(), lr_spin[0].get_energy(), precision) equal(triplet[0].get_oscillator_strength()[0], 0) # io fname = 'lr.dat.gz' if not io_only: lr.write(fname) world.barrier() lr = LrTDDFT(fname) lr.diagonalize() t4 = lr[0] if not io_only: equal(t3.get_energy(), t4.get_energy(), 1e-6) e4 = t4.get_energy() equal(e4, 0.675814, 2e-4) # excited state with forces accuracy = 0.3 exst = ExcitedState(lr_calc, 0) forces = exst.get_forces(H2) parprint('forces=', forces) for c in range(2): equal(forces[0,c], 0.0, accuracy) equal(forces[1,c], 0.0, accuracy) equal(forces[0, 2] + forces[1, 2], 0.0, accuracy) gpaw-0.11.0.13004/gpaw/test/ase3k.py0000664000175000017500000000077712553643471016765 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atom, Atoms from ase.io import read from gpaw import GPAW, FermiDirac from gpaw.test import equal a = 2.0 calc = GPAW(gpts=(12, 12, 12), txt='H.txt', occupations=FermiDirac(0.0)) H = Atoms('H', cell=(a, a, a), pbc=True, calculator=calc) e0 = H.get_potential_energy() H = read('H.txt') equal(H.get_potential_energy(), e0, 1e-6) energy_tolerance = 0.00007 equal(e0, -6.55685, energy_tolerance) print(calc.get_xc_functional()) gpaw-0.11.0.13004/gpaw/test/fixocc.py0000664000175000017500000000271112553643471017220 0ustar jensjjensj00000000000000from __future__ import print_function from ase.structure import molecule from ase.parallel import parprint from gpaw import GPAW from gpaw.cluster import Cluster from gpaw.occupations import FixedOccupations, ZeroKelvin from gpaw.test import equal h = 0.4 box = 2 nbands = 2 txt = '-' txt = None H2 = Cluster(molecule('H2')) H2.minimal_box(box, h) convergence = {'energy':0.01, 'eigenstates':1.e-3, 'density':1.e-2} if 1: # test ZeroKelvin vs FixedOccupations c = GPAW(h=h, nbands=nbands, occupations=ZeroKelvin(True), convergence=convergence, txt=txt) H2.set_calculator(c) E_zk = H2.get_potential_energy() c = GPAW(h=h, nbands=nbands, occupations=FixedOccupations([[2, 0]]), convergence=convergence, txt=txt) H2.set_calculator(c) E_fo = H2.get_potential_energy() parprint(E_zk, E_fo) equal(E_zk, E_fo, 1.e-10) if 1: # test spin-paired vs spin-polarized c = GPAW(h=h, nbands=nbands, occupations=FixedOccupations([[1,1]]), convergence=convergence, txt=txt) H2.set_calculator(c) E_ns = H2.get_potential_energy() if 1: c = GPAW(h=h, nbands=nbands, spinpol=True, occupations=FixedOccupations([[0.5, 0.5]] * 2), convergence=convergence, txt=txt) H2.set_calculator(c) E_sp = H2.get_potential_energy() parprint(E_ns, E_sp) equal(E_ns, E_sp, 1.e-6) gpaw-0.11.0.13004/gpaw/test/8Si.py0000664000175000017500000000272412553643471016414 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atoms from ase.calculators.test import numeric_force from gpaw import GPAW, FermiDirac, PoissonSolver from gpaw.test import equal from gpaw.xc.tools import vxc a = 5.404 bulk = Atoms(symbols='Si8', positions=[(0, 0, 0.1 / a), (0, 0.5, 0.5), (0.5, 0, 0.5), (0.5, 0.5, 0), (0.25, 0.25, 0.25), (0.25, 0.75, 0.75), (0.75, 0.25, 0.75), (0.75, 0.75, 0.25)], pbc=True) bulk.set_cell((a, a, a), scale_atoms=True) n = 20 calc = GPAW(gpts=(n, n, n), nbands='150%', occupations=FermiDirac(width=0.01), poissonsolver=PoissonSolver(nn='M', relax='J'), kpts=(2, 2, 2), convergence={'energy': 1e-7} ) bulk.set_calculator(calc) f1 = bulk.get_forces()[0, 2] e1 = bulk.get_potential_energy() v_xc = vxc(calc) print(v_xc) niter1 = calc.get_number_of_iterations() f2 = numeric_force(bulk, 0, 2) print((f1, f2, f1 - f2)) equal(f1, f2, 0.005) # Volume per atom: vol = a**3 / 8 de = calc.get_electrostatic_corrections() / vol print(de) assert abs(de[0] - -2.190) < 0.001 print((e1, f1, niter1)) energy_tolerance = 0.00025 force_tolerance = 0.0001 niter_tolerance = 0 equal(e1, -46.6596470348, energy_tolerance) # svnversion 5252 equal(f1, -1.38242356123, force_tolerance) # svnversion 5252 gpaw-0.11.0.13004/gpaw/test/ehrenfest_nacl.py0000664000175000017500000000161112553643471020723 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atoms from gpaw import GPAW from gpaw.tddft import TDDFT from gpaw.tddft.ehrenfest import EhrenfestVelocityVerlet from gpaw.test import equal d = 4.0 atoms = Atoms('NaCl', [(0,0,0),(0,0,d)]) atoms.center(vacuum=4.5) gs_calc = GPAW(nbands=4, eigensolver='cg', gpts=(32, 32, 44), xc='LDA', setups={'Na': '1'}) atoms.set_calculator(gs_calc) atoms.get_potential_energy() gs_calc.write('nacl_gs.gpw', 'all') td_calc = TDDFT('nacl_gs.gpw', propagator='EFSICN') evv = EhrenfestVelocityVerlet(td_calc, 0.001) i=0 evv.get_energy() r = evv.x[1][2] - evv.x[0][2] # print 'E = ', [i, r, evv.Etot, evv.Ekin, evv.Epot] for i in range(5): evv.propagate(1.0) evv.get_energy() r = evv.x[1][2] - evv.x[0][2] print('E = ', [i+1, r, evv.Etot, evv.Ekin, evv.Epot]) equal(r, 7.558883144, 1e-7) equal(evv.Etot, -0.1036763317, 1e-7) gpaw-0.11.0.13004/gpaw/test/ylexpand.py0000664000175000017500000000375412553643472017602 0ustar jensjjensj00000000000000from math import pi import os from ase import Atom, Atoms from ase.units import Bohr from ase.parallel import parprint from gpaw import GPAW from gpaw.test import equal from gpaw.grid_descriptor import GridDescriptor from gpaw.analyse.expandyl import AngularIntegral, ExpandYl import gpaw.mpi as mpi fname = 'H2.gpw' donot = '' donot = 'donot' try: calc = GPAW(fname + donot, txt=None) H2 = calc.get_atoms() calc.converge_wave_functions() except: R=0.7 # approx. experimental bond length a = 2. c = 3. H2 = Atoms([Atom('H', (a/2, a/2, (c-R)/2)), Atom('H', (a/2, a/2, (c+R)/2))], cell=(a,a,c), pbc=True) calc = GPAW(gpts=(12, 12, 16), nbands=2, kpts=(1,1,2), convergence={'eigenstates':1.e-6}, txt=None, ) H2.set_calculator(calc) H2.get_potential_energy() if not donot: calc.write(fname) # Check that a / h = 10 is rounded up to 12 as always: assert (calc.wfs.gd.N_c == (12, 12, 16)).all() ############ AngularIntegral gd = calc.density.gd ai = AngularIntegral(H2.positions.mean(0), calc.wfs.gd, Rmax=1.5) unity_g = gd.zeros() + 1. average_R = ai.average(unity_g) integral_R = ai.integrate(unity_g) for V, average, integral, R, Rm in zip(ai.V_R, average_R, integral_R, ai.radii(), ai.radii('mean')): if V > 0: equal(average, 1, 1.e-9) equal(integral / (4 * pi * Rm**2), 1, 0.61) equal(Rm / R, 1, 0.61) ############ ExpandYl yl = ExpandYl(H2.positions.mean(0), calc.wfs.gd, Rmax=1.5) def max_index(l): mi = 0 limax = l[0] for i, li in enumerate(l): if limax < li: limax = li mi = i return mi # check numbers for n in [0,1]: #gl, w = yl.expand(calc.get_pseudo_wave_function(band=n)) gl, w = yl.expand(calc.wfs.kpt_u[0].psit_nG[n]) parprint('max_index(gl), n=', max_index(gl), n) assert(max_index(gl) == n) # io fname = 'expandyl.dat' yl.to_file(calc, fname) gpaw-0.11.0.13004/gpaw/test/expert_diag.py0000664000175000017500000000455712553643471020252 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from ase.lattice import bulk from gpaw import GPAW, PW from gpaw.test import equal from gpaw.mpi import rank # This test is asserting that the expert diagonalization # routine gives the same result as the non-expert version # in terms of eigenvalues and wavefunctions wfs_e = [] for i, expert in enumerate([True, False]): si = bulk('Si') name = 'si_{0:d}'.format(i) si.center() calc = GPAW(mode=PW(400), kpts=(1, 1, 8), symmetry='off', txt=name + '.txt') si.set_calculator(calc) si.get_potential_energy() calc.diagonalize_full_hamiltonian(expert=expert, nbands=50) string = name + '.gpw' calc.write(string, 'all') wfs_e.append(calc.wfs) # Test against values from rev #12394 wfsold_G = np.array([-7.03242443e+01 - 4.00102028e-13j, -1.37801953e+02 - 9.82133133e-14j, 9.63846708e+00 - 1.45030653e-14j, 6.22404541e-01 + 8.10551006e-15j, 1.09715123e-02 - 8.54339549e-15j]) epsn_n = np.array([-0.15883479, -0.04404914, 0.16348702, 0.16348703, 0.25032194]) kpt_u = wfs_e[0].kpt_u for kpt in kpt_u: if kpt.k == 0: assert np.allclose(epsn_n, kpt.eps_n[0:5], 1e-5), \ 'Eigenvalues have changed since rev. #12394' assert np.allclose(wfsold_G, kpt.psit_nG[1, 0:5], 1e-5), \ 'Wavefunctions have changed rev. #12394' # Check that expert={True, False} give # same result while len(wfs_e) > 1: wfs = wfs_e.pop() for wfstmp in wfs_e: for kpt, kpttmp in zip(wfs.kpt_u, wfstmp.kpt_u): for m, (psi_G, eps) in enumerate(zip(kpt.psit_nG, kpt.eps_n)): # Have to do like this if bands are degenerate booleanarray = np.abs(kpttmp.eps_n - eps) < 1e-10 inds = np.argwhere(booleanarray) count = len(inds) assert count > 0, 'Difference between eigenvalues!' psitmp_nG = kpttmp.psit_nG[inds][:, 0, :] fidelity = 0 for psitmp_G in psitmp_nG: fidelity += (np.abs(np.dot(psitmp_G.conj(), psi_G))**2 / np.dot(psitmp_G.conj(), psitmp_G) / np.dot(psi_G.conj(), psi_G)) equal(fidelity, 1, 1e-10, 'Difference between wfs!') gpaw-0.11.0.13004/gpaw/test/bse_sym.py0000664000175000017500000000375512553643472017420 0ustar jensjjensj00000000000000from __future__ import print_function import os import numpy as np from ase.lattice import bulk from gpaw import GPAW from gpaw.response.df0 import DF from ase.dft.kpoints import monkhorst_pack from gpaw.response.bse import BSE from gpaw.mpi import rank, size # generate kmesh kpts =(2,2,2) bzk_kc = monkhorst_pack(kpts) shift_c = [] for Nk in kpts: if Nk % 2 == 0: shift_c.append(0.5 / Nk) else: shift_c.append(0.) atoms = bulk('Si', 'diamond', a=5.431) kpts1 = bzk_kc # not Gamma centered kpts2 = bzk_kc + shift_c # Gamma centered for kpts in (kpts2,): calc = GPAW(h=0.20, kpts=kpts) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('Si.gpw','all') # no symmetry BSE eshift = 0.8 bse = BSE('Si.gpw', w=np.linspace(0,10,201), q=np.array([0.0001, 0, 0.0]), optical_limit=True, ecut=150., nc=np.array([4,6]), nv=np.array([2,4]), eshift=eshift, nbands=8, qsymm=False) bse.get_dielectric_function('bse_nosymm.dat') if rank == 0 and os.path.isfile('phi_qaGp'): os.remove('phi_qaGp') # with symmetry BSE eshift = 0.8 bse = BSE('Si.gpw', w=np.linspace(0,10,201), q=np.array([0.0001,0,0.0]), optical_limit=True, ecut=150., nc=np.array([4,6]), nv=np.array([2,4]), eshift=eshift, nbands=8, qsymm=True) bse.get_dielectric_function('bse_symm.dat') if rank == 0 and os.path.isfile('phi_qaGp'): os.remove('phi_qaGp') check = 1 if check: d1 = np.loadtxt('bse_nosymm.dat') d2 = np.loadtxt('bse_symm.dat') print(np.abs(d1[:,2] - d2[:,2]).max(), np.abs(d1[:,2] - d2[:,2]).sum()) assert np.abs(np.abs(d1[:,2] - d2[:,2]).max() - 0.014775742) < 1e-2 assert np.abs(np.abs(d1[:,2] - d2[:,2]).sum() - 0.210880672212) < 1e-1 gpaw-0.11.0.13004/gpaw/test/dscf_forces.py0000664000175000017500000000504412553643471020227 0ustar jensjjensj00000000000000from __future__ import print_function import sys import numpy as np from ase import Atom, Atoms from gpaw import GPAW, MixerSum, dscf from gpaw.mpi import rank L = 10.0 eigensolver = 'cg' xc = 'PBE' E0 = [] E1 = [] d0 = 1.4 delta = 0.05 for i in range(3): d = d0 + (i - 1) * delta atoms = Atoms([Atom('N',[0.5*L, 0.5*L, 0.5*L - 0.5*d]), Atom('N',[0.5*L, 0.5*L, 0.5*L + 0.5*d])]) atoms.set_cell([L,L,L]) calc_gs = GPAW(h = 0.2, nbands = -5, xc = xc, width = 0.05, eigensolver = eigensolver, spinpol = True, txt = None, mixer = MixerSum(beta=0.1, nmaxold=5, weight=50.0), convergence = {'energy': 100, 'density': 100, 'eigenstates': 1.0e-9, 'bands': -1}) atoms.set_calculator(calc_gs) E0.append(atoms.get_potential_energy()) if i==1: F0 = atoms.get_forces() calc_es = GPAW(h = 0.2, nbands = -5, xc = xc, width = 0.05, eigensolver = eigensolver, spinpol = True, txt = None, mixer = MixerSum(beta=0.1, nmaxold=5, weight=50.0), convergence = {'energy': 100, 'density': 100, 'eigenstates': 1.0e-9, 'bands': -1}) n = 5 # LUMO molecule = [0, 1] wf_u = [kpt.psit_nG[n] for kpt in calc_gs.wfs.kpt_u] p_uai = [dict([(molecule[a], P_ni[n]) for a, P_ni in kpt.P_ani.items()]) for kpt in calc_gs.wfs.kpt_u] atoms.set_calculator(calc_es) lumo = dscf.AEOrbital(calc_es, wf_u, p_uai) dscf.dscf_calculation(calc_es, [[1.0, lumo, 1]], atoms) E1.append(atoms.get_potential_energy()) if i==1: F1 = atoms.get_forces() f0 = np.sqrt(((F0[1,:] - F0[0,:])**2).sum()) * 0.5 f0b = (E0[1] - E0[0]) / delta # backward gradient f0f = (E0[2] - E0[1]) / delta # forward gradient if rank == 0: print('Ground state') print(E0) print(f0b, '<', f0, '<', f0f) assert f0 > f0b assert f0 < f0f f1 = np.sqrt(((F1[1,:] - F1[0,:])**2).sum()) * 0.5 f1b = (E1[1] - E1[0]) / delta # backward gradient f1f = (E1[2] - E1[1]) / delta # forward gradient if rank == 0: print('Excited state') print(E1) print(f1b, '<', f1, '<', f1f) assert f1 > f1b assert f1 < f1f gpaw-0.11.0.13004/gpaw/test/mgga_sc.py0000664000175000017500000000155112553643472017347 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atom from gpaw import GPAW from gpaw.cluster import Cluster from gpaw.test import equal h=0.40 txt = None txt = 'mgga_sc.txt' s = Cluster([Atom('H')]) s.minimal_box(4., h=h) s.set_initial_magnetic_moments([1]) # see https://trac.fysik.dtu.dk/projects/gpaw/ticket/244 s.set_cell((8.400000,8.400000,8.400000)) c = GPAW(xc='TPSS', h=h, nbands=5, txt=txt, eigensolver='rmm-diis', fixmom=True, maxiter=300) c.calculate(s) cpbe = GPAW(xc='PBE', h=h, nbands=5, txt=txt, eigensolver='rmm-diis', fixmom=True, maxiter=300) cpbe.calculate(s) cpbe.set(xc='TPSS') cpbe.calculate() print("Energy difference", (cpbe.get_potential_energy() - c.get_potential_energy())) equal(cpbe.get_potential_energy(), c.get_potential_energy(), 0.002) gpaw-0.11.0.13004/gpaw/test/gllbspin.py0000664000175000017500000000201712553643472017557 0ustar jensjjensj00000000000000from __future__ import print_function from gpaw import GPAW, FermiDirac from gpaw.test import equal from ase.lattice import bulk for spin in [False, True]: a = 3.56 atoms = bulk('C', 'diamond', a=a) calc = GPAW(kpts=(3,3,3), xc='GLLBSC', spinpol = spin, nbands=8, convergence={'bands':6,'density':1e-6}, occupations=FermiDirac(width=0.005)) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('temp.gpw') response = calc.hamiltonian.xc.xcs['RESPONSE'] response.calculate_delta_xc() #Eks is the Kohn-Sham gap and Dxc is the derivative discontinuity if spin: (Eksa, Dxca), (Eksb, Dxcb) = response.calculate_delta_xc_perturbation() Gapa = Eksa+Dxca Gapb = Eksb+Dxcb print("GAP", spin, Gapa, Gapb) else: Eks, Dxc = response.calculate_delta_xc_perturbation() Gap = Eks + Dxc print("GAP", spin, Gap) equal(Gapa, Gapb, 1e-4) equal(Gapa, Gap, 1e-4) gpaw-0.11.0.13004/gpaw/test/band_symmetries.py0000664000175000017500000001065312553643472021137 0ustar jensjjensj00000000000000from __future__ import print_function from ase.lattice import bulk from gpaw import GPAW from gpaw import restart from _gpaw import symmetrize import numpy as np from gpaw.symmetry import Symmetry from gpaw.utilities.tools import md5_array from gpaw.test import equal import os # Normal ground state calculation atoms = bulk('Si') calc = GPAW(h=0.24, kpts=(4,4,4), convergence={'eigenstates' : 1e-4, 'density' : 1e-3}, ) atoms.set_calculator(calc) atoms.get_potential_energy() # "Bandstructure" calculation (only Gamma point here) kpts = np.array(((0, 0, 0),)) calc.set(fixdensity=True, kpts=kpts) atoms.get_potential_energy() calc.write('Si_gamma.gpw', mode='all') # Analyse symmetries of wave functions atoms, calc = restart('Si_gamma.gpw', txt=None) # Find symmetries (in Gamma-point calculations calculator does not # use symmetry) sym = Symmetry(calc.wfs.setups.id_a, atoms.cell, atoms.pbc) sym.analyze(atoms.get_scaled_positions()) def find_classes(op_all_scc): # Find classes of group represented by matrices op_all_scc # and return representative operations op_scc = [op_all_scc[0]] for op1 in op_all_scc[1:]: new_class = True for op2 in op_all_scc: op_tmp = (np.dot(np.dot(op2, op1), np.linalg.inv(op2).astype(int))) # Check whether operation op1 belongs to existing class for op in op_scc: if np.all((op_tmp - op) == 0): new_class = False break if not new_class: break if new_class: op_scc.append(op1) return op_scc op_scc = find_classes(sym.op_scc) nops = len(op_scc) nbands = calc.wfs.bd.nbands characters = np.zeros((nbands, nops)) degeneracy_threshold = 1e-2 # Threshold for considering bands degenerate symdone = np.zeros(nbands, bool) eig_n = calc.get_eigenvalues() for n in range(nbands): # For degenerate states analysis might be already done if symdone[n]: continue # Find degenerate bands ndeg = 0 m = n while abs(eig_n[m] - eig_n[n]) < degeneracy_threshold: ndeg += 1 m += 1 if m == nbands: break # Representation matrix representation_nn = np.zeros((ndeg, ndeg, nops)) for nop, op_cc in enumerate(op_scc): # Bands from n to m are (possibly) degenerate for n1 in range(n, m): for n2 in range(n, m): wf1 = calc.get_pseudo_wave_function(band=n1) wf2 = calc.get_pseudo_wave_function(band=n2) norm1 = np.sqrt(calc.wfs.gd.integrate(wf1, wf1)) norm2 = np.sqrt(calc.wfs.gd.integrate(wf2, wf2).real) wf_rot = np.zeros_like(wf2) symmetrize(wf2, wf_rot, op_cc) # Indices of representation matrix are from 0 to ndeg i1, i2 = n1 - n, n2 - n representation_nn[i1, i2, nop] = calc.wfs.gd.integrate(wf1, wf_rot) representation_nn[i1, i2, nop] /= norm1 * norm2 # Calculate traces of irreducible representations # If bands i1 and i2 are accidentally degenerate (i.e. not due to symmetry) # they belong to different irreducible representations and the # corresponding representation matrix elements are zero for all # symmetry operations. for i1 in range(ndeg): for i2 in range(ndeg): if np.any(abs(representation_nn[i1, i2, :]) > 0.01): characters[n + i1, :] += representation_nn[i2, i2, :] symdone[n + i1] = True # Use four decimals for characters characters = np.round(characters, 4) # Use characters as fingerprints fingerprints = np.array([md5_array(row) for row in characters]) fmt = "%6.4f " * nops for i in range(nbands): print(fmt % tuple([c for c in characters[i, :nops]])) # Correct?!? character table characters_reference = np.array(((1.0, 1.0, 1.0, 1.0, 1.0), (3.0, 1.0, 0.0, -1.0, -1.0), (3.0, 1.0, 0.0, -1.0, -1.0), (3.0, 1.0, 0.0, -1.0, -1.0), (3.0, 1.0, 0.0, -1.0, -1.0), (3.0, 1.0, 0.0, -1.0, -1.0), (3.0, 1.0, 0.0, -1.0, -1.0), (1.0, 1.0, 1.0, 1.0, 1.0))) assert np.all(np.abs(characters_reference-characters) < 1.0e-4) os.remove('Si_gamma.gpw') gpaw-0.11.0.13004/gpaw/test/derivatives.py0000664000175000017500000000305212553643471020271 0ustar jensjjensj00000000000000import numpy as np from gpaw.lfc import LocalizedFunctionsCollection as LFC from gpaw.grid_descriptor import GridDescriptor from gpaw.spline import Spline a = 4.0 gd = GridDescriptor(N_c=[16, 20, 20], cell_cv=[a, a + 1, a + 2], pbc_c=(0, 1, 1)) spos_ac = np.array([[0.25, 0.15, 0.35], [0.5, 0.5, 0.5]]) kpts_kc = None s = Spline(l=0, rmax=2.0, f_g=np.array([1, 0.9, 0.1, 0.0])) p = Spline(l=1, rmax=2.0, f_g=np.array([1, 0.9, 0.1, 0.0])) spline_aj = [[s], [s, p]] c = LFC(gd, spline_aj, cut=True, forces=True) c.set_positions(spos_ac) C_ani = c.dict(3, zero=True) if 1 in C_ani: C_ani[1][:, 1:] = np.eye(3) psi = gd.zeros(3) c.add(psi, C_ani) c.integrate(psi, C_ani) if 1 in C_ani: d = C_ani[1][:, 1:].diagonal() assert d.ptp() < 4e-6 C_ani[1][:, 1:] -= np.diag(d) assert abs(C_ani[1]).max() < 5e-17 d_aniv = c.dict(3, derivative=True) c.derivative(psi, d_aniv) if 1 in d_aniv: for v in range(3): assert abs(d_aniv[1][v - 1, 0, v] + 0.2144) < 5e-5 d_aniv[1][v - 1, 0, v] = 0 assert abs(d_aniv[1]).max() < 3e-16 eps = 0.0001 pos_av = np.dot(spos_ac, gd.cell_cv) for v in range(3): pos_av[0, v] += eps c.set_positions(np.dot(pos_av, gd.icell_cv.T)) c.integrate(psi, C_ani) if 0 in d_aniv: C0_n = C_ani[0][:, 0].copy() pos_av[0, v] -= 2 * eps c.set_positions(np.dot(pos_av, gd.icell_cv.T)) c.integrate(psi, C_ani) if 0 in d_aniv: C0_n -= C_ani[0][:, 0] C0_n /= -2 * eps assert abs(C0_n - d_aniv[0][:, 0, v]).max() < 1e-8 pos_av[0, v] += eps gpaw-0.11.0.13004/gpaw/test/td_na2.py0000664000175000017500000000506012553643471017114 0ustar jensjjensj00000000000000from ase import Atoms from ase.units import Bohr from gpaw import GPAW from gpaw.tddft import TDDFT, photoabsorption_spectrum from gpaw.tddft.abc import LinearAbsorbingBoundary, P4AbsorbingBoundary, PML from gpaw.test import equal import os # Sodium dimer, Na2 d = 1.5 atoms = Atoms(symbols='Na2', positions=[( 0, 0, d), ( 0, 0,-d)], pbc=False) # Calculate ground state for TDDFT # Larger box atoms.center(vacuum=6.0) # Larger grid spacing, LDA is ok gs_calc = GPAW(nbands=1, h=0.35, xc='LDA', setups={'Na': '1'}) atoms.set_calculator(gs_calc) e = atoms.get_potential_energy() niter = gs_calc.get_number_of_iterations() gs_calc.write('na2_gs.gpw', 'all') # 16 fs run with 8.0 attosec time step time_step = 8.0 # 8.0 as (1 as = 0.041341 autime)5D iters = 10 # 2000 x 8 as => 16 fs # Weak delta kick to z-direction kick = [0,0,1e-3] # TDDFT calculator td_calc = TDDFT('na2_gs.gpw') # Kick td_calc.absorption_kick(kick) # Propagate td_calc.propagate(time_step, iters, 'na2_dmz.dat', 'na2_td.gpw') # Linear absorption spectrum photoabsorption_spectrum('na2_dmz.dat', 'na2_spectrum_z.dat', width=0.3) iters = 3 # test restart td_rest = TDDFT('na2_td.gpw') td_rest.propagate(time_step, iters, 'na2_dmz2.dat', 'na2_td2.gpw') # test restart td_rest = TDDFT('na2_td.gpw', solver='BiCGStab') td_rest.propagate(time_step, iters, 'na2_dmz3.dat', 'na2_td3.gpw') # test absorbing boundary conditions # linear imaginary potential td_ipabs = TDDFT('na2_td.gpw') ip_abc = LinearAbsorbingBoundary(5.0, 0.01, atoms.positions) td_ipabs.set_absorbing_boundary(ip_abc) td_ipabs.propagate(time_step, iters, 'na2_dmz4.dat', 'na2_td4.gpw') # 4th order polynomial (1-(x^2-1)^2) imaginary potential td_ip4abs = TDDFT('na2_td.gpw') ip4_abc = P4AbsorbingBoundary(5.0, 0.03, atoms.positions, 3.0) td_ip4abs.set_absorbing_boundary(ip4_abc) td_ip4abs.propagate(time_step, iters, 'na2_dmz5.dat', 'na2_td5.gpw') # perfectly matched layers td_pmlabs = TDDFT('na2_td.gpw', solver='BiCGStab') pml_abc = PML(100.0, 0.1) td_pmlabs.set_absorbing_boundary(pml_abc) td_pmlabs.propagate(time_step, iters, 'na2_dmz6.dat', 'na2_td6.gpw') # photoabsorption_spectrum('na2_dmz2.dat', 'na2_spectrum_z2.dat', width=0.3) #os.remove('na2_gs.gpw') #os.remove('na2_td.gpw') #os.remove('na2_dmz.dat') #os.remove('na2_spectrum_z.dat') #os.remove('na2_td2.gpw') #os.remove('na2_dmz2.dat') # os.remove('na2_spectrum_z2.dat') #energy_tolerance = 0.0001 #niter_tolerance = 0 #equal(e, -1.24941356939, energy_tolerance) # svnversion 5252 #equal(niter, 21, niter_tolerance) # svnversion 5252 gpaw-0.11.0.13004/gpaw/test/chi0.py0000664000175000017500000000723612553643472016600 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from ase.lattice import bulk from ase.dft.kpoints import monkhorst_pack from ase.units import Bohr from gpaw import GPAW from gpaw.response.chi import CHI from gpaw.response.chi0 import Chi0 from gpaw.mpi import serial_comm omega = np.array([0, 1.0, 2.0]) for k in [2, 3]: q_c = [0, 0, 1.0 / k] for gamma in [False, True]: if k == 3 and gamma: continue kpts = monkhorst_pack((k, k, k)) if gamma: kpts += 0.5 / k for center in [False, True]: a = bulk('Si', 'diamond') if center: a.center() for sym in [False, True]: name = 'si.k%d.g%d.c%d.s%d' % (k, gamma, center, bool(sym)) print(name) if 1: calc = a.calc = GPAW( kpts=kpts, eigensolver='rmm-diis', symmetry={'point_group': sym}, mode='pw', width=0.001, txt=name + '.txt') e = a.get_potential_energy() #calc.diagonalize_full_hamiltonian(nbands=100) calc.write(name, 'all') calc = GPAW(name, txt=None, communicator=serial_comm) chiold = CHI(calc, w=omega, q=q_c, ecut=100, hilbert_trans=False, xc='RPA', G_plus_q=True, txt=name + '.logold') chiold.initialize() chiold.calculate() chi0old_wGG = chiold.chi0_wGG chi = Chi0(calc, omega, hilbert=False, ecut=100, txt=name + '.log') pd, chi0_wGG, _, _ = chi.calculate(q_c) assert abs(chi0_wGG - chi0old_wGG).max() < 1e-8 if not sym and not center: chi00_w = chi0_wGG[:, 0, 0] elif -1 not in calc.wfs.kd.bz2bz_ks: assert abs(chi0_wGG[:, 0, 0] - chi00_w).max() < 3e-5 #print abs(chi0_wGG[:, 0, 0] - chi00_w).max() if not sym: chi00_wGG = chi0_wGG elif -1 not in calc.wfs.kd.bz2bz_ks: assert abs(chi0_wGG - chi00_wGG).max() < 2e-5 #print abs(chi0_wGG - chi00_wGG).max() q0_c = [0, 1e-7, 1e-7] q0_v = np.dot(q0_c, a.get_reciprocal_cell() * 2 * np.pi) * Bohr q0 = (q0_v**2).sum()**0.5 chiold = CHI(calc, w=omega, q=q0_c, ecut=100, hilbert_trans=False, xc='RPA', optical_limit=True, G_plus_q=True, txt=name + '.logold0') chiold.initialize() chiold.calculate() chi0old_wGG = chiold.chi0_wGG chi0old_wGG[:, 0] /= q0 chi0old_wGG[:, :, 0] /= q0 pd, chi0_wGG, _, _ = chi.calculate([0, 0, 0]) assert abs(chi0_wGG - chi0old_wGG).max() < 0.003 assert abs(chi0_wGG - chi0old_wGG)[:, 1:, 1:].max() < 1e-8 if not sym and not center: chi000_w = chi0_wGG[:, 0, 0] elif -1 not in calc.wfs.kd.bz2bz_ks: assert abs(chi0_wGG[:, 0, 0] - chi000_w).max() < 0.001 if not sym: chi000_wGG = chi0_wGG elif -1 not in calc.wfs.kd.bz2bz_ks: assert abs(chi0_wGG - chi000_wGG).max() < 0.001 gpaw-0.11.0.13004/gpaw/test/asewannier.py0000664000175000017500000000251412553643471020102 0ustar jensjjensj00000000000000import numpy as np from ase.structure import molecule from ase.dft import Wannier from gpaw import GPAW from gpaw.test import equal # Test of ase wannier using gpaw calc = GPAW(gpts=(32, 32, 32), nbands=4) atoms = molecule('H2', calculator=calc) atoms.center(vacuum=3.) e = atoms.get_potential_energy() niter = calc.get_number_of_iterations() pos = atoms.positions + np.array([[0, 0, .2339], [0, 0, -.2339]]) com = atoms.get_center_of_mass() wan = Wannier(nwannier=2, calc=calc, initialwannier='bloch') equal(wan.get_functional_value(), 2.964, 1e-3) equal(np.linalg.norm(wan.get_centers() - [com, com]), 0, 1e-4) wan = Wannier(nwannier=2, calc=calc, initialwannier='projectors') equal(wan.get_functional_value(), 3.100, 2e-3) equal(np.linalg.norm(wan.get_centers() - pos), 0, 1e-3) wan = Wannier(nwannier=2, calc=calc, initialwannier=[[0, 0, .5], [1, 0, .5]]) equal(wan.get_functional_value(), 3.100, 2e-3) equal(np.linalg.norm(wan.get_centers() - pos), 0, 1e-3) wan.localize() equal(wan.get_functional_value(), 3.100, 2e-3) equal(np.linalg.norm(wan.get_centers() - pos), 0, 1e-3) equal(np.linalg.norm(wan.get_radii() - 1.2393), 0, 2e-3) eig = np.sort(np.linalg.eigvals(wan.get_hamiltonian().real)) equal(np.linalg.norm(eig - calc.get_eigenvalues()[:2]), 0, 1e-4) energy_tolerance = 0.00005 niter_tolerance = 0 equal(e, -6.65064, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/lcao_tddft.py0000664000175000017500000000333412553643471020052 0ustar jensjjensj00000000000000from __future__ import print_function from gpaw.tddft import photoabsorption_spectrum from ase import Atoms from gpaw import GPAW from gpaw.lcaotddft import LCAOTDDFT import gpaw.lrtddft as lrtddft from gpaw.mpi import world N = 2 xc = 'oldLDA' c = 0 h = 0.4 b = 'sz(dzp)' sy = 'H'+str(N) positions = [] for i in range(N): positions.append([0.00,0.00,i*0.7]) atoms = Atoms(symbols=sy, positions = positions) atoms.center(vacuum=3) print(atoms) # LCAO-RT-TDDFT parallel = {} if world.size > 3: parallel['band'] = 2 calc = LCAOTDDFT(mode='lcao', xc=xc, h=h, basis=b, nbands=N, dtype=complex, charge=c, convergence={'density':1e-6}, propagator='cn', parallel=parallel) atoms.set_calculator(calc) atoms.get_potential_energy() dmfile = sy+'_lcao_'+b+'_rt_z.dm'+str(world.size) specfile = sy+'_lcao_'+b+'_rt_z.spectrum'+str(world.size) calc.absorption_kick([0.0,0,0.001]) calc.propagate(10, 20, dmfile) if world.rank == 0: photoabsorption_spectrum(dmfile, specfile) if 0: # Reference RS-LR-TDDFT calc = GPAW(xc=xc, h=h, charge=c, width=0, nbands=4) atoms.set_calculator(calc) atoms.get_potential_energy() lr = lrtddft.LrTDDFT(calc, finegrid=0) lr.diagonalize() if world.rank == 0: lrtddft.photoabsorption_spectrum(lr, sy+'_rs_lr.spectrum', e_min=0.0, e_max=40) # Reference LCAO-LR-TDDFT calc = GPAW(mode='lcao', xc=xc, h=h, basis=b, charge=c, width=0) atoms.set_calculator(calc) atoms.get_potential_energy() lr = lrtddft.LrTDDFT(calc, finegrid=0) lr.diagonalize() if world.rank == 0: lrtddft.photoabsorption_spectrum(lr, sy+'_lcao_'+b+'_lr.spectrum', e_min=0.0, e_max=400) # XXX Actually check that the spectra match gpaw-0.11.0.13004/gpaw/test/pbe_pw91.py0000664000175000017500000000216612553643471017377 0ustar jensjjensj00000000000000from math import pi import numpy as np from gpaw.xc.libxc import LibXC x0 = LibXC('LDA_X') def f0(xc, rs, s): n = 3 / (4 * pi * rs**3) third = 1.0 / 3.0 kF = (3 * pi**2 * n)**third a2 = (2 * kF * n * s)**2 e = np.zeros(1) xc.calculate(e, np.array([[n]]), np.zeros((1, 1)), np.array([[a2]]), np.zeros((1, 1))) exc = n * e[0] x0.calculate(e, np.array([[n]]), np.zeros((1, 1))) ex0 = n * e[0] return exc / ex0 def f1(xc, rs, s): n = 3 / (4 * pi * rs**3) na = 2 * n third = 1.0 / 3.0 kF = (3 * pi**2 * n)**third rsa = (3 / pi / 4 / na)**third a2 = (2 * kF * n * s)**2 e = np.zeros(1) xc.calculate(e, np.array([[n], [0]]), np.zeros((2, 1)), np.array([[a2], [0], [0]]), np.zeros((3, 1))) exc = n * e[0] x0.calculate(e, np.array([[n]]), np.zeros((1, 1))) ex0 = n * e[0] return exc / ex0 pbe = LibXC('PBE') pw91 = LibXC('PW91') assert abs(f0(pbe, 2, 3) - 1.58) < 0.01 assert abs(f1(pbe, 2, 3) - 1.88) < 0.01 assert abs(f0(pw91, 2, 3) - 1.60) < 0.01 assert abs(f1(pw91, 2, 3) - 1.90) < 0.01 gpaw-0.11.0.13004/gpaw/test/si_xas.py0000664000175000017500000000316612553643472017241 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atom, Atoms from gpaw import GPAW, FermiDirac from gpaw.xas import XAS, RecursionMethod from gpaw.test import gen # Generate setup for oxygen with half a core-hole: gen('Si', name='hch1s', corehole=(1, 0, 0.5)) a = 4.0 b = a / 2 c = b / 2 d = b + c si = Atoms([Atom('Si', (0, 0, 0)), Atom('Si', (c, c, c)), Atom('Si', (b, b, 0)), Atom('Si', (d, d, c)), Atom('Si', (b, 0, b)), Atom('Si', (d, c, d)), Atom('Si', (0, b, b)), Atom('Si', (c, d, d))], cell=(a, a, a), pbc=True) import numpy as np calc = GPAW(nbands=None, h=0.25, occupations=FermiDirac(width=0.05), setups={0: 'hch1s'}) si.set_calculator(calc) e = si.get_potential_energy() niter = calc.get_number_of_iterations() calc.write('si.gpw') # restart from file calc = GPAW('si.gpw') import gpaw.mpi as mpi if mpi.size == 1: xas = XAS(calc) x, y = xas.get_spectra() else: x = np.linspace(0, 10, 50) k = 2 calc.set(kpts=(k, k, k)) calc.initialize() calc.set_positions(si) assert calc.wfs.dtype == complex r = RecursionMethod(calc) r.run(40) if mpi.size == 1: z = r.get_spectra(x) if 0: import pylab as p p.plot(x, y[0]) p.plot(x, sum(y)) p.plot(x, z[0]) p.show() # 2p corehole gen('Si', name='hch2p', corehole=(2, 1, 0.5)) calc = GPAW(nbands=None, h=0.25, occupations=FermiDirac(width=0.05), setups={0: 'hch2p'}) si.set_calculator(calc) e = si.get_potential_energy() niter = calc.get_number_of_iterations() calc.write('si_hch2p.gpw') gpaw-0.11.0.13004/gpaw/test/nonlocalset.py0000664000175000017500000000223412553643471020266 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW from gpaw.test import equal from gpaw.poisson import PoissonSolver atoms = Atoms('HF',positions=[(0.0,0.0,0.0),(1.0,0.0,0.0)]) atoms.set_pbc((True,True,True)) atoms.set_cell((2.0,2.0,2.0)) def MGGA_fail(): calc = GPAW(xc='TPSS', eigensolver='cg',kpts=(1,2,1), convergence={'density':1e-8}) atoms.set_calculator(calc) atoms.get_potential_energy() calc.set(kpts=(4,1,1)) return atoms.get_potential_energy() def MGGA_work(): calc = GPAW(xc='TPSS', eigensolver='cg', kpts=(4,1,1), convergence={'density':1e-8}) atoms.set_calculator(calc) return atoms.get_potential_energy() def GLLBSC_fail(): calc = GPAW(xc='GLLBSC', eigensolver='cg', kpts=(1,2,1), convergence={'density':1e-8}) atoms.set_calculator(calc) atoms.get_potential_energy() calc.set(kpts=(4,1,1)) return atoms.get_potential_energy() def GLLBSC_work(): calc = GPAW(xc='GLLBSC', eigensolver='cg', kpts=(4,1,1), convergence={'density':1e-8}) atoms.set_calculator(calc) return atoms.get_potential_energy() a = GLLBSC_fail() b = GLLBSC_work() equal(a,b, 1e-5) c = MGGA_fail() d = MGGA_work() equal(c,d, 1e-5) gpaw-0.11.0.13004/gpaw/test/diamond_gllb.py0000664000175000017500000000451212553643471020361 0ustar jensjjensj00000000000000from __future__ import print_function from ase.lattice import bulk from sys import argv from ase.dft.kpoints import ibz_points, get_bandpath from gpaw.eigensolvers.davidson import Davidson from gpaw import * from ase import * from gpaw.test import gen from gpaw import setup_paths import os """This calculation has the following structure. 1) Calculate the ground state of Diamond. 2) Calculate the band structure of diamond in order to obtain accurate KS band gap for Diamond. 3) Calculate ground state again, and calculate the potential discontinuity using accurate band gap. 4) Calculate band structure again, and apply the discontinuity to CBM. Compare to reference. """ xc = 'GLLBSC' gen('C',xcname=xc) setup_paths.insert(0, '.') # Calculate ground state atoms = bulk('C', 'diamond', a=3.567) calc = GPAW(h=0.15, kpts=(4,4,4), xc=xc, nbands = 6, eigensolver=Davidson(niter=2)) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('Cgs.gpw') # Calculate accurate KS-band gap from band structure points = ibz_points['fcc'] # CMB is in G-X G = points['Gamma'] X = points['X'] #W = points['W'] #K = points['K'] #L = points['L'] #[W, L, G, X, W, K] kpts, x, X = get_bandpath([G, X], atoms.cell, npoints=12) calc = GPAW('Cgs.gpw', kpts=kpts, fixdensity=True, symmetry='off', convergence=dict(bands=6), eigensolver=Davidson(niter=2)) calc.get_atoms().get_potential_energy() # Get the accurate KS-band gap homolumo = calc.occupations.get_homo_lumo(calc.wfs) homo, lumo = homolumo print("band gap ",(lumo-homo)*27.2) # Redo the ground state calculation calc = GPAW(h=0.15, kpts=(4,4,4), xc=xc, nbands = 6, eigensolver=Davidson(niter=2)) atoms.set_calculator(calc) atoms.get_potential_energy() # And calculate the discontinuity potential with accurate band gap response = calc.hamiltonian.xc.xcs['RESPONSE'] response.calculate_delta_xc(homolumo=homolumo) calc.write('CGLLBSC.gpw') # Redo the band structure calculation atoms, calc = restart('CGLLBSC.gpw', kpts=kpts, fixdensity=True, symmetry='off', convergence=dict(bands=6), eigensolver=Davidson(niter=2)) atoms.get_potential_energy() response = calc.hamiltonian.xc.xcs['RESPONSE'] KS, dxc = response.calculate_delta_xc_perturbation() assert abs(KS+dxc-5.41)<0.10 #M. Kuisma et. al, Phys. Rev. B 82, 115106, QP gap for C, 5.41eV, expt. 5.48eV gpaw-0.11.0.13004/gpaw/test/mixer.py0000664000175000017500000000074312553643471017074 0ustar jensjjensj00000000000000from ase import Atom, Atoms from gpaw import GPAW, Mixer from gpaw.test import equal a = 2.7 bulk = Atoms([Atom('Li')], pbc=True, cell=(a, a, a)) k = 2 g = 16 calc = GPAW(gpts=(g, g, g), kpts=(k, k, k), nbands=2, mixer=Mixer(nmaxold=5)) bulk.set_calculator(calc) e = bulk.get_potential_energy() niter = calc.get_number_of_iterations() calc.write('Li.gpw') calc2 = GPAW('Li.gpw') energy_tolerance = 0.00005 niter_tolerance = 0 equal(e, -1.20257, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/Hubbard_U_Zn.py0000664000175000017500000000130612553643471020246 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atom from ase.units import Hartree from gpaw import GPAW, FermiDirac from gpaw.cluster import Cluster from gpaw.test import equal h =.3 box = 4. energy_tolerance = 0.0004 s = Cluster([Atom('Zn')]) s.minimal_box(box, h=h) E = {} E_U = {} for spin in [0, 1]: c = GPAW(h=h, spinpol=spin, eigensolver='cg', charge=1, occupations=FermiDirac(width=0.1, fixmagmom=spin) ) s.set_calculator(c) E[spin] = s.get_potential_energy() c.set(setups=':d,3.0,1') E_U[spin] = s.get_potential_energy() print("E=", E) equal(E[0], E[1], energy_tolerance) print("E_U=", E_U) equal(E_U[0], E_U[1], energy_tolerance) gpaw-0.11.0.13004/gpaw/test/numpy_zdotc_graphite.py0000664000175000017500000000142012553643471022177 0ustar jensjjensj00000000000000# gpaw-python Segmentation faults # when gpaw-python and numpy are linked to different blas import numpy as np import sys from math import sqrt from ase import Atom, Atoms from gpaw import GPAW from gpaw import ConvergenceError kpts = (2,1,1) a=1.42 c=3.355 # AB stack atoms = Atoms('C4',[ (1/3.0,1/3.0,0), (2/3.0,2/3.0,0), (0. ,0. ,0.5), (1/3.0,1/3.0,0.5) ], pbc=(1,1,1)) atoms.set_cell([(sqrt(3)*a/2.0,3/2.0*a,0), (-sqrt(3)*a/2.0,3/2.0*a,0), (0.,0.,2*c)], scale_atoms=True) calc = GPAW(gpts=(8, 8, 20), nbands=9, kpts=kpts, maxiter=1) atoms.set_calculator(calc) try: pot = atoms.get_potential_energy() except ConvergenceError: pass gpaw-0.11.0.13004/gpaw/test/dot.py0000664000175000017500000000140712553643471016534 0ustar jensjjensj00000000000000import numpy as np # Test that numpy.dot behaves as expected, i.e. # [A . B]_ijpq = sum_k A_ijk * B_pkq # Product sum is over last dimension of A and second-to-last dimension of B # # See numpy.tensordot for ultimate flexibility in choosing the pruduct-sum axes # make "random" input arrays A = np.arange(6 * 2 * 5).reshape(6, 2, 5) - 3. B = np.arange(3 * 5 * 4).reshape(3, 5, 4) + 5. # built-in dot product AB1 = np.dot(A, B) # manual dot product AB2 = np.empty(A.shape[:-1] + B.shape[:-2] + (B.shape[-1],)) for i in range(AB2.shape[0]): for j in range(AB2.shape[1]): for p in range(AB2.shape[2]): for q in range(AB2.shape[3]): AB2[i, j, p, q] = np.sum(A[i, j, :] * B[p, :, q]) # test for consistency #print AB1 == AB2 assert np.all(AB1 == AB2) gpaw-0.11.0.13004/gpaw/test/kptpar.py0000664000175000017500000000242212553643471017245 0ustar jensjjensj00000000000000# see changeset 4891 import numpy as np from ase import Atoms from gpaw import GPAW from gpaw.mpi import world from gpaw.test import equal a = 2.5 H = Atoms('H', cell=[a, a, a], pbc=True) energy_tolerance = 0.00006 niter_tolerance = 0 if world.size >= 3: calc = GPAW(kpts=[6, 6, 1], spinpol=True, parallel={'domain': world.size}, txt='H-a.txt') H.set_calculator(calc) e1 = H.get_potential_energy() niter1 = calc.get_number_of_iterations() assert H.get_calculator().wfs.kd.comm.size == 1 equal(e1, -2.23708481, energy_tolerance) if world.rank < 3: comm = world.new_communicator(np.array([0, 1, 2])) H.set_calculator(GPAW(kpts=[6, 6, 1], spinpol=True, communicator=comm, txt='H-b.txt')) e2 = H.get_potential_energy() assert H.get_calculator().wfs.kd.comm.size == 3 equal(e1, e2, 5e-9) else: comm = world.new_communicator(np.array(range(3, world.size))) H.set_calculator(GPAW(kpts=[6, 6, 1], spinpol=True, communicator=comm, txt='H-b2.txt')) e2 = H.get_potential_energy() gpaw-0.11.0.13004/gpaw/test/exx_mgo.py0000664000175000017500000000163712553643471017421 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from ase.units import Ha from ase.dft.kpoints import monkhorst_pack from ase.parallel import paropen from ase.lattice import bulk from gpaw import GPAW, FermiDirac from gpaw.wavefunctions.pw import PW from gpaw.mpi import size from gpaw.xc.hybridg import HybridXC from ase.io import read for nk in (4,6,8): kpts = monkhorst_pack((nk,nk,nk)) kshift = 1./(2*nk) kpts += np.array([kshift, kshift, kshift]) atoms = bulk('MgO', 'rocksalt', a = 4.212) calc = GPAW(mode=PW(600),dtype=complex, basis='dzp', xc='PBE', maxiter=300, txt='gs_%s.txt'%(nk), kpts=kpts,parallel={'band':1}, occupations=FermiDirac(0.01)) atoms.set_calculator(calc) atoms.get_potential_energy() E = calc.get_potential_energy() E_exx = E + calc.get_xc_difference(HybridXC('EXX', method='acdf')) print(nk, E, E_exx) gpaw-0.11.0.13004/gpaw/test/pw/0000775000175000017500000000000012553644063016016 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/pw/slab.py0000664000175000017500000000114312553643471017312 0ustar jensjjensj00000000000000import numpy as np from ase import Atoms from ase.optimize import BFGS from gpaw import GPAW from gpaw.wavefunctions.pw import PW from gpaw.test import equal from gpaw.mpi import world a = 2.65 slab = Atoms('Li2', [(0, 0, 0), (0, 0, a)], cell=(a, a, 3 * a), pbc=True) k = 4 calc = GPAW(mode=PW(200), eigensolver='rmm-diis', parallel={'band': min(world.size, 4)}, idiotproof=0, kpts=(k, k, 1)) slab.set_calculator(calc) BFGS(slab).run(fmax=0.01) assert abs(slab.get_distance(0, 1) - 2.4594) < 0.001, slab.get_distance(0, 1) gpaw-0.11.0.13004/gpaw/test/pw/si_stress.py0000664000175000017500000000276512553643471020422 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from ase.lattice import bulk from gpaw import GPAW, PW si = bulk('Si') k = 3 si.calc = GPAW(mode=PW(250), xc='PBE', kpts=(k, k, k), convergence={'energy': 1e-8}, txt='si.txt') si.set_cell(np.dot(si.cell, [[1.02, 0, 0.03], [0, 0.99, -0.02], [0.2, -0.01, 1.03]]), scale_atoms=True) sigma_vv = si.get_stress(voigt=False) print(sigma_vv) deps = 1e-5 cell = si.cell.copy() for v in range(3): x = np.eye(3) x[v, v] += deps si.set_cell(np.dot(cell, x), scale_atoms=True) ep = si.calc.get_potential_energy(si, force_consistent=True) x[v, v] -= 2 * deps si.set_cell(np.dot(cell, x), scale_atoms=True) em = si.calc.get_potential_energy(si, force_consistent=True) s = (ep - em) / 2 / deps / si.get_volume() print((v, s, abs(s - sigma_vv[v, v]))) assert abs(s - sigma_vv[v, v]) < 1e-4 for v1 in range(3): v2 = (v1 + 1) % 3 x = np.eye(3) x[v1, v2] = deps x[v2, v1] = deps si.set_cell(np.dot(cell, x), scale_atoms=True) ep = si.calc.get_potential_energy(si, force_consistent=True) x[v1, v2] = -deps x[v2, v1] = -deps si.set_cell(np.dot(cell, x), scale_atoms=True) em = si.calc.get_potential_energy(si, force_consistent=True) s = (ep - em) / deps / 4 / si.get_volume() print((v1, v2, s, abs(s - sigma_vv[v1, v2]))) assert abs(s - sigma_vv[v1, v2]) < 2e-4 gpaw-0.11.0.13004/gpaw/test/pw/mgo_hybrids.py0000664000175000017500000000406312553643471020703 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from ase.lattice import bulk from ase.dft.kpoints import monkhorst_pack from ase.parallel import paropen from gpaw import GPAW, PW from gpaw.mpi import size, rank, world, serial_comm from gpaw.xc.tools import vxc from gpaw.xc.hybridg import HybridXC mgo = bulk('MgO', 'rocksalt', a=4.189) if rank < 3: comm = world.new_communicator(np.arange(min(3, size))) else: comm = world.new_communicator(np.array((rank,))) if 1: mgo.calc = GPAW(mode=PW(500), parallel=dict(band=1), idiotproof=False, communicator=comm, setups={'Mg': '2'}, convergence={'eigenstates': 5.e-9}, kpts=monkhorst_pack((2, 2, 2)) + 0.25) mgo.get_potential_energy() if rank < 3: mgo.calc.write('mgo', 'all') else: mgo.calc.write('dummy_%d' % rank, 'all') world.barrier() for name in ['PBE0', 'HSE03', 'HSE06']: calc = GPAW('mgo', setups={'Mg': '2'}, txt=None, communicator=serial_comm) hyb_calc = HybridXC(name, alpha=5.0, bandstructure=True, world=comm) de_skn = vxc(calc, hyb_calc) - vxc(calc, 'LDA') if name == 'PBE0': de_skn_test = np.array([-1.3700, -1.3643, -1.3777, -24.184590]) if name == 'HSE03': de_skn_test = np.array([-2.4565, -2.4326, -2.4583, -24.405001]) if name == 'HSE06': de_skn_test = np.array([-2.0311, -2.0151, -2.0367, -24.324485]) if rank == 0: print(de_skn[0, 0, 1:4], abs(de_skn[0, 0, 1:4] - de_skn_test[0]).max()) print(de_skn[0, 1, 2:4], abs(de_skn[0, 1, 2:4] - de_skn_test[1]).max()) print(de_skn[0, 2, 2:4], abs(de_skn[0, 2, 2:4] - de_skn_test[2]).max()) print(hyb_calc.exx, abs(hyb_calc.exx - de_skn_test[3])) assert abs(de_skn[0, 0, 1:4] - de_skn_test[0]).max() < 0.02 assert abs(de_skn[0, 1, 2:4] - de_skn_test[1]).max() < 0.008 assert abs(de_skn[0, 2, 2:4] - de_skn_test[2]).max() < 0.004 assert abs(hyb_calc.exx - de_skn_test[3]) < 2e-4 gpaw-0.11.0.13004/gpaw/test/pw/h.py0000664000175000017500000000117512553643471016625 0ustar jensjjensj00000000000000from ase.structure import molecule from gpaw import GPAW from gpaw.wavefunctions.pw import PW from gpaw.mpi import world a = molecule('H', pbc=1) a.center(vacuum=2) comm = world.new_communicator([world.rank]) e0 = 0.0 a.calc = GPAW(mode=PW(250), communicator=comm, txt=None) e0 = a.get_potential_energy() e0 = world.sum(e0) / world.size a.calc = GPAW(mode=PW(250), eigensolver='rmm-diis', basis='szp(dzp)', txt='%d.txt' % world.size) e = a.get_potential_energy() f = a.get_forces() assert abs(e - e0) < 7e-5, abs(e - e0) assert abs(f).max() < 1e-10, abs(f).max() gpaw-0.11.0.13004/gpaw/test/pw/lfc.py0000664000175000017500000000342112553643471017136 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from gpaw.test import equal from gpaw.grid_descriptor import GridDescriptor from gpaw.spline import Spline import gpaw.mpi as mpi from gpaw.lfc import LocalizedFunctionsCollection as LFC from gpaw.wavefunctions.pw import PWDescriptor, PWLFC from gpaw.kpt_descriptor import KPointDescriptor x = 2.0 rc = 3.5 r = np.linspace(0, rc, 100) n = 40 a = 8.0 gd = GridDescriptor((n, n, n), (a, a, a), comm=mpi.serial_comm) kpts = np.array([(0.25, 0.25, 0.0)]) kd = KPointDescriptor(kpts) spos_ac = np.array([(0.15, 0.5, 0.95)]) pd = PWDescriptor(45, gd, complex, kd) eikr = np.ascontiguousarray(np.exp(2j * np.pi * np.dot(np.indices(gd.N_c).T, (kpts / gd.N_c).T).T)[0]) from gpaw.fftw import FFTPlan print(FFTPlan) for l in range(3): print(l) s = Spline(l, rc, 2 * x**1.5 / np.pi * np.exp(-x * r**2)) lfc1 = LFC(gd, [[s]], kd, dtype=complex) lfc2 = PWLFC([[s]], pd) c_axi = {0: np.zeros((1, 2 * l + 1), complex)} c_axi[0][0, 0] = 1.9 - 4.5j c_axiv = {0: np.zeros((1, 2 * l + 1, 3), complex)} b1 = gd.zeros(1, dtype=complex) b2 = pd.zeros(1, dtype=complex) for lfc, b in [(lfc1, b1), (lfc2, b2)]: lfc.set_positions(spos_ac) lfc.add(b, c_axi, 0) b2 = pd.ifft(b2[0]) * eikr equal(abs(b2-b1[0]).max(), 0, 0.001) b1 = eikr[None] b2 = pd.fft(b1[0] * 0 + 1).reshape((1, -1)) results = [] results2 = [] for lfc, b in [(lfc1, b1), (lfc2, b2)]: lfc.integrate(b, c_axi, 0) results.append(c_axi[0][0].copy()) lfc.derivative(b, c_axiv, 0) results2.append(c_axiv[0][0].copy()) equal(abs(np.ptp(results2, 0)).max(), 0, 1e-7) equal(abs(np.ptp(results, 0)).max(), 0, 3e-8) gpaw-0.11.0.13004/gpaw/test/pw/davidson_pw.py0000664000175000017500000000201212553643471020702 0ustar jensjjensj00000000000000from ase import Atom, Atoms from gpaw import GPAW from gpaw.test import equal a = 4.05 d = a / 2**0.5 bulk = Atoms([Atom('Al', (0, 0, 0)), Atom('Al', (0.5, 0.5, 0.5))], pbc=True) bulk.set_cell((d, d, a), scale_atoms=True) h = 0.25 calc = GPAW(mode='pw', nbands=2*8, kpts=(2, 2, 2), convergence={'eigenstates': 7.2e-9, 'energy': 1e-5}) bulk.set_calculator(calc) e0 = bulk.get_potential_energy() niter0 = calc.get_number_of_iterations() calc = GPAW(mode='pw', nbands=2*8, kpts=(2, 2, 2), convergence={'eigenstates': 7.2e-9, 'energy': 1e-5, 'bands': 5 }, eigensolver='dav') bulk.set_calculator(calc) e1 = bulk.get_potential_energy() niter1 = calc.get_number_of_iterations() equal(e0, e1, 5.0e-6) energy_tolerance = 0.00004 niter_tolerance = 0 equal(e0, -6.97798, energy_tolerance) assert 10 <= niter0 <= 14, niter0 equal(e1, -6.97798, energy_tolerance) assert 10 <= niter1 <= 24, niter1 gpaw-0.11.0.13004/gpaw/test/pw/interpol.py0000664000175000017500000000366012553643471020233 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from gpaw.test import equal from gpaw.grid_descriptor import GridDescriptor from gpaw.transformers import Transformer from gpaw.wavefunctions.pw import PWDescriptor from gpaw.mpi import world def test(gd1, gd2, pd1, pd2, R1, R2): a1 = gd1.zeros(dtype=pd1.dtype) a1[R1] = 1 a2 = pd1.interpolate(a1, pd2)[0] x = a2[R2] a2 = gd2.zeros(dtype=pd2.dtype) a2[R2] = 1 y = pd2.restrict(a2, pd1)[0][R1] * a2.size / a1.size equal(x, y, 1e-9) return x if world.size == 1: for size1, size2 in [ [(3, 3, 3), (8, 8, 8)], [(4, 4, 4), (9, 9, 9)], [(2, 4, 4), (5, 9, 9)], [(2, 3, 4), (5, 6, 9)], [(2, 3, 4), (5, 6, 8)], [(4, 4, 4), (8, 8, 8)], [(2, 4, 4), (4, 8, 8)], [(2, 4, 2), (4, 8, 4)] ]: print(size1, size2) gd1 = GridDescriptor(size1, size1) gd2 = GridDescriptor(size2, size1) pd1 = PWDescriptor(1, gd1, complex) pd2 = PWDescriptor(1, gd2, complex) pd1r = PWDescriptor(1, gd1) pd2r = PWDescriptor(1, gd2) for R1, R2 in [[(0,0,0), (0,0,0)], [(0,0,0), (0,0,1)]]: x = test(gd1, gd2, pd1, pd2, R1, R2) y = test(gd1, gd2, pd1r, pd2r ,R1, R2) equal(x, y, 1e-9) a1 = np.random.random(size1) a2 = pd1r.interpolate(a1, pd2r)[0] c2 = pd1.interpolate(a1 + 0.0j, pd2)[0] d2 = pd1.interpolate(a1 * 1.0j, pd2)[0] equal(gd1.integrate(a1), gd2.integrate(a2), 1e-13) equal(abs(c2 - a2).max(), 0, 1e-14) equal(abs(d2 - a2 * 1.0j).max(), 0, 1e-14) a1 = pd2r.restrict(a2, pd1r)[0] c1 = pd2.restrict(a2 + 0.0j, pd1)[0] d1 = pd2.restrict(a2 * 1.0j, pd1)[0] equal(gd1.integrate(a1), gd2.integrate(a2), 1e-13) equal(abs(c1 - a1).max(), 0, 1e-14) equal(abs(d1 - a1 * 1.0j).max(), 0, 1e-14) gpaw-0.11.0.13004/gpaw/test/pw/bulk.py0000664000175000017500000000101712553643471017326 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from ase import Atoms from gpaw import GPAW from gpaw.wavefunctions.pw import PW from gpaw.test import equal bulk = Atoms('Li', pbc=True) k = 4 calc = GPAW(mode=PW(200), kpts=(k, k, k), eigensolver='rmm-diis') bulk.set_calculator(calc) e = [] niter = [] A = [2.6, 2.65, 2.7, 2.75, 2.8] for a in A: bulk.set_cell((a, a, a)) e.append(bulk.get_potential_energy()) a = np.roots(np.polyder(np.polyfit(A, e, 2), 1))[0] print('a =', a) equal(a, 2.65247379609, 0.001) gpaw-0.11.0.13004/gpaw/test/pw/fftmixer.py0000664000175000017500000000067012553643471020221 0ustar jensjjensj00000000000000import numpy as np from ase import Atoms from gpaw import GPAW from gpaw.mixer import FFTMixer from gpaw.wavefunctions.pw import PW from gpaw.test import equal bulk = Atoms('Li', pbc=True) k = 4 calc = GPAW(mode=PW(200), kpts=(k, k, k), mixer=FFTMixer(), eigensolver='rmm-diis') bulk.set_calculator(calc) bulk.set_cell((2.6, 2.6, 2.6)) e = bulk.get_potential_energy() nit = calc.get_number_of_iterations() equal(e, -1.98481281259, 1.0e-8) gpaw-0.11.0.13004/gpaw/test/pw/fulldiag.py0000664000175000017500000000222512553643471020162 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW from gpaw.mpi import world, serial_comm a = Atoms('H2', [(0, 0, 0), (0, 0, 0.74)], cell=(3, 3, 3), pbc=1) a.calc = GPAW(mode='pw', eigensolver='rmm-diis', nbands=8, dtype=complex, basis='dzp', txt=None) a.get_potential_energy() w1 = a.calc.get_pseudo_wave_function(0) e1 = a.calc.get_eigenvalues() a.calc.write('H2') if world.size == 1: scalapack = None else: scalapack = (2, world.size // 2, 32) a.calc.diagonalize_full_hamiltonian(nbands=120, scalapack=scalapack) w2 = a.calc.get_pseudo_wave_function(0) e2 = a.calc.get_eigenvalues() calc = GPAW('H2', txt=None) calc.diagonalize_full_hamiltonian(nbands=120, scalapack=scalapack) w3 = calc.get_pseudo_wave_function(0) e3 = calc.get_eigenvalues() calc.write('H2wf', 'all') calc = GPAW('H2wf', txt=None, communicator=serial_comm) w4 = calc.get_pseudo_wave_function(0) e4 = calc.get_eigenvalues() for w in [w2, w3, w4]: assert abs(abs(w[1, 2, 3]) - abs(w[1, 2, 3])) < 1e-10 for e in [e2, e3, e4]: assert abs(e[1] - e1[1]) < 1e-9 assert abs(e[-1] - e2[-1]) < 1e-10 gpaw-0.11.0.13004/gpaw/test/pw/hyb.py0000664000175000017500000000364612553643471017165 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atoms from gpaw import GPAW, PW from gpaw.mpi import rank, size, serial_comm from gpaw.xc.hybridg import HybridXC a = 2.0 li = Atoms('Li', cell=(a, a, a), pbc=1) for spinpol in [False, True]: for symm in [{}, 'off', {'time_reversal': False, 'point_group': False}]: if size == 8 and not spinpol and symm == {}: continue for qparallel in [False, True]: if rank == 0: print((spinpol, symm, qparallel)) li.calc = GPAW(mode=PW(300), kpts=(2, 3, 4), spinpol=spinpol, symmetry=symm, parallel={'band': 1}, txt=None, idiotproof=False) e = li.get_potential_energy() if qparallel: li.calc.write('li', mode='all') calc = GPAW('li', txt=None, communicator=serial_comm) else: calc = li.calc exx = HybridXC('EXX', logfilename=None, method='acdf') de = calc.get_xc_difference(exx) exx = HybridXC('EXX', logfilename=None, method='acdf', bandstructure=True, bands=[0, 1]) de2 = calc.get_xc_difference(exx) kd = calc.wfs.kd print(e, -0.56024, abs(e - -0.56024)) print(de, -0.4520, abs(de - -0.4520)) print(de, de2, abs(de - de2)) assert abs(e - -0.56024) < 1e-5, abs(e) assert abs(de - -0.4520) < 3e-4, abs(de) assert abs(de - de2) < 1e-12 for k in range(kd.nibzkpts): if abs(kd.ibzk_kc[k] - [0.25, 1 / 3.0, 3 / 8.0]).max() < 1e-7: assert abs(exx.exx_skn[:, k, 0] - -0.18246).max() < 1e-5 gpaw-0.11.0.13004/gpaw/test/pw/stresstest.py0000664000175000017500000000355612553643471020626 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from gpaw.grid_descriptor import GridDescriptor from gpaw.spline import Spline import gpaw.mpi as mpi from gpaw.wavefunctions.pw import PWDescriptor, PWLFC x = 2.0 rc = 3.5 r = np.linspace(0, rc, 100) n = 40 a = 8.0 cell_cv = np.array([[a, 0.5, -1], [0, a, 2], [-1, 0, a + 1]]) gd = GridDescriptor((n, n, n), cell_cv, comm=mpi.serial_comm) a_R = gd.empty() z = np.linspace(0, n, n, endpoint=False) a_R[:] = 2 + np.sin(2 * np.pi * z / n) spos_ac = np.array([(0.15, 0.45, 0.95)]) pd = PWDescriptor(45, gd) a_G = pd.fft(a_R) s = Spline(0, rc, 2 * x**1.5 / np.pi * np.exp(-x * r**2)) p = Spline(1, rc, 2 * x**1.5 / np.pi * np.exp(-x * r**2)) d = Spline(2, rc, 2 * x**1.5 / np.pi * np.exp(-x * r**2)) lfc = PWLFC([[s, p, d]], pd) lfc.set_positions(spos_ac) b_LG = pd.zeros(9) lfc.add(b_LG, {0: np.eye(9)}) e1 = pd.integrate(a_G, b_LG) assert abs(lfc.integrate(a_G)[0] - e1).max() < 1e-11 s1 = [] for i in range(9): x = [0, 0, 0, 0, 0, 0, 0, 0, 0] x[i] = 1 s1.append(lfc.stress_tensor_contribution(a_G, {0: x}) - np.eye(3) * e1[i]) x = 1e-6 for dist in [[[x, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, x, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, x]], [[0, x, 0], [x, 0, 0], [0, 0, 0]], [[0, 0, x], [0, 0, 0], [x, 0, 0]], [[0, 0, 0], [0, 0, x], [0, x, 0]]]: e = dist + np.eye(3) c_cv = np.dot(cell_cv, e) gd = GridDescriptor((n, n, n), c_cv, comm=mpi.serial_comm) pd = PWDescriptor(45, gd) aa_G = a_G / np.linalg.det(e) lfc = PWLFC([[s, p, d]], pd) lfc.set_positions(spos_ac) b_LG = pd.zeros(9) lfc.add(b_LG, {0: np.eye(9)}) e2 = pd.integrate(aa_G, b_LG) s2 = (e2 - e1) / x error = (np.array(s1) * dist).sum(1).sum(1) / x - s2 print(s2, abs(error).max()) assert abs(error).max() < 2e-6 gpaw-0.11.0.13004/gpaw/test/pw/fulldiagk.py0000664000175000017500000000231412553643471020334 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW from gpaw.mpi import world, serial_comm a = Atoms('H', cell=(1, 3, 3), pbc=1) a.calc = GPAW(mode='pw', h=0.15, kpts=(4, 1, 1), basis='dzp', nbands=4, eigensolver='rmm-diis', txt=None) a.get_potential_energy() w1 = a.calc.get_pseudo_wave_function(0, 1) e1 = a.calc.get_eigenvalues(1) a.calc.write('H') if world.size <= 2: scalapack = None else: mb = world.size // 4 scalapack = (2, world.size // 4, 32) a.calc.diagonalize_full_hamiltonian(nbands=100, scalapack=scalapack) w2 = a.calc.get_pseudo_wave_function(0, 1) e2 = a.calc.get_eigenvalues(1) calc = GPAW('H', txt=None) calc.diagonalize_full_hamiltonian(nbands=100, scalapack=scalapack) w3 = calc.get_pseudo_wave_function(0, 1) e3 = calc.get_eigenvalues(1) calc.write('Hwf', 'all') calc = GPAW('Hwf', txt=None, communicator=serial_comm) w4 = calc.get_pseudo_wave_function(0, 1) e4 = calc.get_eigenvalues(1) for w in [w2, w3, w4]: assert abs(abs(w[1, 2, 3]) - abs(w1[1, 2, 3])) < 1e-7 for e in [e2, e3, e4]: assert abs(e[0] - e1[0]) < 2e-9, abs(e[0] - e1[0]) assert abs(e[-1] - e2[-1]) < 1e-10 gpaw-0.11.0.13004/gpaw/test/pw/moleculecg.py0000664000175000017500000000043312553643471020511 0ustar jensjjensj00000000000000# fails with On entry to ZGEMV parameter number 8 had an illegal value from ase.structure import molecule from gpaw import GPAW from gpaw.wavefunctions.pw import PW m = molecule('H') m.center(vacuum=2.0) m.set_calculator(GPAW(mode=PW(), eigensolver='cg')) m.get_potential_energy() gpaw-0.11.0.13004/gpaw/test/pw/reallfc.py0000664000175000017500000000312112553643471017777 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from gpaw.test import equal from gpaw.grid_descriptor import GridDescriptor from gpaw.spline import Spline import gpaw.mpi as mpi from gpaw.lfc import LocalizedFunctionsCollection as LFC from gpaw.wavefunctions.pw import PWDescriptor, PWLFC from gpaw.kpt_descriptor import KPointDescriptor x = 2.0 rc = 3.5 r = np.linspace(0, rc, 100) n = 40 a = 8.0 gd = GridDescriptor((n, n, n), (a, a, a), comm=mpi.serial_comm) spos_ac = np.array([(0.15, 0.45, 0.95)]) pd = PWDescriptor(45, gd, complex) pdr = PWDescriptor(45, gd) from gpaw.fftw import FFTPlan print(FFTPlan) for l in range(4): print(l) s = Spline(l, rc, 2 * x**1.5 / np.pi * np.exp(-x * r**2)) lfc = PWLFC([[s]], pd) lfcr = PWLFC([[s]], pdr) c_axi = {0: np.zeros((1, 2 * l + 1), complex)} c_axi[0][0, 0] = 1.9 cr_axi = {0: np.zeros((1, 2 * l + 1))} cr_axi[0][0, 0] = 1.9 b = pd.zeros(1, dtype=complex) br = pdr.zeros(1) lfc.set_positions(spos_ac) lfc.add(b, c_axi) lfcr.set_positions(spos_ac) lfcr.add(br, cr_axi) a = pd.ifft(b) ar = pdr.ifft(br) equal(abs(a-ar).max(), 0, 1e-14) if l == 0: a = a[:, ::-1].copy() b0 = pd.fft(a) br0 = pdr.fft(a.real) lfc.integrate(b0, c_axi) lfcr.integrate(br0, cr_axi) assert abs(c_axi[0][0]-cr_axi[0][0]).max() < 1e-14 c_axiv = {0: np.zeros((1, 2 * l + 1, 3), complex)} cr_axiv = {0: np.zeros((1, 2 * l + 1, 3))} lfc.derivative(b0, c_axiv) lfcr.derivative(br0, cr_axiv) assert abs(c_axiv[0][0]-cr_axiv[0][0]).max() < 1e-14 gpaw-0.11.0.13004/gpaw/test/pw/__init__.py0000664000175000017500000000000012553643471020117 0ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/reorder.py0000664000175000017500000000306212553643471017407 0ustar jensjjensj00000000000000from optparse import OptionParser import numpy as np usage = '%prog [OPTION] FILE' description = 'Parse test results in FILE and reorder tests by duration.' p = OptionParser(usage=usage, description=description) p.add_option('--pretty', action='store_true', help='print nicely with timings. ' 'Otherwise print Python syntax') opts, args = p.parse_args() if len(args) != 1: p.error('One file please.') fd = open(args[0]) for line in fd: if line.startswith('===='): break tests = [] durations = [] results = [] for line in fd: if line.startswith('===='): break t1, t2, t3 = line.split() tests.append(t1) if t3 == 'OK': durations.append(float(t2)) else: durations.append(np.inf) results.append(t3) # Use stable sort for minimum shuffling args = np.argsort(durations, kind='mergesort') tests = np.array(tests)[args] durations = np.array(durations)[args] results = np.array(results)[args] if opts.pretty: for test, duration, result in zip(tests, durations, results): print('%30s %10s %10s' % (test, duration, result)) else: maxnamelen = max([len(test) for test in tests]) for test, duration in zip(tests, durations): comment = '' if duration > 1.0: if np.isfinite(duration): comment = '# ~%ds' % int(duration) else: comment = '# duration unknown' print(''.join([' ', ("'%s'," % test).ljust(maxnamelen + 5), comment]).rstrip()) gpaw-0.11.0.13004/gpaw/test/lapack.py0000664000175000017500000000052012553643471017174 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from gpaw.test import equal from gpaw.utilities.lapack import sqrt_matrix # check sqrt of a matrix A = [[20, 4], [4, 1]] a = [[4.4, .8], [.8, .6]] A = np.array(A, float) print('A=', A) a = np.array(a) b = sqrt_matrix(A) print('sqrt(A)=', b) equal(((a-b)**2).sum(), 0, 1.e-12) gpaw-0.11.0.13004/gpaw/test/two_phi_plw_integrals.py0000664000175000017500000000340012553643472022345 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from gpaw.lfc import LocalizedFunctionsCollection as LFC from gpaw.grid_descriptor import GridDescriptor, RadialGridDescriptor from gpaw.spline import Spline from gpaw.response.math_func import two_phi_planewave_integrals # Initialize s, p, d (9 in total) wave and put them on grid rc = 2.0 a = 2.5 * rc n = 64 lmax = 2 b = 8.0 m = (lmax + 1)**2 gd = GridDescriptor([n, n, n], [a, a, a]) r = np.linspace(0, rc, 200) g = np.exp(-(r / rc * b)**2) splines = [Spline(l=l, rmax=rc, f_g=g) for l in range(lmax + 1)] c = LFC(gd, [splines]) c.set_positions([(0.5, 0.5, 0.5)]) psi = gd.zeros(m) d0 = c.dict(m) if 0 in d0: d0[0] = np.identity(m) c.add(psi, d0) # Calculate on 3d-grid < phi_i | e**(-ik.r) | phi_j > R_a = np.array([a/2,a/2,a/2]) rr = gd.get_grid_point_coordinates() for dim in range(3): rr[dim] -= R_a[dim] k_G = np.array([[11.,0.2,0.1],[10., 0., 10.]]) nkpt = k_G.shape[0] d0 = np.zeros((nkpt,m,m), dtype=complex) for i in range(m): for j in range(m): for ik in range(nkpt): k = k_G[ik] kk = np.sqrt(np.inner(k,k)) kr = np.inner(k,rr.T).T expkr = np.exp(-1j * kr) d0[ik, i,j] = gd.integrate(psi[i] * psi[j] * expkr) # Calculate on 1d-grid < phi_i | e**(-ik.r) | phi_j > rgd = RadialGridDescriptor(r, np.ones_like(r) * r[1]) g = [np.exp(-(r / rc * b)**2)*r**l for l in range(lmax + 1)] l_j = range(lmax + 1) d1 = two_phi_planewave_integrals(k_G, rgd=rgd, phi_jg=g, phit_jg=np.zeros_like(g), l_j=l_j) d1 = d1.reshape(nkpt, m, m) for i in range(m): for j in range(m): for ik in range(nkpt): if np.abs(d0[ik,i,j] - d1[ik,i,j]) > 1e-10: print(i, j, d0[ik,i,j]- d1[ik,i,j]) gpaw-0.11.0.13004/gpaw/test/ralda_energy_H2.py0000664000175000017500000000416312553643471020735 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW from gpaw.wavefunctions.pw import PW from gpaw.xc.fxc import FXCCorrelation from gpaw.test import equal from gpaw.mpi import world if world.size == 1: scalapack1 = None scalapack2 = None elif world.size == 2: scalapack1 = (2, world.size // 2, 32) scalapack2 = None else: scalapack1 = (2, world.size // 2, 32) scalapack2 = (2, world.size // 4, 32) # H2 -------------------------------------- H2 = Atoms('H2', [(0,0,0),(0,0,0.7413)]) H2.set_pbc(True) H2.set_cell((2., 2., 3.)) H2.center() calc = GPAW(mode=PW(210), eigensolver='rmm-diis', dtype=complex, xc='LDA', basis='dzp', nbands=8, convergence={'density': 1.e-6}) H2.set_calculator(calc) H2.get_potential_energy() calc.diagonalize_full_hamiltonian(nbands=80, scalapack=scalapack1) calc.write('H2.gpw', mode='all') ralda = FXCCorrelation('H2.gpw', xc='rALDA') E_ralda_H2 = ralda.calculate(ecut=[200]) rapbe = FXCCorrelation('H2.gpw', xc='rAPBE') E_rapbe_H2 = rapbe.calculate(ecut=[200]) # H --------------------------------------- H = Atoms('H', [(0,0,0)]) H.set_pbc(True) H.set_cell((2., 2., 3.)) H.center() calc = GPAW(mode=PW(210), eigensolver='rmm-diis', dtype=complex, xc='LDA', basis='dzp', nbands=4, hund=True, convergence={'density': 1.e-6}) H.set_calculator(calc) H.get_potential_energy() calc.diagonalize_full_hamiltonian(nbands=80, scalapack=scalapack2) calc.write('H.gpw', mode='all') ralda = FXCCorrelation('H.gpw', xc='rALDA') E_ralda_H = ralda.calculate(ecut=[200]) rapbe = FXCCorrelation('H.gpw', xc='rAPBE') E_rapbe_H = rapbe.calculate(ecut=[200]) # if rank == 0: # system('rm H2.gpw') # system('rm H.gpw') # system('rm fhxc_H2_rALDA_200_0.gpw') # system('rm fhxc_H_rALDA_200_0.gpw') # system('rm fhxc_H2_rAPBE_200_0.gpw') # system('rm fhxc_H_rAPBE_200_0.gpw') equal(E_ralda_H2, -0.8411, 0.001) equal(E_ralda_H, 0.002860, 0.00001) equal(E_rapbe_H2, -0.7233, 0.001) equal(E_rapbe_H, 0.016022, 0.00001) gpaw-0.11.0.13004/gpaw/test/AA_exx_enthalpy.py0000664000175000017500000001672012553643472021024 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atoms, Atom from ase.structure import molecule from ase.parallel import barrier from ase.units import Hartree, mol, kcal from gpaw import GPAW, setup_paths from gpaw.mixer import Mixer, MixerSum from gpaw.occupations import FermiDirac from gpaw.atom.generator import Generator from gpaw.atom.configurations import parameters from gpaw.test import equal, gen from gpaw.mpi import rank from os import remove from os.path import exists data = {} # data (from tables.pdf of 10.1063/1.1626543) data['N'] = { # intermolecular distance (A), #formation enthalpy(298) (kcal/mol) on B3LYP geometry 'exp': (1.098, 0.0, 'none', 'none'), 'HCTH407': (1.097, 7.9, 'HCTH407', 'gga'), 'PBE': (1.103, -15.1, 'PBE', 'gga'), 'BLYP': (1.103, -11.7, 'BLYP', 'gga'), 'BP86': (1.104, -15.6, 'BP86', 'gga'), 'BPW91': (1.103, -8.5, 'BPW91', 'gga'), 'B3LYP': (1.092, -1.03, 'BLYP', 'hyb_gga'), 'B3PW91': (1.091, 2.8, 'PW91', 'hyb_gga'), 'PBE0': (1.090, 3.1, 'PBE', 'hyb_gga'), 'PBEH': (1.090, 3.1, 'PBE', 'hyb_gga'), 'magmom': 3.0, # tables.pdf: # http://ftp.aip.org/epaps/journ_chem_phys/E-JCPSA6-119-302348/tables.pdf 'R_AA_B3LYP': 1.092, # (from tables.pdf of 10.1063/1.1626543) (Angstom) 'ZPE_AA_B3LYP': 0.005457 * Hartree, # (from benchmarks.txt of # 10.1063/1.1626543) (eV) 'H_298_H_0_AA_B3LYP': 0.003304 * Hartree, # (from benchmarks.txt of # 10.1063/1.1626543) (eV) 'H_298_H_0_A': 1.04 / (mol / kcal), # (from 10.1063/1.473182) (eV) 'dHf_0_A': 112.53 / (mol / kcal), # (from 10.1063/1.473182) (eV) } data['O'] = { # intermolecular distance (A), # formation enthalpy(298) (kcal/mol) on B3LYP geometry 'exp': (1.208, 0.0, 'none', 'none'), 'HCTH407': (1.202, -14.5, 'HCTH407', 'gga'), 'PBE': (1.218, -23.6, 'PBE', 'gga'), 'BLYP': (1.229, -15.4, 'BLYP', 'gga'), 'BP86': (1.220, -21.9, 'BP86', 'gga'), 'BPW91': (1.219, -17.9, 'BPW91', 'gga'), 'B3LYP': (1.204, -3.7, 'BLYP', 'hyb_gga'), 'B3PW91': (1.197, -5.1, 'PW91', 'hyb_gga'), 'PBE0': (1.192, -4.3, 'PBE', 'hyb_gga'), 'PBEH': (1.192, -4.3, 'PBE', 'hyb_gga'), 'magmom': 2.0, # tables.pdf: # http://ftp.aip.org/epaps/journ_chem_phys/E-JCPSA6-119-302348/tables.pdf 'R_AA_B3LYP': 1.204, # (from tables.pdf of 10.1063/1.1626543) (Angstom) 'ZPE_AA_B3LYP': 0.003736 * Hartree, # (from benchmarks.txt of # 10.1063/1.1626543) (eV) 'H_298_H_0_AA_B3LYP': 0.003307*Hartree, # (from benchmarks.txt of # 10.1063/1.1626543) (eV) 'H_298_H_0_A': 1.04 / (mol / kcal), # (from 10.1063/1.473182) (eV) 'dHf_0_A': 58.99 / (mol / kcal), # (from 10.1063/1.473182) (eV) } data['H'] = { # intermolecular distance (A), # formation enthalpy(298) (kcal/mol) on B3LYP geometry 'exp': (0.741, 0.0, 'none', 'none'), 'HCTH407': (0.744, 1.8, 'HCTH407', 'gga'), 'PBE': (0.750, 5.1, 'PBE', 'gga'), 'BLYP': (0.746, 0.3, 'BLYP', 'gga'), 'BP86': (0.750, -1.8, 'BP86', 'gga'), 'BPW91': (0.748, 4.0, 'BPW91', 'gga'), 'B3LYP': (0.742, -0.5, 'BLYP', 'hyb_gga'), 'B3PW91': (0.744, 2.4, 'PW91', 'hyb_gga'), 'PBE0': (0.745, 5.3, 'PBE', 'hyb_gga'), 'PBEH': (0.745, 5.3, 'PBE', 'hyb_gga'), 'magmom': 1.0, # tables.pdf: # http://ftp.aip.org/epaps/journ_chem_phys/E-JCPSA6-119-302348/tables.pdf 'R_AA_B3LYP': 0.742, # (from tables.pdf of 10.1063/1.1626543) (Angstom) 'ZPE_AA_B3LYP': 0.010025 * Hartree, # (from benchmarks.txt of # 10.1063/1.1626543) (eV) 'H_298_H_0_AA_B3LYP': 0.003305 * Hartree, # (from benchmarks.txt of # 10.1063/1.1626543) (eV) 'H_298_H_0_A': 1.01 / (mol / kcal), # (from 10.1063/1.473182) (eV) 'dHf_0_A': 51.63 / (mol / kcal), # (from 10.1063/1.473182) (eV) } def calculate(element, h, vacuum, xc, magmom): atom = Atoms([Atom(element, (0, 0, 0))]) if magmom > 0.0: mms = [magmom for i in range(len(atom))] atom.set_initial_magnetic_moments(mms) atom.center(vacuum=vacuum) mixer = MixerSum(beta=0.2) if element == 'O': mixer = MixerSum(nmaxold=1, weight=100) atom.set_positions(atom.get_positions()+[0.0, 0.0, 0.0001]) calc_atom = GPAW(h=h, xc=data[element][xc][2], eigensolver='rmm-diis', occupations=FermiDirac(0.0, fixmagmom=True), mixer=mixer, nbands=-2, txt='%s.%s.txt' % (element, xc)) atom.set_calculator(calc_atom) mixer = Mixer(beta=0.2, weight=100) compound = molecule(element+'2') if compound == 'O2': mixer = MixerSum(beta=0.2) mms = [1.0 for i in range(len(compound))] compound.set_initial_magnetic_moments(mms) calc = GPAW(h=h, xc=data[element][xc][2], eigensolver='rmm-diis', mixer=mixer, txt='%s2.%s.txt' % (element, xc)) compound.set_distance(0,1, data[element]['R_AA_B3LYP']) compound.center(vacuum=vacuum) compound.set_calculator(calc) if data[element][xc][3] == 'hyb_gga': # only for hybrids e_atom = atom.get_potential_energy() e_compound = compound.get_potential_energy() calc_atom.set(xc=xc) calc.set(xc=xc) if 0: qn = QuasiNewton(compound) qn.attach(Trajectory( element+'2'+'_'+xc+'.traj', 'w', compound).write) qn.run(fmax=0.02) e_atom = atom.get_potential_energy() e_compound = compound.get_potential_energy() dHf_0 = (e_compound - 2 * e_atom + data[element]['ZPE_AA_B3LYP'] + 2 * data[element]['dHf_0_A']) dHf_298 = (dHf_0 + data[element]['H_298_H_0_AA_B3LYP'] - 2 * data[element]['H_298_H_0_A']) * (mol / kcal) dist_compound = compound.get_distance(0,1) de = dHf_298-data[element][xc][1] E[element][xc] = de if rank == 0: print((xc, h, vacuum, dHf_298, data[element][xc][1], de, de/data[element][xc][1])) if element == 'H': equal(dHf_298, data[element][xc][1], 0.25, msg=xc+': ') # kcal/mol elif element == 'O': equal(dHf_298, data[element][xc][1], 7.5, msg=xc+': ') # kcal/mol else: equal(dHf_298, data[element][xc][1], 2.15, msg=xc+': ') # kcal/mol equal(de, E_ref[element][xc], 0.06, msg=xc+': ') # kcal/mol E = {} E_ref = {'H': {'HCTH407': 0.19286893273630645, 'B3LYP': -0.11369634560501423, 'PBE0': -0.21413764474738262, 'PBEH': -0.14147808591211231}, 'N': {'HCTH407': 2.1354017840869268, 'B3LYP': 0.63466589919873972, 'PBE0': -0.33376468078480226, 'PBEH': -0.30365500626180042}} # svnversion 5599 # -np 4 for element in ['H']:#, 'N']:#, 'O']: # oxygen atom fails to converge E[element] = {} for xc in ['HCTH407', 'PBE0', 'B3LYP']: setup = data[element][xc][2] if data[element][xc][3] == 'hyb_gga': # only for hybrids exx = True else: exx = False gen(element, exx=exx, xcname=setup) for h in [0.20]: for vacuum in [4.5]: calculate(element, h, vacuum, xc, data[element]['magmom']) barrier() if rank == 0: if exists(element+'.'+setup): remove(element+'.'+setup) gpaw-0.11.0.13004/gpaw/test/ed.py0000664000175000017500000000555712553643471016350 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW from gpaw.fdtd.poisson_fdtd import FDTDPoissonSolver from gpaw.fdtd.polarizable_material import PermittivityPlus, PolarizableMaterial, PolarizableSphere from gpaw.mpi import world from gpaw.tddft import TDDFT, photoabsorption_spectrum, units from gpaw.test import equal import numpy as np # Whole simulation cell (Angstroms) large_cell = [20, 20, 30]; # Quantum subsystem atom_center = np.array([10.0, 10.0, 20.0]); atoms = Atoms('Na2', [atom_center + [0.0, 0.0, -1.50], atom_center + [0.0, 0.0, +1.50]]); # Permittivity file if world.rank == 0: fo = open('ed.txt', 'w') fo.writelines(['1.20 0.20 25.0']) fo.close() world.barrier() # Classical subsystem classical_material = PolarizableMaterial() sphere_center = np.array([10.0, 10.0, 10.0]); classical_material.add_component(PolarizableSphere(permittivity = PermittivityPlus('ed.txt'), center = sphere_center, radius = 5.0 )) # Combined Poisson solver poissonsolver = FDTDPoissonSolver(classical_material = classical_material, qm_spacing = 0.40, cl_spacing = 0.40*4, cell = large_cell, remove_moments = (1, 4), communicator = world, potential_coupler = 'Refiner') poissonsolver.set_calculation_mode('iterate') # Combined system atoms.set_cell(large_cell) atoms, qm_spacing, gpts = poissonsolver.cut_cell(atoms, vacuum=2.50) # Initialize GPAW gs_calc = GPAW(gpts = gpts, eigensolver = 'cg', nbands = -1, poissonsolver = poissonsolver); atoms.set_calculator(gs_calc) # Ground state energy = atoms.get_potential_energy() # Save state gs_calc.write('gs.gpw', 'all') classical_material = None gs_calc = None # Initialize TDDFT and FDTD kick = [0.0, 0.0, 1.0e-3] time_step = 10.0 max_time = 100 # 0.1 fs td_calc = TDDFT('gs.gpw') td_calc.absorption_kick(kick_strength=kick) td_calc.hamiltonian.poisson.set_kick(kick) # Propagate TDDFT and FDTD td_calc.propagate(time_step, max_time/time_step/2, 'dm.dat', 'td.gpw') td_calc2 = TDDFT('td.gpw') td_calc2.propagate(time_step, max_time/time_step/2, 'dm.dat', 'td.gpw') # Test ref_cl_dipole_moment = [ -5.16149623e-14, -5.89090408e-14, 3.08450150e-02] ref_qm_dipole_moment = [ -2.63340461e-11, 2.61812794e-12, -9.35619772e-02] tol = 0.0001 equal(td_calc2.hamiltonian.poisson.get_classical_dipole_moment(), ref_cl_dipole_moment, tol) equal(td_calc2.hamiltonian.poisson.get_quantum_dipole_moment(), ref_qm_dipole_moment, tol) gpaw-0.11.0.13004/gpaw/test/fermilevel.py0000664000175000017500000000232512553643472020101 0ustar jensjjensj00000000000000import numpy as np from ase import Atoms from gpaw import GPAW, FermiDirac from gpaw.test import equal modes = ['gpw'] try: import _gpaw_hdf5 modes.append('hdf5') except ImportError: pass calc = GPAW(nbands=1, occupations=FermiDirac(0.0))#, txt=None) atoms = Atoms('He', pbc=True, calculator=calc) atoms.center(vacuum=3) e0 = atoms.get_potential_energy() niter0 = calc.get_number_of_iterations() try: calc.get_fermi_level() except ValueError: pass # It *should* raise an error else: raise RuntimeError('get_fermi_level should not be possible for width=0') calc.set(nbands=3, convergence={'bands':2}) atoms.get_potential_energy() homo, lumo = calc.get_homo_lumo() equal(homo, -15.4473, 0.01) equal(lumo, -0.2566, 0.01) for mode in modes: calc.write('test.%s' % mode) assert np.all(GPAW('test.%s' % mode, txt=None).get_homo_lumo() == (homo, lumo)) ef = calc.get_fermi_level() equal(ef, -7.85196, 0.01) calc.set(occupations=FermiDirac(0.1)) e1 = atoms.get_potential_energy() niter1 = calc.get_number_of_iterations() ef = calc.get_fermi_level() equal(ef, -7.85196, 0.01) for mode in modes: calc.write('test.%s' % mode) equal(GPAW('test.%s' % mode, txt=None).get_fermi_level(), ef, 1e-8) gpaw-0.11.0.13004/gpaw/test/df_block_par_test_na_plasmons.py0000664000175000017500000000462312553643471024007 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW, PW from gpaw.response.df import DielectricFunction from gpaw.test import equal, findpeak # Comparing the EELS spectrum of sodium for different block # parallelizations. Intended to be run with 8 cores. a = 4.23 / 2.0 a1 = Atoms('Na', scaled_positions=[[0, 0, 0]], cell=(a, a, a), pbc=True) a1.calc = GPAW(gpts=(10, 10, 10), mode=PW(300), kpts={'size': (10, 10, 10), 'gamma': True}, parallel={'band': 1}, txt='small.txt') a1.get_potential_energy() a1.calc.diagonalize_full_hamiltonian(nbands=20) a1.calc.write('gs_Na.gpw', 'all') # Calculate the dielectric functions df1 = DielectricFunction('gs_Na.gpw', nblocks=1, ecut=400, txt='1block.txt') df1NLFCx, df1LFCx = df1.get_dielectric_function(direction='x') df1NLFCy, df1LFCy = df1.get_dielectric_function(direction='y') df1NLFCz, df1LFCz = df1.get_dielectric_function(direction='z') df2 = DielectricFunction('gs_Na.gpw', nblocks=2, ecut=400, txt='2block.txt') df2NLFCx, df2LFCx = df2.get_dielectric_function(direction='x') df2NLFCy, df2LFCy = df2.get_dielectric_function(direction='y') df2NLFCz, df2LFCz = df2.get_dielectric_function(direction='z') df3 = DielectricFunction('gs_Na.gpw', nblocks=4, ecut=400, txt='4block.txt') df3NLFCx, df3LFCx = df3.get_dielectric_function(direction='x') df3NLFCy, df3LFCy = df3.get_dielectric_function(direction='y') df3NLFCz, df3LFCz = df3.get_dielectric_function(direction='z') df4 = DielectricFunction('gs_Na.gpw', nblocks=8, ecut=400, txt='8block.txt') df4NLFCx, df4LFCx = df4.get_dielectric_function(direction='x') df4NLFCy, df4LFCy = df4.get_dielectric_function(direction='y') df4NLFCz, df4LFCz = df4.get_dielectric_function(direction='z') # Compare plasmon frequencies and intensities w_w = df1.chi0.omega_w w1, I1 = findpeak(w_w, -(1. / df1LFCx).imag) w2, I2 = findpeak(w_w, -(1. / df2LFCx).imag) w3, I3 = findpeak(w_w, -(1. / df3LFCy).imag) w4, I4 = findpeak(w_w, -(1. / df4LFCy).imag) equal(w1, w2, 1e-2) equal(I1, I2, 1e-3) equal(w1, w3, 1e-2) equal(I1, I3, 1e-3) equal(w1, w4, 1e-2) equal(I1, I4, 1e-3) gpaw-0.11.0.13004/gpaw/test/si_primitive.py0000664000175000017500000000144212553643471020450 0ustar jensjjensj00000000000000import numpy as np from ase.lattice import bulk from gpaw import GPAW, FermiDirac from gpaw.test import equal a = 5.475 calc = GPAW(h=0.24, kpts=(4, 4, 4), occupations=FermiDirac(width=0.0), nbands=5) atoms = bulk('Si', 'diamond', a=a) atoms.set_calculator(calc) E = atoms.get_potential_energy() equal(E, -11.8092858, 0.0002) niter = calc.get_number_of_iterations() equal(atoms.calc.get_fermi_level(), 5.17751284, 0.005) homo, lumo = calc.get_homo_lumo() equal(lumo - homo, 1.11445025, 0.002) calc.write('si_primitive.gpw', 'all') calc = GPAW('si_primitive.gpw', parallel={'domain': 1, 'band': 1}, idiotproof=False, txt=None) from gpaw.xc.hybridk import HybridXC pbe0 = HybridXC('PBE0', alpha=5.0) calc.get_xc_difference(pbe0) gpaw-0.11.0.13004/gpaw/test/ldos.py0000664000175000017500000000571512553643471016715 0ustar jensjjensj00000000000000from __future__ import print_function import os import numpy as np from ase import Atom, Atoms from gpaw import GPAW, FermiDirac from gpaw.utilities.dos import raw_orbital_LDOS, raw_wignerseitz_LDOS, RawLDOS from gpaw.test import equal import gpaw.mpi as mpi import numpy as np comms = [mpi.world.new_communicator(np.array([r])) for r in range(mpi.size)] comm = comms[mpi.rank] Hnospin = Atoms([Atom('H')], cell=[5, 5, 5], pbc=False) Hspin = Atoms([Atom('H', magmom=1)], cell=[5, 5, 5], pbc=False) LiH = Atoms([Atom('Li', [.0, .0, .41]), Atom('H', [.0, .0, -1.23])]) Hnospin.center() Hspin.center() LiH.center(vacuum=3.0) # This is needed for the Wigner-Seitz test to give # architecture-independent results: LiH.translate(0.003234) calc = GPAW(gpts=(24, 24, 24), communicator=comm) Hnospin.set_calculator(calc) e_Hnospin = Hnospin.get_potential_energy() niter_Hnospin = calc.get_number_of_iterations() energies, sweight = raw_orbital_LDOS(calc, a=0, spin=0, angular='s') energies, pdfweight = raw_orbital_LDOS(calc, a=0, spin=0, angular='pdf') calc = GPAW(gpts=(24, 24, 24), occupations=FermiDirac(width=0, fixmagmom=True), hund=True, communicator=comm) Hspin.set_calculator(calc) e_Hspin = Hspin.get_potential_energy() niter_Hspin = calc.get_number_of_iterations() energies,sweight_spin = raw_orbital_LDOS(calc, a=0, spin=0, angular='s') calc = GPAW(gpts=(32, 32, 40), nbands=2, #eigensolver='dav', communicator=comm) LiH.set_calculator(calc) e_LiH = LiH.get_potential_energy() niter_LiH = calc.get_number_of_iterations() energies, Li_orbitalweight = raw_orbital_LDOS(calc, a=0, spin=0, angular=None) energies, H_orbitalweight = raw_orbital_LDOS(calc, a=1, spin=0, angular=None) energies, Li_wzweight = raw_wignerseitz_LDOS(calc, a=0, spin=0) energies, H_wzweight = raw_wignerseitz_LDOS(calc, a=1, spin=0) n_a = calc.get_wigner_seitz_densities(spin=0) print(sweight, pdfweight) print(sweight_spin) print(Li_wzweight) print(H_wzweight) print(n_a) equal(sweight[0], 1., .06) equal(pdfweight[0], 0., .0001) equal(sweight_spin[0], 1.14, .06) assert ((Li_wzweight - [.13, .93]).round(2) == 0).all() assert ((H_wzweight - [.87, .07]).round(2) == 0).all() assert ((Li_wzweight + H_wzweight).round(5) == 1).all() equal(n_a.sum(), 0., 1e-5) equal(n_a[1], .737, .001) print(Li_orbitalweight) print(H_orbitalweight) # HOMO s py pz px *s Li_orbitalweight[0] -= [.5, .0, .6, .0, .0] H_orbitalweight[0] -= [.7, .0, .0, .0, .0] # LUMO s py pz px *s Li_orbitalweight[1] -= [1.0, .0, 0.9, .0, .0] H_orbitalweight[1] -= [0.1, .0, 0.0, .0, .0] assert not Li_orbitalweight.round(1).any() assert not H_orbitalweight.round(1).any() ldos = RawLDOS(calc) fname = 'ldbe.dat' ldos.by_element_to_file(fname, shift=False) ldos.by_element_to_file(fname, 2.0, shift=False) energy_tolerance = 0.00006 niter_tolerance = 0 equal(e_Hnospin, 0.153991, energy_tolerance) equal(e_Hspin, -0.782309, energy_tolerance) equal(e_LiH, -3.74582, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/pes.py0000664000175000017500000000367212553643471016543 0ustar jensjjensj00000000000000from ase import Atom, Atoms from gpaw import GPAW, mpi from gpaw.test import equal from gpaw.lrtddft import LrTDDFT from gpaw.pes.dos import DOSPES from gpaw.pes.tddft import TDDFTPES txt = None R=0.7 # approx. experimental bond length a = 3.0 c = 3.0 h = .3 H2 = Atoms([Atom('H', (a / 2, a / 2, (c - R) / 2)), Atom('H', (a / 2, a / 2, (c + R) / 2))], cell=(a, a, c)) H2_plus = Atoms([Atom('H', (a / 2, a / 2, (c - R) / 2)), Atom('H', (a / 2, a / 2, (c + R) / 2))], cell=(a, a, c)) xc='LDA' calc = GPAW(gpts=(12, 12, 12), xc=xc, nbands=1, parallel={'domain': mpi.world.size}, spinpol=True, txt=txt) H2.set_calculator(calc) e_H2 = H2.get_potential_energy() niter_H2 = calc.get_number_of_iterations() calc_plus = GPAW(gpts=(12, 12, 12), xc=xc, nbands=2, parallel={'domain': mpi.world.size}, spinpol=True, txt=txt) calc_plus.set(charge=+1) H2_plus.set_calculator(calc_plus) e_H2_plus = H2_plus.get_potential_energy() niter_H2_plus = calc.get_number_of_iterations() out = 'dospes.dat' pes = DOSPES(calc, calc_plus, shift=True) pes.save_folded_pes(filename=out, folding=None) pes.save_folded_pes(filename=None, folding=None) # check for correct shift VDE = calc_plus.get_potential_energy() - calc.get_potential_energy() BE_HOMO = 1.e23 be_n, f_n = pes.get_energies_and_weights() for be, f in zip(be_n, f_n): if f > 0.1 and be < BE_HOMO: BE_HOMO = be equal(BE_HOMO, VDE) lr = LrTDDFT(calc_plus, xc=xc) out = 'lrpes.dat' pes = TDDFTPES(calc, lr) pes.save_folded_pes(filename=out, folding='Gauss') pes.save_folded_pes(filename=None, folding=None) energy_tolerance = 0.0001 niter_tolerance = 1 equal(e_H2, -3.90059, energy_tolerance) equal(e_H2_plus, 10.5659703, energy_tolerance) # io out = 'lrpes.dat.gz' lr.write(out) lr = LrTDDFT(out) lr.set_calculator(calc_plus) pes = TDDFTPES(calc, lr) pes.save_folded_pes(filename=None, folding=None) gpaw-0.11.0.13004/gpaw/test/rpa_energy_Si.py0000664000175000017500000000133012553643471020527 0ustar jensjjensj00000000000000from ase.lattice import bulk from gpaw import GPAW, FermiDirac from gpaw.mpi import serial_comm from gpaw.test import equal from gpaw.xc.rpa import RPACorrelation a0 = 5.43 Si = bulk('Si', a=a0) calc = GPAW(mode='pw', kpts={'size': (2, 2, 2), 'gamma': True}, occupations=FermiDirac(0.001), communicator=serial_comm) Si.set_calculator(calc) E = Si.get_potential_energy() calc.diagonalize_full_hamiltonian(nbands=50) ecut = 50 rpa = RPACorrelation(calc, qsym=False, nfrequencies=8) E_rpa_noqsym = rpa.calculate(ecut=[ecut]) rpa = RPACorrelation(calc, qsym=True, nfrequencies=8) E_rpa_qsym = rpa.calculate(ecut=[ecut]) print(E_rpa_qsym, E_rpa_noqsym, 0.001) equal(E_rpa_qsym, -12.61, 0.01) gpaw-0.11.0.13004/gpaw/test/aluminum_EELS.py0000664000175000017500000000432012553643472020403 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np import sys import os import time from ase.units import Bohr from ase.lattice import bulk from ase.utils import devnull from gpaw import GPAW, PW from gpaw.test import findpeak from gpaw.eigensolvers.rmm_diis_old import RMM_DIIS from gpaw.mixer import Mixer from gpaw.atom.basis import BasisMaker from gpaw.response.df import DielectricFunction from gpaw.mpi import serial_comm, rank, size from gpaw.wavefunctions.pw import PW if rank != 0: sys.stdout = devnull assert size <= 4**3 # Ground state calculation t1 = time.time() a = 4.043 atoms = bulk('Al', 'fcc', a=a) atoms.center() calc = GPAW(mode=PW(200), eigensolver=RMM_DIIS(), mixer=Mixer(0.1,3), kpts=(4,4,4), parallel={'band':1}, idiotproof=False, # allow uneven distribution of k-points xc='LDA') atoms.set_calculator(calc) atoms.get_potential_energy() t2 = time.time() # Excited state calculation q = np.array([1/4.,0.,0.]) w = np.linspace(0, 24, 241) df = DielectricFunction(calc=calc, frequencies=w, eta=0.2, ecut=50) eels_NLFC_w, eels_LFC_w = df.get_eels_spectrum(filename='EELS_Al', q_c=q) df_NLFC_w, df_LFC_w = df.get_dielectric_function(q_c=q) df.check_sum_rule(spectrum=np.imag(df_NLFC_w)) df.check_sum_rule(spectrum=np.imag(df_LFC_w)) df.check_sum_rule(spectrum=eels_NLFC_w) df.check_sum_rule(spectrum=eels_LFC_w) #df.write('Al.pckl') t3 = time.time() print('') print('For ground state calc, it took', (t2 - t1) / 60, 'minutes') print('For excited state calc, it took', (t3 - t2) / 60, 'minutes') d = np.loadtxt('EELS_Al',delimiter=',') # New results are compared with test values wpeak1,Ipeak1 = findpeak(d[:,0],d[:,1]) wpeak2,Ipeak2 = findpeak(d[:,0],d[:,2]) test_wpeak1 = 15.70 # eV test_Ipeak1 = 29.05 # eV test_wpeak2 = 15.725 # eV test_Ipeak2 = 26.41 # eV if np.abs(test_wpeak1-wpeak1)<1e-2 and np.abs(test_wpeak2-wpeak2)<1e-2: pass else: print(test_wpeak1-wpeak1,test_wpeak2-wpeak2) raise ValueError('Plasmon peak not correct ! ') if np.abs(test_Ipeak1-Ipeak1)>1e-2 or np.abs(test_Ipeak2-Ipeak2)>1e-2: print(Ipeak1-test_Ipeak1, Ipeak2-test_Ipeak2) raise ValueError('Please check spectrum strength ! ') gpaw-0.11.0.13004/gpaw/test/scipy_test.py0000664000175000017500000000067212553643472020140 0ustar jensjjensj00000000000000from __future__ import print_function import sys from scipy import test from gpaw.mpi import rank _stdout = sys.stdout _stderr = sys.stderr # scipy tests write to stderr sys.stderr = open("scipy_test%02d.out" % rank, "w") result = test(verbose=10) sys.stdout = _stdout sys.stderr = _stderr if not result.wasSuccessful(): print("scipy_test%02d.out" % rank, result.errors, result.failures, file=sys.stderr) assert result.wasSuccessful() gpaw-0.11.0.13004/gpaw/test/restart.py0000664000175000017500000000371512553643472017437 0ustar jensjjensj00000000000000from __future__ import print_function import os from gpaw import GPAW, restart from ase import Atoms from gpaw.test import equal from math import sqrt import numpy as np modes = ['gpw'] try: import _gpaw_hdf5 modes.append('hdf5') except ImportError: pass d = 3.0 atoms = Atoms('Na3', positions=[( 0, 0, 0), ( 0, 0, d), ( 0, d*sqrt(3./4.), d/2.)], magmoms=[1.0, 1.0, 1.0], cell=(3.5, 3.5, 4.+2/3.), pbc=True) # Only a short, non-converged calcuation conv = {'eigenstates': 1.24, 'energy':2e-1, 'density':1e-1} calc = GPAW(h=0.30, nbands=3, setups={'Na': '1'}, convergence=conv) atoms.set_calculator(calc) e0 = atoms.get_potential_energy() niter0 = calc.get_number_of_iterations() f0 = atoms.get_forces() m0 = atoms.get_magnetic_moments() eig00 = calc.get_eigenvalues(spin=0) eig01 = calc.get_eigenvalues(spin=1) # Write the restart file(s) for mode in modes: calc.write('tmp.%s' % mode) del atoms, calc # Try restarting from all the files for mode in modes: atoms, calc = restart('tmp.%s' % mode) e1 = atoms.get_potential_energy() try: # number of iterations needed in restart niter1 = calc.get_number_of_iterations() except: pass f1 = atoms.get_forces() m1 = atoms.get_magnetic_moments() eig10 = calc.get_eigenvalues(spin=0) eig11 = calc.get_eigenvalues(spin=1) print(e0, e1) equal(e0, e1, 1e-10) print(f0, f1) for ff0, ff1 in zip(f0, f1): err = np.linalg.norm(ff0-ff1) assert err <= 1e-10 print(m0, m1) for mm0, mm1 in zip(m0, m1): equal(mm0, mm1, 1e-10) print('A',eig00, eig10) for eig0, eig1 in zip(eig00, eig10): equal(eig0, eig1, 1e-10) print('B',eig01, eig11) for eig0, eig1 in zip(eig01, eig11): equal(eig0, eig1, 1e-10) # Check that after restart everything is writable calc.write('tmp2.%s' % mode) gpaw-0.11.0.13004/gpaw/test/gauss_wave.py0000664000175000017500000001224012553643471020107 0ustar jensjjensj00000000000000from __future__ import print_function import time import numpy as np from gpaw.utilities.gauss import gaussian_wave sigma = 2.4 C = 3 G = 50 t = time.time() r_cG = np.random.normal(size=C*G**3).reshape((C,G,G,G)) r0_c = np.random.normal(size=C) k_c = np.random.normal(size=C) A = np.random.uniform()*np.exp(1j*np.random.uniform(0,2*np.pi)) print('Allocation: %8.5f s' % (time.time()-t)) # ------------------------------------------------------------------- # Test case for real-part of gamma-point wave with normalized amplitude _gaussRGN = lambda r_cG, r0_c, sigma: 1/(sigma*np.pi**0.5)**1.5 \ * np.exp(-np.sum((r_cG-r0_c[:,np.newaxis,np.newaxis,np.newaxis])**2, axis=0)/(2*sigma**2)) t = time.time() gs0_G = _gaussRGN(r_cG, r0_c, sigma) print('_gaussRGN: %8.5f s' % (time.time()-t)) t = time.time() gs1_G = gaussian_wave(r_cG, r0_c, sigma) print('+gaussRGN: %8.5f s' % (time.time()-t)) assert np.abs(gs0_G-gs1_G).max() < 1e-12, 'Max error %g' % np.abs(gs0_G-gs1_G).max() del gs0_G, gs1_G # Test case for real-part of gamma-point wave with complex amplitude _gaussRGA = lambda r_cG, r0_c, sigma, A: np.real(A) \ * np.exp(-np.sum((r_cG-r0_c[:,np.newaxis,np.newaxis,np.newaxis])**2, axis=0)/(2*sigma**2)) t = time.time() gs0_G = _gaussRGA(r_cG, r0_c, sigma, A) print('_gaussRGA: %8.5f s' % (time.time()-t)) t = time.time() gs1_G = gaussian_wave(r_cG, r0_c, sigma, None, A) print('+gaussRGA: %8.5f s' % (time.time()-t)) assert np.abs(gs0_G-gs1_G).max() < 1e-12, 'Max error %g' % np.abs(gs0_G-gs1_G).max() del gs0_G, gs1_G # Test case for real-part of kpoint-point wave with normalized amplitude _gaussRKN = lambda r_cG, r0_c, sigma, k_c: 1/(sigma*np.pi**0.5)**1.5 \ * np.exp(-np.sum((r_cG-r0_c[:,np.newaxis,np.newaxis,np.newaxis])**2, axis=0)/(2*sigma**2)) \ * np.cos(np.sum(r_cG*k_c[:,np.newaxis,np.newaxis,np.newaxis], axis=0)) t = time.time() gs0_G = _gaussRKN(r_cG, r0_c, sigma, k_c) print('_gaussRKN: %8.5f s' % (time.time()-t)) t = time.time() gs1_G = gaussian_wave(r_cG, r0_c, sigma, k_c) print('+gaussRKN: %8.5f s' % (time.time()-t)) assert np.abs(gs0_G-gs1_G).max() < 1e-12, 'Max error %g' % np.abs(gs0_G-gs1_G).max() del gs0_G, gs1_G # Test case for real-part of kpoint-point wave with complex amplitude _gaussRKA = lambda r_cG, r0_c, sigma, k_c, A: \ np.exp(-np.sum((r_cG-r0_c[:,np.newaxis,np.newaxis,np.newaxis])**2, axis=0)/(2*sigma**2)) \ * np.real(A*np.exp(1j*np.sum(r_cG*k_c[:,np.newaxis,np.newaxis,np.newaxis], axis=0))) t = time.time() gs0_G = _gaussRKA(r_cG, r0_c, sigma, k_c, A) print('_gaussRKA: %8.5f s' % (time.time()-t)) t = time.time() gs1_G = gaussian_wave(r_cG, r0_c, sigma, k_c, A) print('+gaussRKA: %8.5f s' % (time.time()-t)) assert np.abs(gs0_G-gs1_G).max() < 1e-12, 'Max error %g' % np.abs(gs0_G-gs1_G).max() del gs0_G, gs1_G # ------------------------------------------------------------------- # Test case for complex case of gamma-point wave with normalized amplitude _gaussCGN = lambda r_cG, r0_c, sigma: (1+0j)/(sigma*np.pi**0.5)**1.5 \ * np.exp(-np.sum((r_cG-r0_c[:,np.newaxis,np.newaxis,np.newaxis])**2, axis=0)/(2*sigma**2)) t = time.time() gs0_G = _gaussCGN(r_cG, r0_c, sigma) print('_gaussCGN: %8.5f s' % (time.time()-t)) t = time.time() gs1_G = gaussian_wave(r_cG, r0_c, sigma, dtype=complex) print('+gaussCGN: %8.5f s' % (time.time()-t)) assert np.abs(gs0_G-gs1_G).max() < 1e-12, 'Max error %g' % np.abs(gs0_G-gs1_G).max() del gs0_G, gs1_G # Test case for complex case of gamma-point wave with complex amplitude _gaussCGA = lambda r_cG, r0_c, sigma, A: A \ * np.exp(-np.sum((r_cG-r0_c[:,np.newaxis,np.newaxis,np.newaxis])**2, axis=0)/(2*sigma**2)) t = time.time() gs0_G = _gaussCGA(r_cG, r0_c, sigma, A) print('_gaussCGA: %8.5f s' % (time.time()-t)) t = time.time() gs1_G = gaussian_wave(r_cG, r0_c, sigma, None, A, dtype=complex) print('+gaussCGA: %8.5f s' % (time.time()-t)) assert np.abs(gs0_G-gs1_G).max() < 1e-12, 'Max error %g' % np.abs(gs0_G-gs1_G).max() del gs0_G, gs1_G # Test case for complex case of kpoint-point wave with normalized amplitude _gaussCKN = lambda r_cG, r0_c, sigma, k_c: (1+0j)/(sigma*np.pi**0.5)**1.5 \ * np.exp(-np.sum((r_cG-r0_c[:,np.newaxis,np.newaxis,np.newaxis])**2, axis=0)/(2*sigma**2)) \ * np.exp(1j*np.sum(r_cG*k_c[:,np.newaxis,np.newaxis,np.newaxis], axis=0)) t = time.time() gs0_G = _gaussCKN(r_cG, r0_c, sigma, k_c) print('_gaussCKN: %8.5f s' % (time.time()-t)) t = time.time() gs1_G = gaussian_wave(r_cG, r0_c, sigma, k_c, dtype=complex) print('+gaussCKN: %8.5f s' % (time.time()-t)) assert np.abs(gs0_G-gs1_G).max() < 1e-12, 'Max error %g' % np.abs(gs0_G-gs1_G).max() del gs0_G, gs1_G # Test case for complex case of kpoint-point wave with complex amplitude _gaussCKA = lambda r_cG, r0_c, sigma, k_c, A: A \ * np.exp(-np.sum((r_cG-r0_c[:,np.newaxis,np.newaxis,np.newaxis])**2, axis=0)/(2*sigma**2)) \ * np.exp(1j*np.sum(r_cG*k_c[:,np.newaxis,np.newaxis,np.newaxis], axis=0)) t = time.time() gs0_G = _gaussCKA(r_cG, r0_c, sigma, k_c, A) print('_gaussCKA: %8.5f s' % (time.time()-t)) t = time.time() gs1_G = gaussian_wave(r_cG, r0_c, sigma, k_c, A, dtype=complex) print('+gaussCKA: %8.5f s' % (time.time()-t)) assert np.abs(gs0_G-gs1_G).max() < 1e-12, 'Max error %g' % np.abs(gs0_G-gs1_G).max() del gs0_G, gs1_G gpaw-0.11.0.13004/gpaw/test/mgga_restart.py0000664000175000017500000000251512553643471020426 0ustar jensjjensj00000000000000from __future__ import print_function import os import sys from ase import Atom from gpaw import GPAW from gpaw.cluster import Cluster from gpaw.test import equal fname='H2_PBE.gpw' fwfname='H2_wf_PBE.gpw' txt = None # write first if needed try: c = GPAW(fname, txt=txt) c = GPAW(fwfname, txt=txt) except: s = Cluster([Atom('H'), Atom('H', [0,0,1])]) s.minimal_box(3.) c = GPAW(xc='PBE', h=.3, convergence={'density':1e-4, 'eigenstates':1e-6}) c.calculate(s) c.write(fname) c.write(fwfname, 'all') # full information c = GPAW(fwfname, txt=txt) E_PBE = c.get_potential_energy() try: # number of iterations needed in restart niter_PBE = c.get_number_of_iterations() except: pass dE = c.get_xc_difference('TPSS') E_1 = E_PBE + dE print("E PBE, TPSS=", E_PBE, E_1) # no wfs c = GPAW(fname, txt=txt) E_PBE_no_wfs = c.get_potential_energy() try: # number of iterations needed in restart niter_PBE_no_wfs = c.get_number_of_iterations() except: pass dE = c.get_xc_difference('TPSS') E_2 = E_PBE_no_wfs + dE print("E PBE, TPSS=", E_PBE_no_wfs, E_2) print("diff=", E_1 - E_2) assert abs(E_1 - E_2) < 0.005 energy_tolerance = 0.00008 niter_tolerance = 0 equal(E_PBE, -5.33901, energy_tolerance) equal(E_PBE_no_wfs, -5.33901, energy_tolerance) equal(E_1, -5.57685, energy_tolerance) equal(E_2, -5.57685, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/bse_vs_lrtddft.py0000664000175000017500000000305112553643471020747 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from ase import Atom, Atoms from ase.units import Hartree from gpaw.mpi import size from gpaw import GPAW from gpaw.response.bse import BSE GS = 1 bse = 1 casida = 1 compare = 1 if GS: d = 2.89 cluster = Atoms([Atom('Na', (0, 0, 0)), Atom('Na', (0, 0, d)), ], pbc=True) cluster.set_cell((15.,15.,18.), scale_atoms=False) cluster.center() calc = GPAW(h=0.3, nbands=8, setups={'Na': '1'}) cluster.set_calculator(calc) cluster.get_potential_energy() calc.write('Na2.gpw','all') if bse: bse = BSE('Na2.gpw', w=np.linspace(0,15,151), nv=[0,8], nc=[0,8], mode='RPA', coupling=True, q=np.array([0,0,0.0001]), optical_limit=True, ecut=50., nbands=8) bse.initialize() H_SS = bse.calculate() bse.diagonalize(H_SS) w = np.real(bse.w_S) * Hartree print(np.shape(w)) energies = np.sort(w)[len(w)/2:] print('BSE:', energies) if casida: from gpaw.lrtddft import LrTDDFT from gpaw.lrtddft import photoabsorption_spectrum calc = GPAW('Na2.gpw',txt=None) lr = LrTDDFT(calc, xc=None, istart=0, jend=7, nspins=1) lr.diagonalize() photoabsorption_spectrum(lr, 'Na2_spectrum.dat', width=0.05) energies_lrtddft = lr.get_energies() * Hartree print('lrTDDFT:', energies_lrtddft) if compare: assert (np.abs(energies - energies_lrtddft)).max() < 3*1e-3 gpaw-0.11.0.13004/gpaw/test/gd.py0000664000175000017500000000024112553643471016333 0ustar jensjjensj00000000000000from gpaw.grid_descriptor import GridDescriptor gd = GridDescriptor([4, 4, 4]) a = gd.empty(dtype=complex) a[:] = 1.0 assert gd.integrate(a.real, a.real) == 1.0 gpaw-0.11.0.13004/gpaw/test/stark_shift.py0000664000175000017500000001475012553643471020274 0ustar jensjjensj00000000000000from __future__ import print_function import sys from math import sqrt, pi import numpy as np from ase import Atoms from ase.units import Bohr, Hartree from ase.parallel import rank, size from gpaw import GPAW from gpaw.external_potential import ConstantElectricField from gpaw.point_charges import PointCharges from gpaw.utilities import packed_index from gpaw.pair_density import PairDensity # Three ways to compute the polarizability of hydrogen: # 1. Perturbation theory # 2. Constant electric field # 3. Middle of an electric dipole # Note: The analytical value for the polarizability # is 4.5 a0**3 (e.g. PRA 33, 3671), while the experimental # value is 4.6 a0**3 (e.g. PR 133, A629). ### to_au = Hartree / Bohr**2 to_eVA = Hartree / Bohr ### def dipole_op(c, state1, state2, k=0, s=0): # Taken from KSSingle, maybe make this accessible in # KSSingle? wfs = c.wfs gd = wfs.gd kpt = None for i in wfs.kpt_u: if i.k == k and i.s == s: kpt = i pd = PairDensity(c) pd.initialize(kpt, state1, state2) # coarse grid contribution # is the negative of the dipole moment (because of negative # e- charge) me = -gd.calculate_dipole_moment(pd.get()) # augmentation contributions ma = np.zeros(me.shape) pos_av = c.get_atoms().get_positions() / Bohr for a, P_ni in kpt.P_ani.items(): Ra = pos_av[a] Pi_i = P_ni[state1] Pj_i = P_ni[state2] Delta_pL = wfs.setups[a].Delta_pL ni = len(Pi_i) ma0 = 0 ma1 = np.zeros(me.shape) for i in range(ni): for j in range(ni): pij = Pi_i[i]*Pj_i[j] ij = packed_index(i, j, ni) # L=0 term ma0 += Delta_pL[ij,0]*pij # L=1 terms if wfs.setups[a].lmax >= 1: # see spherical_harmonics.py for # L=1:y L=2:z; L=3:x ma1 += np.array([Delta_pL[ij,3], Delta_pL[ij,1], Delta_pL[ij,2]]) * pij ma += sqrt(4 * pi / 3) * ma1 + Ra * sqrt(4 * pi) * ma0 gd.comm.sum(ma) me += ma return me * Bohr # Currently only works on a single processor assert size == 1 maxfield = 0.01 nfs = 5 # number of field nbands = 30 # number of bands h = 0.20 # grid spacing debug = not False if debug: txt = 'gpaw.out' else: txt = None ### test1 = True test2 = True test3 = True ### a0 = 6.0 a = Atoms('H', positions=[[a0 / 2, a0 / 2, a0 / 2 ]], cell=[ a0, a0, a0 ]) ### alpha1 = None alpha2 = None alpha3 = None # Test 1 if test1: c = GPAW( h=h, width=0.00, nbands=nbands+10, spinpol=True, hund=True, xc='LDA', eigensolver='cg', convergence={'bands': nbands, 'eigenstates': 3.3e-4}, maxiter= 1000, txt= txt ) a.set_calculator(c) a.get_potential_energy() o1 = c.get_occupation_numbers(spin=0) if o1[0] > 0.0: spin = 0 else: spin = 1 alpha = 0.0 ev = c.get_eigenvalues(0, spin) gd = c.wfs.gd for i in range(1, nbands): mu_x, mu_y, mu_z = dipole_op(c, 0, i, k=0, s=spin) alpha += mu_z**2 / (ev[i] - ev[0]) alpha *= 2 if rank == 0 and debug: print('From perturbation theory:') print(' alpha = ', alpha, ' A**2/eV') print(' alpha = ', alpha*to_au, ' Bohr**3') alpha1 = alpha ### c = GPAW( h = h, width = 0.00, nbands = 2, spinpol = True, hund = True, xc = 'LDA', #eigensolver = 'cg', convergence = {'bands': nbands, 'eigenstates': 3.3e-4}, maxiter = 1000, txt = txt ) a.set_calculator(c) # Test 2 if test2: e = [ ] e1s = [ ] d = [ ] fields = np.linspace(-maxfield, maxfield, nfs) for field in fields: if rank == 0 and debug: print(field) c.set( external = ConstantElectricField(field * Bohr/Hartree), ) etot = a.get_potential_energy() e += [ etot ] ev0 = c.get_eigenvalues(0) ev1 = c.get_eigenvalues(1) e1s += [ min( ev0[0], ev1[0] ) ] dip = c.get_dipole_moment() d += [ dip[2] ] pol1, dummy = np.polyfit(fields, d, 1) pol2, dummy1, dummy2 = np.polyfit(fields, e1s, 2) if rank == 0 and debug: print('From shift in 1s-state at constant electric field:') print(' alpha = ', -pol2, ' A**2/eV') print(' alpha = ', -pol2*to_au, ' Bohr**3') print('From dipole moment at constant electric field:') print(' alpha = ', pol1, ' A**2/eV') print(' alpha = ', pol1*to_au, ' Bohr**3') np.savetxt('ecf.out', np.transpose( [ fields, e, e1s, d ] )) assert abs(pol1+pol2) < 0.0001 alpha2 = (pol1-pol2)/2 # Test 3 if test3: pcd = 1000.0 # distance of the two point charges maxcharge = 100.0 # maximum charge on the point charge e = [ ] e1s = [ ] d = [ ] charges = np.linspace(-maxcharge, maxcharge, nfs) fields = [ ] for charge in charges: ex = PointCharges( positions = [ [ a0/2, a0/2, -pcd/2+a0/2 ], [ a0/2, a0/2, pcd/2+a0/2 ] ], charges = [ charge, -charge ] ) c.set( external = ex ) etot = a.get_potential_energy() e += [ etot ] ev0 = c.get_eigenvalues(0) ev1 = c.get_eigenvalues(1) e1s += [ min( ev0[0], ev1[0] ) ] dip = c.get_dipole_moment() d += [ dip[2] ] field = ex.get_taylor(position=a[0].position)[1][1] if rank == 0 and debug: print(field*to_eVA, 2*charge/((pcd/2)**2)*Hartree*Bohr) fields += [ field*to_eVA ] pol1, dummy = np.polyfit(fields, d, 1) pol2, dummy1, dummy2 = np.polyfit(fields, e1s, 2) if rank == 0 and debug: print('From shift in 1s-state between two point charges:') print(' alpha = ', -pol2, ' A**2/eV') print(' alpha = ', -pol2*to_au, ' Bohr**3') #print 'From dipole moment between two point charges:' #print ' alpha = ', pol1, ' A**2/eV' #print ' alpha = ', pol1*to_au, ' Bohr**3' np.savetxt('epc.out', np.transpose( [ fields, e, e1s, d ] )) alpha3 = alpha # This is a very, very rough test assert abs(alpha1-alpha2) < 0.01 assert abs(alpha3-alpha2) < 0.01 gpaw-0.11.0.13004/gpaw/test/force_as_stop.py0000664000175000017500000000057412553643471020600 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW H2 = Atoms('H2', positions=[(0, 0, 0), (1, 0, 0)]) H2.set_cell((3, 3.1, 3.2)) H2.center() calc = GPAW(convergence={'forces': 1e-8, 'density': 100, 'energy': 100, 'eigenstates': 100}) H2.set_calculator(calc) H2.get_potential_energy() assert 17 < calc.iter < 19 gpaw-0.11.0.13004/gpaw/test/test_ibzqpt.py0000664000175000017500000000145012553643472020315 0ustar jensjjensj00000000000000import numpy as np from ase.lattice import bulk from ase.units import Hartree, Bohr from gpaw import GPAW, FermiDirac from ase.dft.kpoints import monkhorst_pack for kpt in (3, 4): kpts = (kpt, kpt, kpt) bzk_kc = monkhorst_pack(kpts) shift_c = [] for Nk in kpts: if Nk % 2 == 0: shift_c.append(0.5 / Nk) else: shift_c.append(0.) bzk_kc += shift_c atoms = bulk('Si', 'diamond', a=5.431) calc = GPAW(h=0.2, kpts=bzk_kc) atoms.set_calculator(calc) atoms.get_potential_energy() kd = calc.wfs.kd bzq_qc = kd.get_bz_q_points() ibzq_qc = kd.get_ibz_q_points(bzq_qc, calc.wfs.kd.symmetry.op_scc)[0] assert np.abs(bzq_qc - kd.bzk_kc).sum() < 1e-8 assert np.abs(ibzq_qc - kd.ibzk_kc).sum() < 1e-8 gpaw-0.11.0.13004/gpaw/test/gradient.py0000664000175000017500000000341612553643472017546 0ustar jensjjensj00000000000000from __future__ import print_function from gpaw.fd_operators import Gradient import numpy as np from gpaw.grid_descriptor import GridDescriptor from gpaw.mpi import world if world.size > 4: # Grid is so small that domain decomposition cannot exceed 4 domains assert world.size % 4 == 0 group, other = divmod(world.rank, 4) ranks = np.arange(4*group, 4*(group+1)) domain_comm = world.new_communicator(ranks) else: domain_comm = world gd = GridDescriptor((8, 1, 1), (8.0, 1.0, 1.0), comm=domain_comm) a = gd.zeros() dadx = gd.zeros() a[:, 0, 0] = np.arange(gd.beg_c[0], gd.end_c[0]) gradx = Gradient(gd, v=0) print(a.itemsize, a.dtype, a.shape) print(dadx.itemsize, dadx.dtype, dadx.shape) gradx.apply(a, dadx) # a = [ 0. 1. 2. 3. 4. 5. 6. 7.] # # da # -- = [-2.5 1. 1. 1. 1. 1. 1. -2.5] # dx dadx = gd.collect(dadx, broadcast=True) assert dadx[3, 0, 0] == 1.0 and np.sum(dadx[:, 0, 0]) == 0.0 gd = GridDescriptor((1, 8, 1), (1.0, 8.0, 1.0), (1, 0, 1), comm=domain_comm) dady = gd.zeros() a = gd.zeros() grady = Gradient(gd, v=1) a[0, :, 0] = np.arange(gd.beg_c[1], gd.end_c[1]) - 1 grady.apply(a, dady) # da # -- = [0.5 1. 1. 1. 1. 1. -2.5] # dy dady = gd.collect(dady, broadcast=True) assert dady[0, 0, 0] == 0.5 and np.sum(dady[0, :, 0]) == 3.0 # a GUC cell gd = GridDescriptor((1, 7, 1), ((1.0, 0.0, 0.0), (5.0, 5.0, 0.0), (0.0, 0.0, 0.7)), comm=domain_comm) dady = gd.zeros() grady = Gradient(gd, v=1) a = gd.zeros() a[0, :, 0] = np.arange(gd.beg_c[1], gd.end_c[1]) - 1 grady.apply(a, dady) # da # -- = [-3.5 1.4 1.4 1.4 1.4 1.4 -3.5] # dy dady = gd.collect(dady, broadcast=True) assert dady[0, 0, 0] == -3.5 and abs(np.sum(dady[0, :, 0])) < 1E-12 gpaw-0.11.0.13004/gpaw/test/complex.py0000664000175000017500000000265212553643471017420 0ustar jensjjensj00000000000000from __future__ import print_function from gpaw import GPAW, restart from ase.structure import molecule from gpaw.test import equal Eini0 = -17.7436014436 Iini0 = 12 esolvers = ['cg', 'rmm-diis', 'dav'] E0 = {'cg': -17.7439210822, 'rmm-diis': -17.7439094546, 'dav': -17.7439760796} I0 = {'cg': 6, 'rmm-diis': 6, 'dav': 8} calc = GPAW(xc='LDA', eigensolver='cg', convergence={'eigenstates': 3.5e-5}, #txt=None, dtype=complex) mol = molecule('N2') mol.center(vacuum=3.0) mol.set_calculator(calc) Eini = mol.get_potential_energy() Iini = calc.get_number_of_iterations() print(('%10s: %12.6f eV in %3d iterations' % ('init(cg)', Eini, Iini))) equal(Eini, Eini0, 1E-8) calc.write('N2_complex.gpw', mode='all') del calc, mol E = {} I = {} for esolver in esolvers: mol, calc = restart('N2_complex.gpw', txt=None) if (calc.wfs.dtype!=complex or calc.wfs.kpt_u[0].psit_nG.dtype!=complex): raise AssertionError('ERROR: restart failed to read complex WFS') calc.scf.reset() calc.set(convergence={'eigenstates': 3.5e-9}) calc.set(eigensolver=esolver) E[esolver]=mol.get_potential_energy() I[esolver]=calc.get_number_of_iterations() print(('%10s: %12.6f eV in %3d iterations' % (esolver, E[esolver], I[esolver]))) for esolver in esolvers: print(esolver) equal(E[esolver], E0[esolver], 8E-5) gpaw-0.11.0.13004/gpaw/test/external_potential.py0000664000175000017500000000506612553643471021654 0ustar jensjjensj00000000000000from __future__ import print_function import os import sys from ase import Atom, Atoms from ase.units import Bohr, Hartree from ase.io.cube import write_cube from gpaw import GPAW from gpaw.test import equal from gpaw.cluster import Cluster from gpaw.point_charges import PointCharges from gpaw.external_potential import ConstantPotential from gpaw.mpi import world cp = ConstantPotential() sc = 2.9 R=0.7 # approx. experimental bond length R=1. a = 2 * sc c = 3 * sc at='H' H2 = Atoms([Atom(at, (a/2, a/2, (c-R)/2)), Atom(at, (a/2, a/2, (c+R)/2))], cell=(a,a,c), pbc=False) print(at, 'dimer') nelectrons = 2 * H2[0].number txt = None #txt = '-' # load point charges fname = 'pc.xyz' if world.rank == 0: f = open('i' + fname, 'w') print("""1 X 0 0 100 -0.5""", file=f) f.close() world.barrier() ex = PointCharges() ex.read('i' + fname) ex.write('o' + fname) convergence = {'eigenstates':1.e-4*40*1.5**3, 'density':1.e-2, 'energy':0.1} # without potential if True: if txt: print('\n################## no potential') c00 = GPAW(h=0.3, nbands=-1, convergence=convergence, txt=txt) c00.calculate(H2) eps00_n = c00.get_eigenvalues() # 0 potential if True: if txt: print('\n################## 0 potential') cp0 = ConstantPotential(0.0) c01 = GPAW(h=0.3, nbands=-2, external=cp0, convergence=convergence, txt=txt) c01.calculate(H2) # 1 potential if True: if txt: print('################## 1 potential') cp1 = ConstantPotential(-1.0/Hartree) c1 = GPAW(h=0.3, nbands=-2, external=cp1, convergence=convergence, txt=txt) c1.calculate(H2) for i in range(c00.get_number_of_bands()): f00 = c00.get_occupation_numbers()[i] if f00 > 0.01: e00 = c00.get_eigenvalues()[i] e1 = c1.get_eigenvalues()[i] print('Eigenvalues no pot, expected, error=', e00, e1 + 1, e00 - e1 - 1) equal(e00, e1 + 1., 0.007) E_c00 = c00.get_potential_energy() niter_c00 = c00.get_number_of_iterations() E_c1 = c1.get_potential_energy() niter_c1 = c1.get_number_of_iterations() DeltaE = E_c00 - E_c1 print('Energy diff, expected, error=', DeltaE, nelectrons, DeltaE - nelectrons) equal(DeltaE, nelectrons, 0.002) energy_tolerance = 0.00001 niter_tolerance = 0 #equal(E_c00, 10.4409370467, energy_tolerance) # svnversion 5252 #equal(niter_c00, 14, niter_tolerance) # svnversion 5252 #equal(E_c1, -11.5590572387, energy_tolerance) # svnversion 5252 #equal(niter_c1, 14, niter_tolerance) # svnversion 5252 gpaw-0.11.0.13004/gpaw/test/proton.py0000664000175000017500000000056512553643471017273 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atoms from gpaw import GPAW a = 4.5 H = Atoms('H', [(a / 2, a / 2, a / 2)], pbc=0, cell=(a, a, a)) calc = GPAW(nbands=1, h=0.2, charge=1) H.set_calculator(calc) print(H.get_potential_energy() + calc.get_reference_energy()) assert abs(H.get_potential_energy() + calc.get_reference_energy()) < 0.014 gpaw-0.11.0.13004/gpaw/test/transport.py0000664000175000017500000000225612553643471020005 0ustar jensjjensj00000000000000import numpy as np from ase import Atoms from gpaw import FermiDirac, Mixer from gpaw.transport.calculator import Transport from gpaw.atom.basis import BasisMaker from gpaw.poisson import PoissonSolver a = 3.6 L = 7.00 basis = BasisMaker('Na').generate(1, 1, energysplit=0.3) atoms = Atoms('Na12', pbc=(1, 1, 1), cell=[L, L, 12 * a]) atoms.positions[:12, 2] = [i * a for i in range(12)] atoms.positions[:, :2] = L / 2. atoms.center() pl_atoms1 = np.arange(4) pl_atoms2 = np.arange(8, 12) pl_cell1 = (L, L, 4 * a) pl_cell2 = pl_cell1 t = Transport(h=0.3, xc='LDA', basis={'Na': basis}, kpts=(2, 2, 1), occupations=FermiDirac(0.1), mode='lcao', poissonsolver=PoissonSolver(nn=2, relax='GS'), txt='Na_lcao.txt', mixer=Mixer(0.1, 5, weight=100.0), guess_steps=10, pl_atoms=[pl_atoms1, pl_atoms2], pl_cells=[pl_cell1, pl_cell2], pl_kpts=(2, 2, 15), analysis_data_list=['tc', 'force'], edge_atoms=[[0, 3], [0, 11]], mol_atoms=np.arange(4, 8)) atoms.set_calculator(t) t.calculate_iv(0.5, 2) gpaw-0.11.0.13004/gpaw/test/Al2_lrtddft.py0000664000175000017500000000501512553643471020106 0ustar jensjjensj00000000000000from __future__ import print_function from gpaw import GPAW, FermiDirac from gpaw.mpi import world, size, rank from gpaw.lrtddft2 import LrTDDFT2 from gpaw.lrtddft2.lr_communicators import LrCommunicators from gpaw.test import equal from ase.atoms import Atoms from glob import glob import os import numpy as np debug = False use_hdf5 = True try: import _gpaw_hdf5 restart_file = 'Al2_gs.hdf5' except ImportError: restart_file = 'Al2_gs.gpw' d = 2.563 atoms = Atoms('Al2', positions=((0, 0, 0), (0, 0, d)) ) atoms.center(4.0) calc = GPAW(h=0.24, eigensolver='cg', basis='dzp', occupations=FermiDirac(width=0.01), convergence={'eigenstates': 4.0e-5, 'density' : 1.0e-2, 'bands' : 'all'}, nbands=20) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write(restart_file, mode='all') # Try to run parallel over eh-pairs if size % 2 == 0: eh_size = 2 domain_size = size // eh_size else: eh_size = 1 domain_size = size lr_comms = LrCommunicators(world, domain_size, eh_size) calc = GPAW(restart_file, communicator=lr_comms.dd_comm) de = 3.0 lr = LrTDDFT2('Al2_lri', calc, fxc = 'PBE', max_energy_diff=de, lr_communicators=lr_comms ) (w,S,R,Sx,Sy,Sz) = lr.get_transitions(max_energy=1e9, units='au') e0_1 = w[0] e1_1 = w[-1] # Continue with larger de de = 4.5 lr = LrTDDFT2('Al2_lri', calc, fxc = 'PBE', max_energy_diff=de, lr_communicators=lr_comms ) (w,S,R,Sx,Sy,Sz) = lr.get_transitions(max_energy=1e9, units='au') e0_2 = w[0] e1_2 = w[-1] # Continue with smaller de de = 2.5 lr = LrTDDFT2('Al2_lri', calc, fxc = 'PBE', max_energy_diff=de, lr_communicators=lr_comms ) (w,S,R,Sx,Sy,Sz) = lr.get_transitions(max_energy=1e9, units='au') e0_3 = w[0] e1_3 = w[-1] if debug and rank == 0: print(e0_1, e1_1) print(e0_2, e1_2) print(e0_3, e1_3) tol = 1.0e-8 equal(e0_1, 0.00105074187176, tol) equal(e0_1, e0_2, tol) equal(e0_1, e0_3, tol) equal(e1_1, 0.183188157301, tol) equal(e1_2, 0.194973135812, tol) equal(e1_3, 0.120681529342, tol) # Remove the unused output files if rank == 0: files = glob('*.ready_rows.*') files += glob('*.LR_info') files += glob('*.log.*') files += glob('*.K_matrix.*') files += glob('*.KS_singles') for file in files: os.remove(file) gpaw-0.11.0.13004/gpaw/test/pbc.py0000664000175000017500000000062312553643472016512 0ustar jensjjensj00000000000000"""Make sure we get an exception when an atom is too close to the boundary.""" from ase import Atoms from gpaw import GPAW from gpaw.grid_descriptor import GridBoundsError a = 4.0 x = 0.1 hydrogen = Atoms('H', [(x, x, x)], cell=(a, a, a), calculator=GPAW(maxiter=7)) try: e1 = hydrogen.get_potential_energy() except GridBoundsError: pass else: assert False gpaw-0.11.0.13004/gpaw/test/observer.py0000664000175000017500000000151112553643471017571 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW from ase.visualize import view class ObsTest: def __init__(self): self.steps = [] def run(self): self.steps.append(calc.iter) def converge(self): calc.scf.converged = True H = Atoms('H', positions=[(1.5, 1.5, 1.5)]) H.set_cell((3, 3, 3)) calc = GPAW(convergence={'density': -1}, maxiter=11) AllCall = ObsTest() EvenCall = ObsTest() OneCall = ObsTest() FinalCall = ObsTest() calc.attach(AllCall.run, 1) calc.attach(EvenCall.run, 2) calc.attach(OneCall.run, -7) calc.attach(OneCall.converge, -7) calc.attach(FinalCall.run, 0) H.set_calculator(calc) H.get_potential_energy() assert AllCall.steps == [1, 2, 3, 4, 5, 6, 7] assert EvenCall.steps == [2, 4, 6, 7] assert OneCall.steps == [7] assert FinalCall.steps == [7] gpaw-0.11.0.13004/gpaw/test/ralda_energy_Si.py0000664000175000017500000000227012553643472021035 0ustar jensjjensj00000000000000from ase import * from ase.lattice import bulk from ase.dft.kpoints import monkhorst_pack from gpaw import * from gpaw.mpi import serial_comm from gpaw.test import equal from gpaw.xc.rpa import RPACorrelation from gpaw.xc.fxc import FXCCorrelation import numpy as np a0 = 5.43 cell = bulk('Si', 'fcc', a=a0).get_cell() Si = Atoms('Si2', cell=cell, pbc=True, scaled_positions=((0,0,0), (0.25,0.25,0.25))) kpts = monkhorst_pack((2,2,2)) kpts += np.array([1/4., 1/4., 1/4.]) calc = GPAW(mode='pw', kpts=kpts, occupations=FermiDirac(0.001), communicator=serial_comm) Si.set_calculator(calc) E = Si.get_potential_energy() calc.diagonalize_full_hamiltonian(nbands=50) rpa = RPACorrelation(calc) E_rpa1 = rpa.calculate(ecut=[25, 50]) fxc = FXCCorrelation(calc, xc='RPA', nlambda=16) E_rpa2 = fxc.calculate(ecut=[25, 50]) fxc = FXCCorrelation(calc, xc='rALDA', unit_cells=[1,1,2]) E_ralda = fxc.calculate(ecut=[25, 50]) fxc = FXCCorrelation(calc, xc='rAPBE', unit_cells=[1,1,2]) E_rapbe = fxc.calculate(ecut=[25, 50]) equal(E_rpa1[-1], E_rpa2[-1], 0.01) equal(E_rpa2[-1], -12.6495, 0.001) equal(E_ralda[-1], -11.3817, 0.001) equal(E_rapbe[-1], -11.1640, 0.001) gpaw-0.11.0.13004/gpaw/test/exx_coarse.py0000664000175000017500000000234512553643472020111 0ustar jensjjensj00000000000000from __future__ import print_function import sys from ase import Atoms from ase.utils.timing import Timer from gpaw import GPAW from gpaw.test import equal from gpaw.xc.hybrid import HybridXC timer = Timer() loa = Atoms('Be2', [(0, 0, 0), (2.45, 0, 0)], magmoms=[0.5, 0.5], cell=[5.9, 4.8, 5.0]) loa.center() fgl = [False, True] #fgl = [True, False] txt='-' txt='/dev/null' E = {} niter = {} for fg in fgl: if fg: tstr = 'Exx on fine grid' else: tstr = 'Exx on coarse grid' timer.start(tstr) calc = GPAW(h=0.3, eigensolver='rmm-diis', xc='PBE', nbands=4, convergence={'eigenstates': 1e-4}, charge=-1) loa.set_calculator(calc) E[fg] = loa.get_potential_energy() calc.set(xc=HybridXC('PBE0', finegrid=fg)) E[fg] = loa.get_potential_energy() niter[fg] = calc.get_number_of_iterations() timer.stop(tstr) timer.write(sys.stdout) print('Total energy on the fine grid =', E[True]) print('Total energy on the coarse grid =', E[False]) equal(E[True], E[False], 0.01) energy_tolerance = 0.0003 equal(E[False], 6.97818, energy_tolerance) equal(E[True], 6.97153, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/ts09.py0000664000175000017500000000215012553643471016541 0ustar jensjjensj00000000000000from ase import Atoms, io from ase.calculators.vdwcorrection import vdWTkatchenko09prl from ase.structure import molecule from ase.parallel import barrier from gpaw import GPAW from gpaw.cluster import Cluster from gpaw.analyse.hirshfeld import HirshfeldDensity, HirshfeldPartitioning from gpaw.analyse.vdwradii import vdWradii from gpaw.test import equal h = 0.4 s = Cluster(molecule('Na2')) s.minimal_box(3., h=h) out_traj = 'Na2.traj' out_txt = 'Na2.txt' cc = GPAW(h=h, xc='PBE', txt=out_txt) # this is needed to initialize txt output cc.initialize(s) c = vdWTkatchenko09prl(HirshfeldPartitioning(cc), vdWradii(s.get_chemical_symbols(), 'PBE')) s.set_calculator(c) E = s.get_potential_energy() F_ac = s.get_forces() s.write(out_traj) barrier() # test I/O, accuracy due to text output accuracy = 1.e-5 for fname in [out_traj, out_txt]: s_out = io.read(fname) ##print s_out.get_potential_energy(), E ##print s_out.get_forces() equal(s_out.get_potential_energy(), E, accuracy) for fi, fo in zip(F_ac, s_out.get_forces()): equal(fi, fo, accuracy) gpaw-0.11.0.13004/gpaw/test/test.py0000664000175000017500000001235412553643471016730 0ustar jensjjensj00000000000000from __future__ import print_function import os import platform import tempfile import warnings from optparse import OptionParser import gpaw.mpi as mpi from gpaw import debug from gpaw.version import version def main(args=None): description = ('Run the GPAW test suite. The test suite can be run in ' 'parallel with MPI through gpaw-python. The test suite ' 'supports 1, 2, 4 or 8 CPUs although some tests are ' 'skipped for some parallelizations. If no TESTs are ' 'given, run all tests supporting the parallelization.') parser = OptionParser(usage='%prog [OPTION...] [TEST...]', description=description, version='%%prog %s' % version) parser.add_option('-x', '--exclude', type='string', default=None, help='Exclude tests (comma separated list of tests).', metavar='test1.py,test2.py,...') parser.add_option('-f', '--run-failed-tests-only', action='store_true', help='Run failed tests only.') parser.add_option('--from', metavar='TESTFILE', dest='from_test', help='Run remaining tests, starting from TESTFILE') parser.add_option('--after', metavar='TESTFILE', dest='after_test', help='Run remaining tests, starting after TESTFILE') parser.add_option('--range', type='string', default=None, help='Run tests in range test_i.py to test_j.py ' '(inclusive)', metavar='test_i.py,test_j.py') parser.add_option('-j', '--jobs', type='int', default=1, help='Run JOBS threads. Each test will be executed ' 'in serial by one thread. This option cannot be used ' 'for parallelization together with MPI.') parser.add_option('--reverse', action='store_true', help=('Run tests in reverse order (less overhead with ' 'multiple jobs)')) parser.add_option('-k', '--keep-temp-dir', action='store_true', dest='keep_tmpdir', help='Do not delete temporary files.') parser.add_option('-d', '--directory', help='Run test in this directory') parser.add_option('-s', '--show-output', action='store_true', help='Show standard output from tests.') opt, tests = parser.parse_args(args) if len(tests) == 0: from gpaw.test import tests if opt.reverse: tests.reverse() if opt.run_failed_tests_only: tests = [line.strip() for line in open('failed-tests.txt')] exclude = [] if opt.exclude is not None: exclude += opt.exclude.split(',') if opt.from_test: fromindex = tests.index(opt.from_test) tests = tests[fromindex:] if opt.after_test: index = tests.index(opt.after_test) + 1 tests = tests[index:] if opt.range: # default start(stop) index is first(last) test indices = opt.range.split(',') try: start_index = tests.index(indices[0]) except ValueError: start_index = 0 try: stop_index = tests.index(indices[1]) + 1 except ValueError: stop_index = len(tests) tests = tests[start_index:stop_index] if opt.jobs > 1: exclude.append('maxrss.py') for test in exclude: if test in tests: tests.remove(test) from gpaw.test import TestRunner if mpi.world.size > 8: if mpi.rank == 0: message = '!!!!!!!\n' \ 'GPAW regression test suite was not designed to run on more\n' \ 'than 8 MPI tasks. Re-run test suite using 1, 2, 4 or 8 MPI\n' \ 'tasks instead.' warnings.warn(message, RuntimeWarning) if mpi.rank == 0: if opt.directory is None: tmpdir = tempfile.mkdtemp(prefix='gpaw-test-') else: tmpdir = opt.directory if os.path.isdir(tmpdir): opt.keep_tmpdir = True else: os.mkdir(tmpdir) else: tmpdir = None tmpdir = mpi.broadcast_string(tmpdir) cwd = os.getcwd() os.chdir(tmpdir) operating_system = platform.system() + ' ' + platform.machine() operating_system += ' ' + ' '.join(platform.dist()) python = platform.python_version() + ' ' + platform.python_compiler() python += ' ' + ' '.join(platform.architecture()) if mpi.rank == 0: print('python %s on %s' % (python, operating_system)) print('Running tests in %s' % tmpdir) print('Jobs: %d, Cores: %d, debug-mode: %r' % (opt.jobs, mpi.size, debug)) failed = TestRunner(tests, jobs=opt.jobs, show_output=opt.show_output).run() os.chdir(cwd) if mpi.rank == 0: if len(failed) > 0: open('failed-tests.txt', 'w').write('\n'.join(failed) + '\n') elif not opt.keep_tmpdir: os.system('rm -rf ' + tmpdir) return len(failed) # Backwards compatibility: run = main if __name__ == '__main__': main() gpaw-0.11.0.13004/gpaw/test/Hubbard_U.py0000664000175000017500000000456312553643472017610 0ustar jensjjensj00000000000000# -*- coding: utf-8 -*- import numpy as np from math import sqrt from ase.units import Hartree from ase import Atoms from gpaw import GPAW, FermiDirac, PoissonSolver from gpaw.test import equal ############################################################################## ## Define a function that returns the band gab ## defined as the difference between the bottom of the conduction band and the ## top of the valence band. def band_gab(calc): ef = calc.get_fermi_level() Nb = calc.wfs.bd.nbands w_k = calc.wfs.kd.weight_k x = 0 nspin=calc.get_number_of_spins() energies = np.empty(len(w_k) * Nb*nspin) for spin in np.arange(nspin): for k, w in enumerate(w_k): energies[x:x + Nb] = calc.get_eigenvalues(k,spin) x += Nb index1=np.where(energies-ef<=0) index2=np.where(energies-ef>0) Vb=max(energies[index1[0]])-ef Cb=min(energies[index2[0]])-ef return Cb-Vb ############################################################################## ## Setup up bulk NiO in an antiferromagnetic configuration name='Hubbard_test_on_NiO' a = 4.19 # Lattice constants b=a/sqrt(2) m=2 k=2 # Number of k-points atoms = Atoms(symbols='Ni2O2', pbc=True, cell=(b, b, a), positions=[(0, 0, 0), (b/2, b/2, a/2), (0, 0, a/2), (b/2, b/2, 0)], magmoms=(m,-m,0,0) ) ############################################################################## ## Setup the calculator calc = GPAW( h=0.25, occupations=FermiDirac(width=0.05), poissonsolver=PoissonSolver(nn='M', relax='J'), setups={'Ni': '10'}, convergence={'eigenstates':8e-4,'density': 1.0e-2,'energy': 0.1}, #txt=name+'.txt', kpts=(k, k, k), xc='PBE') atoms.set_pbc(1) atoms.set_calculator(calc) ############################################################################## ## Find the ground-state and get the band gab e1 = atoms.get_potential_energy() Eg_non_Hub = band_gab(calc) # Setup 6eV Hubbard U on the d-orbitals (l=2) of Ni atoms: calc.set(setups={'Ni': '10:d,6.0'}) ## Make ready for scf with the DFT+U functional and converge this new system ## and get new band bag.....which should be much larger: e2 = calc.get_potential_energy() Eg_Hub = band_gab(calc) equal(Eg_Hub, 4.7, 0.2) equal(Eg_non_Hub, 0.8, 0.1) gpaw-0.11.0.13004/gpaw/test/lcao_tdgllbsc.py0000664000175000017500000000602012553643471020536 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW, FermiDirac, Mixer from gpaw.lcaotddft import LCAOTDDFT from gpaw.mpi import world from gpaw.version import version from gpaw.tddft import TDDFT as GRIDTDDFT from gpaw.test import equal ref_values = [[-0.0153712, -0.0153712, -0.0153712], [ 0.0037263, 0.0037263, 0.0037263], [ 0.0118144, 0.0118144, 0.0118144], [-0.0902301, -0.0902301, -0.0902301], [-0.0835503, -0.0835503, -0.08355028]] calcs = [] # Cross-check fd and lcao with PBE and GLLBSC. # Also test GLLBSC-ground state + ALDA-response in both modes. for (mode, TDDFT) in [('lcao', LCAOTDDFT), ('fd', GRIDTDDFT)]: for (xc, fxc) in [('PBE', 'PBE'), ('GLLBSC', 'GLLBSC'), ('GLLBSC', 'LDA')]: if xc=='PBE' and mode=='fd': # There are other checks for this combination continue tag = 'np%i_ver%s_%s_%s+%s' % (world.size, version, mode, xc, fxc) # silane atoms = Atoms('SiH4',[( 0.0000, 0.0000, 0.0000), ( 0.8544, 0.8544, 0.8544), (-0.8544, -0.8544, 0.8544), ( 0.8544, -0.8544, -0.8544), (-0.8544, 0.8544, -0.8544)]) atoms.center(vacuum=4.0) # 1) ground state calcs.append(GPAW(nbands = 7, mixer = Mixer(0.20, 5, weight=50.0), convergence = {'eigenstates': 1e-6, 'density': 1e-6, 'energy': 1e-6}, h = 0.40, mode = mode, xc = xc, basis = 'dzp', dtype = complex)) atoms.set_calculator(calcs[-1]) energy = atoms.get_potential_energy() calcs[-1].write('gs.gpw', mode='all') # 2) restart ground state calcs.append(GPAW('gs.gpw')) calcs[-1].set(occupations=FermiDirac(0.05)) calcs[-1].get_potential_energy() calcs[-1].write('gs.gpw', mode='all') # 3) time propagation calcs.append(TDDFT('gs.gpw')) if fxc != xc: calcs[-1].linearize_to_xc(fxc) calcs[-1].propagate(10.0, 20, 'dm.%s.dat' % tag) # dipole moment must remain zero calcs[-1].attach(equal, 1, calcs[-1].density.finegd.calculate_dipole_moment(calcs[-1].density.rhot_g), 0.0, 1.0e-6) calcs[-1].write('td.gpw', mode='all') # 4) restart time propagation + apply kick if xc==fxc: # TODO: restart when linearize_to_xc was applied calcs.append(TDDFT('td.gpw')) calcs[-1].absorption_kick([0.01, 0.01, 0.01]) calcs[-1].propagate(10.0, 30, 'dm.%s.dat' % tag) equal(calcs[-1].density.finegd.calculate_dipole_moment(calcs[-1].density.rhot_g), ref_values.pop(0), 1.0e-5, msg="Failed with %s/%s+%s: " % (mode, xc, fxc)) gpaw-0.11.0.13004/gpaw/test/GW_testsym.py0000664000175000017500000000363012553643472020054 0ustar jensjjensj00000000000000from __future__ import print_function from ase.lattice import bulk from gpaw import GPAW, FermiDirac from ase.units import Hartree import numpy as np from gpaw.response.gw import GW a = 5.431 atoms = bulk('Si', 'diamond', a=a) kpts =(3,3,3) calc = GPAW( h=0.24, kpts=kpts, xc='LDA', txt='Si_gs.txt', nbands=20, convergence={'bands':8}, occupations=FermiDirac(0.001) ) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('Si_kpt3.gpw','all') file='Si_kpt3.gpw' gw = GW( file=file, nbands=8, bands=np.array([2,3]), kpoints=np.arange(27), w=np.linspace(0., 60., 601), ecut=100., eta=0.1 ) gw.get_QP_spectrum() gw.Qp_kn *= Hartree checkQp_kn = np.zeros((gw.kd.nibzkpts, gw.gwnband)) nn = np.zeros(gw.kd.nibzkpts) for k in range(gw.nkpt): ibzk = gw.kd.bz2ibz_k[k] checkQp_kn[ibzk,:] += gw.Qp_kn[k,:] nn[ibzk] += 1 for k in range(gw.kd.nibzkpts): checkQp_kn[k] /= nn[k] for k in range(gw.nkpt): ibzk = gw.kd.bz2ibz_k[k] print(np.abs(checkQp_kn[ibzk] - gw.Qp_kn[k])) # gw.Qp_kn #[[ 6.19522578 6.19534951] # [ 3.99972211 3.98923808] # [ 1.27697908 4.28309876] # [ 3.99980109 3.98910082] # [ 6.18609008 6.16523424] # [ 1.27796725 4.28057501] # [ 1.27694066 4.28322734] # [ 1.27793528 4.28067604] # [ 1.27709399 4.27762828] # [ 4.00034637 3.98848107] # [ 6.19054241 6.16985403] # [ 1.27781506 4.28614094] # [ 6.19044301 6.16981151] # [ 7.1159977 7.11541927] # [ 6.19469536 6.17384384] # [ 1.27780361 4.28614089] # [ 6.19473472 6.17384953] # [ 4.00680613 3.98247912] # [ 1.27709219 4.27768906] # [ 1.27792268 4.28066888] # [ 1.27693712 4.28320036] # [ 1.27796113 4.28054092] # [ 6.19021475 6.16917482] # [ 4.0073578 3.98186593] # [ 1.27696901 4.28309883] # [ 4.00743753 3.98172983] # [ 6.19094467 6.19115549]] gpaw-0.11.0.13004/gpaw/test/keep_htpsit.py0000664000175000017500000000123312553643472020263 0ustar jensjjensj00000000000000from gpaw import GPAW from gpaw.eigensolvers.rmm_diis_old import RMM_DIIS from ase import Atoms from gpaw.test import equal atoms = Atoms('H') atoms.center(3.0) convergence={'eigenstates' : 1e-2, 'density' : 1e-2} # Keep htpsit calc = GPAW(nbands=2, eigensolver=RMM_DIIS(keep_htpsit=True), convergence=convergence, maxiter=20) atoms.set_calculator(calc) e0 = atoms.get_potential_energy() # Do not keep htpsit calc = GPAW(nbands=2, eigensolver=RMM_DIIS(keep_htpsit=False), convergence=convergence, maxiter=20) atoms.set_calculator(calc) e1 = atoms.get_potential_energy() equal(e0, e1, 1e-12) gpaw-0.11.0.13004/gpaw/test/response_graphene.py0000664000175000017500000000577412553643472021471 0ustar jensjjensj00000000000000import os import time import pickle as pckl import numpy as np from ase import Atoms from ase.io import read from ase.lattice.compounds import Rocksalt from gpaw import GPAW, FermiDirac, Mixer from gpaw.utilities import compiled_with_sl from gpaw.eigensolvers import Davidson from gpaw.wavefunctions.pw import PW from gpaw.occupations import FermiDirac from gpaw.response.df import DielectricFunction from gpaw.mpi import world # This test assures that some things that # should be equal, are. a = 2.5 c = 3.22 GR = Atoms(symbols='C2', positions=[(0.5*a, 0.2 + -np.sqrt(3) / 6 * a, 0.0), (0.5*a, 0.2 + np.sqrt(3) / 6 * a, 0.0)], cell=[(0.5*a,-0.5*3**0.5*a,0), (0.5*a,+0.5*3**0.5*a,0), (0.0,0.0,c*2.0)]) GR.set_pbc((True,True,True)) atoms = GR GSsettings = [{'symmetry': 'off', 'kpts': {'density': 2.5, 'gamma': False}}, {'symmetry': {}, 'kpts': {'density': 2.5, 'gamma': False}}, {'symmetry': 'off', 'kpts': {'density': 2.5, 'gamma': True}}, {'symmetry': {}, 'kpts': {'density': 2.5, 'gamma': True}}] DFsettings = [{'disable_point_group': True, 'disable_time_reversal': True, 'use_more_memory': 0}, {'disable_point_group': False, 'disable_time_reversal': True, 'use_more_memory': 0}, {'disable_point_group': True, 'disable_time_reversal': False, 'use_more_memory': 0}, {'disable_point_group': False, 'disable_time_reversal': False, 'use_more_memory': 0}, {'disable_point_group': False, 'disable_time_reversal': False, 'use_more_memory': 0, 'unsymmetrized': False}, {'disable_point_group': False, 'disable_time_reversal': False, 'use_more_memory': 1}] if world.size > 1 and compiled_with_sl(): DFsettings.append({'disable_point_group': False, 'disable_time_reversal': False, 'use_more_memory': 1, 'nblocks': 2}) for GSkwargs in GSsettings: calc = GPAW(h=0.18, mode=PW(600), occupations=FermiDirac(0.2), **GSkwargs) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('gr.gpw', 'all') dfs = [] for kwargs in DFsettings: DF = DielectricFunction(calc='gr.gpw', domega0=0.2, eta=0.2, ecut=40.0, **kwargs) df1, df2 = DF.get_dielectric_function() if world.rank == 0: dfs.append(df1) while len(dfs): df = dfs.pop() for df2 in dfs: try: assert np.allclose(df, df2) except AssertionError: print(np.max(np.abs((df - df2) / df))) raise AssertionError gpaw-0.11.0.13004/gpaw/test/symmetry.py0000664000175000017500000000504412553643471017640 0ustar jensjjensj00000000000000from math import sqrt import numpy as np from gpaw.symmetry import Symmetry from ase.dft.kpoints import monkhorst_pack # Primitive diamond lattice, with Si lattice parameter a = 5.475 cell_cv = .5 * a * np.array([(1, 1, 0), (1, 0, 1), (0, 1, 1)]) spos_ac = np.array([(.00, .00, .00), (.25, .25, .25)]) id_a = [1, 1] # Two identical atoms pbc_c = np.ones(3, bool) bzk_kc = monkhorst_pack((4, 4, 4)) # Do check symm = Symmetry(id_a, cell_cv, pbc_c) symm.analyze(spos_ac) ibzk_kc, w_k = symm.reduce(bzk_kc)[:2] assert len(symm.op_scc) == 24 assert len(w_k) == 10 a = 3 / 32.; b = 1 / 32.; c = 6 / 32. assert np.all(w_k == [a, b, a, c, c, a, a, a, a, b]) assert not symm.op_scc.sum(0).any() # Rotate unit cell and check again: cell_cv = a / sqrt(2) * np.array([(1, 0, 0), (0.5, sqrt(3) / 2, 0), (0.5, sqrt(3) / 6, sqrt(2.0 / 3))]) symm = Symmetry(id_a, cell_cv, pbc_c) symm.analyze(spos_ac) ibzkb_kc, wb_k = symm.reduce(bzk_kc)[:2] assert len(symm.op_scc) == 24 assert abs(w_k - wb_k).sum() < 1e-14 assert abs(ibzk_kc - ibzkb_kc).sum() < 1e-14 assert not symm.op_scc.sum(0).any() bzk_kc = monkhorst_pack((3, 3, 3)) symm = Symmetry(id_a, cell_cv, pbc_c) symm.analyze(spos_ac) ibzk_kc, w_k = symm.reduce(bzk_kc)[:2] assert len(symm.op_scc) == 24 assert len(w_k) == 4 assert abs(w_k * 27 - (1, 12, 6, 8)).sum() < 1e-14 assert not symm.op_scc.sum(0).any() # Linear chain of four atoms, with H lattice parameter cell_cv = np.diag((8., 5., 5.)) spos_ac = np.array([[ 0.125, 0.5 , 0.5 ], [ 0.375, 0.5 , 0.5 ], [ 0.625, 0.5 , 0.5 ], [ 0.875, 0.5 , 0.5 ]]) id_a = [1, 1, 1, 1] # Four identical atoms pbc_c = np.array([1, 0, 0], bool) bzk_kc = monkhorst_pack((3, 1, 1)) # Do check symm = Symmetry(id_a, cell_cv, pbc_c) symm.analyze(spos_ac) ibzk_kc, w_k = symm.reduce(bzk_kc)[:2] assert len(symm.op_scc) == 2 assert len(w_k) == 2 assert np.all(w_k == [1 / 3., 2 / 3.]) # Rocksalt Ni2O2 a = 7.92; x = 2. * np.sqrt(1./3.); y = np.sqrt(1./8.); z1 = np.sqrt(1./24.); z2 = np.sqrt(1./6.) cell_cv = a * np.array([(x, y, -z1), (x, -y, -z1), (x, 0., z2)]) spos_ac = np.array([[0., 0. ,0.], [1./2., 1./2., 1./2.], [1./4., 1./4., 1./4.], [3./4., 3./4., 3./4.]]) id_a = [1, 2, 3, 3] pbc_c = np.array([1, 1, 1], bool) bzk_kc = monkhorst_pack((2, 2, 2)) # Do check symm = Symmetry(id_a, cell_cv, pbc_c) symm.analyze(spos_ac) ibzk_kc, w_k = symm.reduce(bzk_kc)[:2] assert len(symm.op_scc) == 12 assert len(w_k) == 2 assert np.all(w_k == [3/4., 1/4.]) gpaw-0.11.0.13004/gpaw/test/aeatom.py0000664000175000017500000000176212553643471017220 0ustar jensjjensj00000000000000from __future__ import print_function from gpaw.atom.aeatom import AllElectronAtom, c from gpaw.test import equal Z = 79 # gold atom kwargs = dict(ngpts=5000, alpha2=1000 * Z**2, ngauss=200) # Test Schroedinger equation: aea = AllElectronAtom(Z, log=None) aea.initialize(**kwargs) errors = [] for channel in aea.channels: channel.solve(-Z) for n in range(7): e = channel.e_n[n] e0 = -0.5 * Z**2 / (n + channel.l + 1)**2 errors.append(abs(e / e0 - 1)) print(max(errors)) equal(max(errors), 0, 2.0e-5) # Test Dirac equation: aea = AllElectronAtom(Z, dirac=True, log=None) aea.initialize(**kwargs) errors = [] for channel in aea.channels: channel.solve(-Z) for n in range(7): e = channel.e_n[n] if channel.k > 0: n += 1 e0 = (1 + (Z / c)**2 / ((channel.k**2 - (Z / c)**2)**0.5 + n)**2)**-0.5 - 1 e0 *= c**2 errors.append(abs(e / e0 - 1)) print(max(errors)) equal(max(errors), 0, 4.0e-5) gpaw-0.11.0.13004/gpaw/test/spectrum.py0000664000175000017500000000176712553643471017621 0ustar jensjjensj00000000000000import os from math import exp, pi, sqrt import numpy as np from gpaw.gauss import Gauss, Lorentz from gpaw.test import equal from gpaw.utilities.folder import Folder # Gauss and Lorentz functions width = 0.5 x = 1.5 equal(Gauss(width).get(x), exp(- x**2 / 2 / width**2) / sqrt(2 * pi) / width, 1.e-15) equal(Lorentz(width).get(x), width / (x**2 + width**2) / pi, 1.e-15) # folder function for name in ['Gauss', 'Lorentz']: folder = Folder(width, name) x = [0, 2] y = [[2, 0, 1], [1, 1, 1]] xl, yl = folder.fold(x, y, dx=.7) # check first value if name == 'Lorentz': func = Lorentz(width) else: func = Gauss(width) yy = np.dot(np.array(y)[:, 0], func.get(xl[0] - np.array(x))) equal(yl[0, 0], yy, 1.e-15) # write spectrum from gpaw.lrtddft import LrTDDFT from gpaw.lrtddft.spectrum import spectrum fname = 'lr.dat.gz' if os.path.exists(fname): lr = LrTDDFT(fname) lr.diagonalize() spectrum(lr, 'spectrum.dat') gpaw-0.11.0.13004/gpaw/test/ed_wrapper.py0000664000175000017500000000366112553643471020102 0ustar jensjjensj00000000000000from ase import Atoms from gpaw.fdtd.poisson_fdtd import QSFDTD from gpaw.fdtd.polarizable_material import PermittivityPlus, PolarizableMaterial, PolarizableSphere from gpaw.mpi import world from gpaw.tddft import photoabsorption_spectrum, units from gpaw.test import equal import numpy as np # Whole simulation cell (Angstroms) cell = [20, 20, 30]; # Quantum subsystem atom_center = np.array([10.0, 10.0, 20.0]); atoms = Atoms('Na2', [atom_center + [0.0, 0.0, -1.50], atom_center + [0.0, 0.0, +1.50]]); # Classical subsystem sphere_center = np.array([10.0, 10.0, 10.0]); classical_material = PolarizableMaterial() classical_material.add_component(PolarizableSphere(permittivity = PermittivityPlus(data = [[1.20, 0.20, 25.0]]), center = sphere_center, radius = 5.0 )) # Wrap calculators qsfdtd = QSFDTD(classical_material = classical_material, atoms = atoms, cells = (cell, 2.50), spacings = [1.60, 0.40], remove_moments = (1, 4), communicator = world) # Run energy = qsfdtd.ground_state('gs.gpw', eigensolver = 'cg', nbands = -1) qsfdtd.time_propagation('gs.gpw', kick_strength=[0.000, 0.000, 0.001], time_step=10, iterations=5, dipole_moment_file='dm.dat', restart_file='td.gpw') qsfdtd.time_propagation('td.gpw', kick_strength=None, time_step=10, iterations=5, dipole_moment_file='dm.dat') # Test ref_cl_dipole_moment = [ -5.16149623e-14, -5.89090408e-14, 3.08450150e-02] ref_qm_dipole_moment = [ -2.63340461e-11, 2.61812794e-12, -9.35619772e-02] tol = 0.0001 equal(qsfdtd.td_calc.hamiltonian.poisson.get_classical_dipole_moment(), ref_cl_dipole_moment, tol) equal(qsfdtd.td_calc.hamiltonian.poisson.get_quantum_dipole_moment(), ref_qm_dipole_moment, tol) gpaw-0.11.0.13004/gpaw/test/fd2lcao_restart.py0000664000175000017500000000301612553643472021023 0ustar jensjjensj00000000000000"""Test read/write of restart files between fd and lcao mode""" from __future__ import print_function import os from ase import Atom, Atoms from gpaw import GPAW, Mixer, restart, FermiDirac from gpaw.test import equal energy_tolerance = 0.0001 niter_tolerance = 0 if not os.path.isfile('Na4_fd.gpw'): # Do grid kpts calculation a = 3.31 atoms = Atoms([Atom('Na',(i*a,0,0)) for i in range(4)], pbc=(1,0,0)) atoms.center(vacuum=a/2, axis=0) atoms.center(vacuum=3.5, axis=1) atoms.center(vacuum=3.5, axis=2) calc = GPAW(nbands=-3, h=0.3, setups={'Na': '1'}, xc='PBE', occupations=FermiDirac(width=0.1), kpts=(3, 1, 1), #basis='dzp', txt='Na4_fd.txt') atoms.set_calculator(calc) etot_fd = atoms.get_potential_energy() niter_fd = calc.get_number_of_iterations() print('Etot:', etot_fd, 'eV in fd-mode') calc.write('Na4_fd.gpw') del atoms,calc equal(etot_fd, -1.99055, energy_tolerance) if os.path.isfile('Na4_fd.gpw'): # LCAO calculation based on grid kpts calculation atoms, calc = restart('Na4_fd.gpw', #basis='dzp', mode='lcao', txt='Na4_lcao.txt') etot_lcao = atoms.get_potential_energy() niter_lcao = calc.get_number_of_iterations() print('Etot:', etot_lcao, 'eV in lcao-mode') calc.write('Na4_lcao.gpw') del atoms, calc equal(etot_lcao, -1.9616, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/diag_perf.py0000664000175000017500000000163412553643471017670 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from time import time from gpaw.utilities.lapack import diagonalize, diagonalize_mr3 seed = 43 gen = np.random.RandomState(seed) def main(i,seed=42,dtype=float): if (dtype==complex): epsilon = 0.1j else: epsilon = 0.1 x = i + 1 N = x*100 print("N =",N) H0 = np.zeros((N,N),dtype=dtype) + gen.rand(*(N,N)) H1 = H0 + epsilon*np.tri(N,N, k=-1) W0 = np.zeros((N)) Z0 = np.zeros_like(H0) t0 = time() diagonalize(H1, W0) t1 = time() - t0 print("diagonalize", t1) t2 = time() diagonalize_mr3(H1, W0, Z0) t3 = time() - t2 print("diagonalize_mr3",t3) # diagonalize_mr3 must be faster than diagonalize assert(t3 < t1) if __name__ in ['__main__', '__builtin__']: for i in range(8): # Check matrix sizes only up to 800 main(i,dtype=float) main(i,dtype=complex) gpaw-0.11.0.13004/gpaw/test/ofdft.py0000664000175000017500000000161212553643471017046 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW from gpaw.mixer import Mixer from gpaw.test import equal from gpaw.test import gen h = 0.18 a = 8 c = a / 2 d = 1.8 elements = ['C'] results = [0.0256218846668] electrons = [6] for symbol in elements: xcname = '1.0_LDA_K_TF+1.0_LDA_X' g = gen(symbol, xcname=xcname, scalarrel=False, orbital_free=True) for element, result, e in zip(elements, results, electrons): atom = Atoms(element, positions=[(c, c, c)], cell=(a, a, a)) mixer = Mixer(0.3, 5, 1) calc = GPAW(h=h, txt='-', xc=xcname, maxiter=240, eigensolver='cg', mixer=mixer) atom.set_calculator(calc) E = atom.get_total_energy() n = calc.get_all_electron_density() dv = atom.get_volume() / calc.get_number_of_grid_points().prod() I = n.sum() * dv / 2**3 equal(I, e, 1.0e-6) equal(result, E, 1.0e-3) gpaw-0.11.0.13004/gpaw/test/H_force.py0000664000175000017500000000165512553643471017320 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atom, Atoms from ase.calculators.test import numeric_force from gpaw import GPAW, Mixer, FermiDirac from gpaw.test import equal a = 4.0 n = 16 atoms = Atoms([Atom('H', [1.234, 2.345, 3.456])], cell=(a, a, a), pbc=True) calc = GPAW(nbands=1, gpts=(n, n, n), txt=None, mixer=Mixer(0.25, 3, 1), convergence={'energy': 1e-7}, occupations=FermiDirac(0.0)) atoms.set_calculator(calc) e1 = atoms.get_potential_energy() niter1 = calc.get_number_of_iterations() f1 = atoms.get_forces()[0] for i in range(3): f2i = numeric_force(atoms, 0, i) print(f1[i]-f2i) equal(f1[i], f2i, 0.00025) energy_tolerance = 0.00006 force_tolerance = 0.0001 niter_tolerance = 0 equal(e1, -0.531042, energy_tolerance) f1_ref = [-0.291893, -0.305174, -0.35329] for i in range(3): equal(f1[i], f1_ref[i], force_tolerance) gpaw-0.11.0.13004/gpaw/test/mpicomm.py0000664000175000017500000000305212553643471017405 0ustar jensjjensj00000000000000 import numpy as np from gpaw import debug from gpaw.mpi import world, serial_comm, _Communicator, SerialCommunicator even_comm = world.new_communicator(np.arange(0, world.size, 2)) if world.size > 1: odd_comm = world.new_communicator(np.arange(1, world.size, 2)) else: odd_comm = None if world.rank % 2 == 0: assert odd_comm is None comm = even_comm else: assert even_comm is None comm = odd_comm hasmpi = False try: import _gpaw hasmpi = hasattr(_gpaw, 'Communicator') and world.size > 1 except (ImportError, AttributeError): pass assert world.parent is None assert comm.parent is world if hasmpi: assert comm.parent.get_c_object() is world.get_c_object() assert comm.get_c_object().parent is world.get_c_object() commranks = np.arange(world.rank % 2, world.size, 2) assert np.all(comm.get_members() == commranks) assert comm.get_members()[comm.rank] == world.rank subcomm = comm.new_communicator(np.array([comm.rank])) assert subcomm.parent is comm assert subcomm.rank == 0 and subcomm.size == 1 assert subcomm.get_members().item() == comm.rank if debug: assert isinstance(world, _Communicator) assert isinstance(comm, _Communicator) assert isinstance(subcomm, _Communicator) elif world is serial_comm: assert isinstance(world, SerialCommunicator) assert isinstance(comm, SerialCommunicator) assert isinstance(subcomm, SerialCommunicator) elif hasmpi: assert isinstance(world, _gpaw.Communicator) assert isinstance(comm, _gpaw.Communicator) assert isinstance(subcomm, _gpaw.Communicator) gpaw-0.11.0.13004/gpaw/test/ralda_energy_Ni.py0000664000175000017500000000234312553643471021030 0ustar jensjjensj00000000000000from os import system from ase import * from ase.lattice import bulk from ase.dft.kpoints import monkhorst_pack from gpaw import * from gpaw.test import equal from gpaw.xc.fxc import FXCCorrelation from gpaw.mpi import world, serial_comm if world.rank == 0: a0 = 5.43 Ni = bulk('Ni', 'fcc') Ni.set_initial_magnetic_moments([0.7]) kpts = monkhorst_pack((3,3,3)) calc = GPAW(mode='pw', kpts=kpts, occupations=FermiDirac(0.001), setups={'Ni': '10'}, communicator=serial_comm) Ni.set_calculator(calc) Ni.get_potential_energy() calc.diagonalize_full_hamiltonian() calc.write('Ni.gpw', mode='all') world.barrier() rpa = FXCCorrelation('Ni.gpw', xc='RPA', nfrequencies=8, skip_gamma=True) E_rpa = rpa.calculate(ecut=[50]) ralda = FXCCorrelation('Ni.gpw', xc='rALDA', unit_cells=[2,1,1], nfrequencies=8, skip_gamma=True) E_ralda = ralda.calculate(ecut=[50]) rapbe = FXCCorrelation('Ni.gpw', xc='rAPBE', unit_cells=[2,1,1], nfrequencies=8, skip_gamma=True) E_rapbe = rapbe.calculate(ecut=[50]) equal(E_rpa, -7.827, 0.01) equal(E_ralda, -7.501, 0.01) equal(E_rapbe, -7.444, 0.01) gpaw-0.11.0.13004/gpaw/test/ne_gllb.py0000664000175000017500000000207612553643471017353 0ustar jensjjensj00000000000000import os from ase import * from gpaw import GPAW, Mixer from gpaw.atom.generator import Generator from gpaw.atom.configurations import parameters from gpaw import setup_paths from gpaw.test import equal from gpaw.mpi import world atom = 'Ne' setup_paths.insert(0, '.') for xcname in ['GLLBSC','GLLB']: if world.rank == 0: g = Generator(atom, xcname =xcname, scalarrel=False,nofiles=True) g.run(**parameters[atom]) eps = g.e_j[-1] world.barrier() a = 5 Ne = Atoms([Atom(atom, (0, 0, 0))], cell=(a, a, a), pbc=False) Ne.center() calc = GPAW(nbands=7, h=0.25, xc=xcname) Ne.set_calculator(calc) e = Ne.get_potential_energy() # Calculate the discontinuity response = calc.hamiltonian.xc.xcs['RESPONSE'] response.calculate_delta_xc() response.calculate_delta_xc_perturbation() eps3d = calc.wfs.kpt_u[0].eps_n[3] if world.rank == 0: equal(eps, eps3d, 1e-3) # Correct for small cell +0.14eV (since the test needs to be fast in test suite) equal(e+0.147106041, 0, 5e-2) gpaw-0.11.0.13004/gpaw/test/Gauss.py0000664000175000017500000000117612553643471017033 0ustar jensjjensj00000000000000from gpaw.test import equal from gpaw.gauss import test_derivatives for i in range(3): i1, i2 = test_derivatives((1.0, -3.4, 1.2), (0, 0, 0), (1, 0, 0), 1.4, 3.0, i) equal(i1, i2, 4e-10) i1, i2 = test_derivatives((1.0, -3.4, 1.2), (0, 1, 0), (0, 0, 1), 1.4, 3.0, i) equal(i1, i2, 2e-10) i1, i2 = test_derivatives((1.0, -3.4, 1.2), (0, 1, 0), (1, 0, 1), 1.4, 3.0, i) equal(i1, i2, 4e-11) i1, i2 = test_derivatives((1.0, -3.4, 1.2), (0, 2, 0), (1, 0, 1), 1.4, 3.0, i) equal(i1, i2, 6e-10) gpaw-0.11.0.13004/gpaw/test/cg2.py0000664000175000017500000000214012553643472016415 0ustar jensjjensj00000000000000import numpy as np from gpaw.utilities.cg import CG def A(x, b): b[:] = np.reshape(np.dot(np.reshape(x, (2, 4)), np.array([[1.0, 0.1, 0.0, 0.0], [0.1, 1.1, 0.1, 0.1], [0.0, 0.1, 0.8, 0.1], [0.0, 0.1, 0.1, 0.9]])), (2, 2, 1, 2)) A.sum = lambda x: x b = np.array([[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0]]) b.shape = (2, 2, 1, 2) x = b.copy() niter, error = CG(A, x, b, verbose=1) assert niter < 5 def A(x, b): b[:] = np.reshape(np.dot(np.reshape(x, (2, 4)), np.array([[1.0, 0.1, 0.0, 0.0], [0.1, 1.1, 0.1, 0.1], [0.0, 0.1, 0.8, 0.1], [0.0, 0.1, 0.1, 0.9]])), (2, 2, 1, 2)) A.sum = lambda x: x b = np.array([[1.0, 0.1j, 0.01+0.1j, 0.0], [0.0, 1.0, 0.0, 0.0]]) b.shape = (2, 2, 1, 2) x = b.copy() niter, error = CG(A, x, b, verbose=1) assert niter < 5 gpaw-0.11.0.13004/gpaw/test/ne_disc.py0000664000175000017500000000273412553643471017356 0ustar jensjjensj00000000000000import os from ase import * from gpaw import GPAW, restart from gpaw.atom.generator import Generator from gpaw.atom.configurations import parameters from gpaw import setup_paths from gpaw.mpi import world from gpaw.test import equal # This test calculates the derivative discontinuity of Ne-atom # first on 3D without restart. Then does restart and recalculates. atom = 'Ne' setup_paths.insert(0, '.') for xcname in ['GLLB','GLLBSC']: if world.rank == 0: g = Generator(atom, xcname =xcname, scalarrel=False,nofiles=True) g.run(**parameters[atom]) eps = g.e_j[-1] world.barrier() a = 10 Ne = Atoms([Atom(atom, (0, 0, 0))], cell=(a, a, a), pbc=False) Ne.center() calc = GPAW(nbands=10, h=0.21, xc=xcname) Ne.set_calculator(calc) e = Ne.get_potential_energy() response = calc.hamiltonian.xc.xcs['RESPONSE'] response.calculate_delta_xc() KS, dxc = response.calculate_delta_xc_perturbation() if xcname=='GLLB': equal(KS+dxc, 24.71, 1.5e-1) else: equal(KS+dxc, 27.70, 6.0e-2) eps3d = calc.wfs.kpt_u[0].eps_n[3] calc.write('Ne_temp.gpw') atoms, calc = restart('Ne_temp.gpw') KS2, dxc2 = response.calculate_delta_xc_perturbation() equal(KS, KS2, 1e-5) equal(dxc2, dxc, 1e-5) # Hardness of Ne 24.71eV by GLLB+Dxc, experimental I-A = I = 21.56eV if world.rank == 0: equal(eps, eps3d, 1e-3) if xcname=='GLLB': equal(24.71, KS2+dxc2, 1.2e-1) gpaw-0.11.0.13004/gpaw/test/aedensity.py0000664000175000017500000000257612553643471017743 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np from ase import Atom, Atoms from ase.parallel import rank from gpaw import GPAW from gpaw.test import equal try: calc = GPAW('NaCl.gpw') NaCl = calc.get_atoms() e = NaCl.get_potential_energy() niter = None except IOError: h = 0.21 # gridspacing a = [6.5, 6.5, 7.7] # unit cell d = 2.3608 # experimental bond length NaCl = Atoms([Atom('Na', [0, 0, 0]), Atom('Cl', [0, 0, d])], pbc=False, cell=a) NaCl.center() calc = GPAW(h=h, xc='LDA', nbands=5, lmax=0, setups={'Na': '1'}, convergence={'eigenstates': 1e-6}, spinpol=1) NaCl.set_calculator(calc) e = NaCl.get_potential_energy() niter = calc.get_number_of_iterations() calc.write('NaCl.gpw') dv = NaCl.get_volume() / calc.get_number_of_grid_points().prod() nt1 = calc.get_pseudo_density(gridrefinement=1) Zt1 = nt1.sum() * dv nt2 = calc.get_pseudo_density(gridrefinement=2) Zt2 = nt2.sum() * dv / 8 print('Integral of pseudo density:', Zt1, Zt2) equal(Zt1, Zt2, 1e-12) for gridrefinement in [1, 2, 4]: n = calc.get_all_electron_density(gridrefinement=gridrefinement) Z = n.sum() * dv / gridrefinement**3 print('Integral of all-electron density:', Z) equal(Z, 28, 1e-5) energy_tolerance = 0.0004 niter_tolerance = 0 equal(e, -4.908677, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/lxc_xcatom.py0000664000175000017500000000530312553643471020106 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np import numpy.random as ra from gpaw.setup import create_setup from gpaw.xc import XC from gpaw.test import equal, gen if 1: for functional in [ 'LDA_X', 'LDA_X+LDA_C_PW', 'LDA_X+LDA_C_VWN', 'LDA_X+LDA_C_PZ', 'GGA_X_PBE+GGA_C_PBE', 'GGA_X_PBE_R+GGA_C_PBE', 'GGA_X_B88+GGA_C_P86', 'GGA_X_B88+GGA_C_LYP', 'GGA_X_FT97_A+GGA_C_LYP' ]: gen('N', xcname=functional) tolerance = 0.000005 # libxc must reproduce old gpaw energies # zero Kelvin: in Hartree reference = { # version 0.9.1 'LDA_X+LDA_C_PW': 2.28836113207, # 'LDA' 'GGA_X_PBE+GGA_C_PBE': 2.3366049993, # 'PBE' 'GGA_X_PBE_R+GGA_C_PBE': 2.34496288319, # 'revPBE' } tolerance_libxc = 0.000001 # libxc must reproduce reference libxc energies reference_libxc = { # svnversion 5252 'LDA_X': 1.95030600807, 'LDA_X+LDA_C_PW': 2.23194461135, 'LDA_X+LDA_C_VWN': 2.23297429824, 'LDA_X+LDA_C_PZ': 2.23146045547, 'GGA_X_PBE+GGA_C_PBE': 2.28208665019, 'GGA_X_PBE_R+GGA_C_PBE': 2.29201920843, 'GGA_X_B88+GGA_C_P86': 2.30508027546, 'GGA_X_B88+GGA_C_LYP': 2.28183010548, 'GGA_X_FT97_A+GGA_C_LYP': 2.26846048873, } libxc_set = [ 'LDA_X', 'LDA_X+LDA_C_PW', 'LDA_X+LDA_C_VWN', 'LDA_X+LDA_C_PZ', 'GGA_X_PBE+GGA_C_PBE', 'GGA_X_PBE_R+GGA_C_PBE', 'GGA_X_B88+GGA_C_P86', 'GGA_X_B88+GGA_C_LYP', 'GGA_X_FT97_A+GGA_C_LYP' ] x = 0.000001 for xcname in libxc_set: ra.seed(8) xc = XC(xcname) s = create_setup('N', xc) ni = s.ni nii = ni * (ni + 1) // 2 D_p = 0.1 * ra.random(nii) + 0.4 H_p = np.zeros(nii) E1 = xc.calculate_paw_correction(s, D_p.reshape(1, -1), H_p.reshape(1, -1)) dD_p = x * ra.random(nii) D_p += dD_p dE = np.dot(H_p, dD_p) / x E2 = xc.calculate_paw_correction(s, D_p.reshape(1, -1)) print(xcname, dE, (E2 - E1) / x) equal(dE, (E2 - E1) / x, 0.003) E2s = xc.calculate_paw_correction(s, np.array([0.5 * D_p, 0.5 * D_p]), np.array([H_p, H_p])) print(E2, E2s) equal(E2, E2s, 1.0e-12) if xcname in reference: # compare with old gpaw print('A:', E2, reference[xcname]) equal(E2, reference[xcname], tolerance) if xc in reference_libxc: # compare with reference libxc print('B:', E2, reference_libxc[xcname]) equal(E2, reference_libxc[xcname], tolerance) D_sp = 0.1 * ra.random((2, nii)) + 0.2 H_sp = np.zeros((2, nii)) E1 = xc.calculate_paw_correction(s, D_sp, H_sp) dD_sp = x * ra.random((2, nii)) D_sp += dD_sp dE = np.dot(H_sp.ravel(), dD_sp.ravel()) / x E2 = xc.calculate_paw_correction(s, D_sp, H_sp) print(dE, (E2 - E1) / x) equal(dE, (E2 - E1) / x, 0.005) gpaw-0.11.0.13004/gpaw/test/exx.py0000664000175000017500000000327412553643471016556 0ustar jensjjensj00000000000000"""Test EXX/HFT implementation.""" from __future__ import print_function from ase import Atoms from gpaw import GPAW, PoissonSolver from gpaw.test import equal be2 = Atoms('Be2', [(0, 0, 0), (2.45, 0, 0)]) be2.center(vacuum=2.0) calc = GPAW(h=0.21, eigensolver='rmm-diis', nbands=3, convergence={'eigenstates': 1e-6}, poissonsolver=PoissonSolver(nn='M', relax='J'), txt='exx.txt') be2.set_calculator(calc) ref_1871 = { # Values from revision 1871. Not true reference values # xc Energy eigenvalue 0 eigenvalue 1 'PBE': (5.427450, -3.84092, -0.96192), 'PBE0': (-790.919942, -4.92321, -1.62948), 'EXX': (-785.590402, -7.17440, -2.73259) } from gpaw.xc import XC from gpaw.xc.hybrid import HybridXC current = {} # Current revision for xc in [XC('PBE'), HybridXC('PBE0', finegrid=True), HybridXC('EXX', finegrid=True), XC('PBE')]: # , 'oldPBE', 'LDA']: # Generate setup #g = Generator('Be', setup, scalarrel=True, nofiles=True, txt=None) #g.run(exx=True, **parameters['Be']) # switch to new xc functional calc.set(xc=xc) E = be2.get_potential_energy() if xc.name != 'PBE': E += calc.get_reference_energy() bands = calc.get_eigenvalues()[:2] # not 3 as unocc. eig are random!? XXX res = (E,) + tuple(bands) print(xc.name, res) if xc.name in current: for first, second in zip(current[xc.name], res): equal(first, second, 2.5e-3) else: current[xc.name] = res for name in current: for ref, cur in zip(ref_1871[name], current[name]): print(ref, cur, ref - cur) equal(ref, cur, 2.5e-3) gpaw-0.11.0.13004/gpaw/test/lcao_tddft_restart.py0000664000175000017500000000155612553643471021622 0ustar jensjjensj00000000000000from gpaw.tddft import photoabsorption_spectrum from ase import Atoms from gpaw import GPAW from gpaw.lcaotddft import LCAOTDDFT from gpaw.mpi import world xc = 'oldLDA' c = +1 h = 0.4 b = 'dzp' sy = 'Na2' positions = [[0.00,0.00,0.00],[0.00,0.00,2.00]] atoms = Atoms(symbols=sy, positions = positions) atoms.center(vacuum=3) # LCAO-RT-TDDFT calc = GPAW(mode='lcao', nbands=1, xc=xc, h=h, basis=b, dtype=complex, charge=c, width=0, convergence={'density':1e-8}, setups={'Na': '1'}) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('Na2.gpw','all') del calc calc = LCAOTDDFT('Na2.gpw') dmfile = sy+'_lcao_restart_'+b+'_rt_z.dm'+str(world.size) specfile = sy+'_lcao_restart_'+b+'_rt_z.spectrum'+str(world.size) calc.absorption_kick([0.0,0,0.001]) calc.propagate(10, 20, dmfile) if world.rank == 0: photoabsorption_spectrum(dmfile, specfile) gpaw-0.11.0.13004/gpaw/test/davidson.py0000664000175000017500000000167312553643471017562 0ustar jensjjensj00000000000000from ase import Atom, Atoms from gpaw import GPAW from gpaw.test import equal a = 4.05 d = a / 2**0.5 bulk = Atoms([Atom('Al', (0, 0, 0)), Atom('Al', (0.5, 0.5, 0.5))], pbc=True) bulk.set_cell((d, d, a), scale_atoms=True) h = 0.25 calc = GPAW(h=h, nbands=2*8, kpts=(2, 2, 2), convergence={'eigenstates': 7.2e-9, 'energy': 1e-5}) bulk.set_calculator(calc) e0 = bulk.get_potential_energy() niter0 = calc.get_number_of_iterations() calc = GPAW(h=h, nbands=2*8, kpts=(2, 2, 2), convergence={'eigenstates': 7.2e-9, 'energy': 1e-5, 'bands': 5 }, eigensolver='dav') bulk.set_calculator(calc) e1 = bulk.get_potential_energy() niter1 = calc.get_number_of_iterations() equal(e0, e1, 5.0e-5) energy_tolerance = 0.00004 niter_tolerance = 0 equal(e0, -6.97626, energy_tolerance) equal(e1, -6.976265, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/si_xas_nonortho.py0000664000175000017500000000432012553643471021157 0ustar jensjjensj00000000000000import os from math import pi, cos, sin from ase import Atom, Atoms from ase.parallel import rank, barrier from gpaw import GPAW, FermiDirac from gpaw.test import equal, gen from gpaw.xas import * #XAS, RecursionMethod import numpy as np from gpaw import setup_paths #setup_paths.insert(0, '.') # Generate setup for oxygen with half a core-hole: gen('Si', name='hch1s', corehole=(1, 0, 0.5)) a = 5.43095 b = a / 2 c = b / 2 d = b + c si_nonortho = Atoms([Atom('Si', (0, 0, 0)), Atom('Si', (a/4, a/4, a/4))], cell=[(a/2,a/2,0),(a/2,0,a/2),(0,a/2,a/2)], pbc=True) # calculation with full symmetry calc = GPAW(nbands=-10, h=0.25, kpts=(2,2,2), occupations=FermiDirac(width=0.05), setups={0: 'hch1s'}) si_nonortho.set_calculator(calc) e = si_nonortho.get_potential_energy() niter = calc.get_number_of_iterations() calc.write('si_nonortho_xas_sym.gpw') # calculation without any symmetry calc = GPAW(nbands=-10, h=0.25, kpts=(2,2,2), occupations=FermiDirac(width=0.05), setups={0: 'hch1s'}, symmetry='off') si_nonortho.set_calculator(calc) e = si_nonortho.get_potential_energy() niter = calc.get_number_of_iterations() calc.write('si_nonortho_xas_nosym.gpw') # restart from file calc1 = GPAW('si_nonortho_xas_sym.gpw') calc2 = GPAW('si_nonortho_xas_nosym.gpw') if mpi.size == 1: xas1 = XAS(calc1) x, y1 = xas1.get_spectra() xas2 = XAS(calc2) x2, y2 = xas2.get_spectra(E_in=x) assert (np.sum(abs(y1-y2)[0,:500] ** 2 ) < 5e-9) assert (np.sum(abs(y1-y2)[1,:500] ** 2 ) < 5e-9) assert (np.sum(abs(y1-y2)[2,:500] ** 2 ) < 5e-9) #else: # x = np.linspace(0, 10, 50) # #r1 = RecursionMethod(calc1) #r1.run(40) # #r2 = RecursionMethod(calc1) #r2.run(40) # #if mpi.size == 1: # y1 = r1.get_spectra(x) # y2 = r2.get_spectra(x) # # assert (np.sum(abs(y1-y2)[0,:] ** 2 ) < 5e-9) # assert (np.sum(abs(y1-y2)[1,:] ** 2 ) < 5e-9) # assert (np.sum(abs(y1-y2)[2,:] ** 2 ) < 5e-9) gpaw-0.11.0.13004/gpaw/test/nonselfconsistent.py0000664000175000017500000000201712553643471021522 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atoms from ase.units import Bohr from gpaw import GPAW from gpaw.test import equal a = 7.5 * Bohr n = 16 atoms = Atoms('He', [(0.0, 0.0, 0.0)], cell=(a, a, a), pbc=True) calc = GPAW(gpts=(n, n, n), nbands=1, xc='PBE') atoms.set_calculator(calc) e1 = atoms.get_potential_energy() niter1 = calc.get_number_of_iterations() e1ref = calc.get_reference_energy() de12 = calc.get_xc_difference('revPBE') calc.set(xc='revPBE') e2 = atoms.get_potential_energy() niter2 = calc.get_number_of_iterations() e2ref = calc.get_reference_energy() de21 = calc.get_xc_difference('PBE') print(e1ref + e1 + de12 - (e2ref + e2)) print(e1ref + e1 - (e2ref + e2 + de21)) print(de12, de21) equal(e1ref + e1 + de12, e2ref + e2, 8e-4) equal(e1ref + e1, e2ref + e2 + de21, 3e-3) calc.write('revPBE.gpw') de21b = GPAW('revPBE.gpw').get_xc_difference('PBE') equal(de21, de21b, 9e-8) energy_tolerance = 0.00005 niter_tolerance = 0 equal(e1, -0.07904951, energy_tolerance) equal(e2, -0.08147563, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/fixdensity.py0000664000175000017500000000162012553643471020131 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW from gpaw.test import equal # Self-consistent calculation: a = 2.5 slab = Atoms('Li', cell=(a, a, 2 * a), pbc=1) slab.calc = GPAW(kpts=(3,3,1), txt='li.txt', parallel=dict(kpt=1)) slab.get_potential_energy() slab.calc.write('Li.gpw') # Gamma point: e1 = slab.calc.get_eigenvalues(kpt=0)[0] # Fix density and continue: kpts = [(0,0,0)] slab.calc.set(fixdensity=True, nbands=5, kpts=kpts, symmetry='off', eigensolver='cg') slab.get_potential_energy() e2 = slab.calc.get_eigenvalues(kpt=0)[0] # Start from gpw-file: calc = GPAW('Li.gpw', fixdensity=True, nbands=5, kpts=kpts, symmetry='off', eigensolver='cg') calc.scf.reset() calc.get_potential_energy() e3 = calc.get_eigenvalues(kpt=0)[0] equal(e1, e2, 3e-5) equal(e1, e3, 3e-5) gpaw-0.11.0.13004/gpaw/test/ralda_energy_N2.py0000664000175000017500000000326312553643471020743 0ustar jensjjensj00000000000000from ase import Atoms from ase.structure import molecule from gpaw import GPAW from gpaw.xc.fxc import FXCCorrelation from gpaw.test import equal from gpaw.mpi import world if world.size == 1: scalapack1 = None scalapack2 = None elif world.size == 2: scalapack1 = (2, world.size // 2, 32) scalapack2 = None else: scalapack1 = (2, world.size // 2, 32) scalapack2 = (2, world.size // 4, 32) # N2 -------------------------------------- N2 = molecule('N2') N2.set_cell((2.5, 2.5, 3.5)) N2.center() calc = GPAW(mode='pw', eigensolver='rmm-diis', dtype=complex, xc='LDA', nbands=16, basis='dzp', convergence={'density': 1.e-6}) N2.set_calculator(calc) N2.get_potential_energy() calc.diagonalize_full_hamiltonian(nbands=80, scalapack=scalapack1) calc.write('N2.gpw', mode='all') ralda = FXCCorrelation('N2.gpw', xc='rALDA') Ec_N2 = ralda.calculate(ecut=[50]) # N --------------------------------------- N = Atoms('N', [(0,0,0)]) N.set_cell((2.5, 2.5, 3.5)) N.center() calc = GPAW(mode='pw', eigensolver='rmm-diis', dtype=complex, xc='LDA', basis='dzp', nbands=8, hund=True, convergence={'density': 1.e-6}) N.set_calculator(calc) N.get_potential_energy() calc.diagonalize_full_hamiltonian(nbands=80, scalapack=scalapack2) calc.write('N.gpw', mode='all') ralda = FXCCorrelation('N.gpw', xc='rALDA') Ec_N = ralda.calculate(ecut=[50]) # if rank == 0: # system('rm N2.gpw') # system('rm N.gpw') # system('rm fhxc_N2_rALDA_50_0.gpw') # system('rm fhxc_N_rALDA_50_0.gpw') equal(Ec_N2, -6.1651, 0.001,) equal(Ec_N, -1.1085, 0.001) gpaw-0.11.0.13004/gpaw/test/stdout.py0000664000175000017500000000133512553643471017270 0ustar jensjjensj00000000000000import sys class Out: def write(self, x): sys.__stdout__.write(x) raise RuntimeError('not silent') out, err = sys.stdout, sys.stderr sys.stdout = sys.stderr = Out() try: from gpaw import GPAW, FermiDirac from ase import Atom, Atoms a = 5.0 h = 0.2 calc = GPAW(h=h, nbands=1, kpts=(1, 1, 1), occupations=FermiDirac(width=1e-9), xc='PBE', txt=None) hydrogen = Atoms([Atom('H', (a / 2, a / 2, a / 2), magmom=0)], cell=(a, a, a), calculator=calc) f = hydrogen.get_forces() except Exception: sys.stdout = out sys.stderr = err raise sys.stdout = out sys.stderr = err gpaw-0.11.0.13004/gpaw/test/IP_oxygen.py0000664000175000017500000000135012553643471017644 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atom, Atoms from gpaw import GPAW from gpaw.test import equal a = 6.0 calc = GPAW(gpts=(32, 36, 32), nbands=4) O = Atoms([Atom('O', (a/2, a/2 + 0.5, a/2), magmom=2)], pbc=False, cell=(a, a + 1, a), calculator=calc) e0 = O.get_potential_energy() niter0 = calc.get_number_of_iterations() calc.set(charge=1) e1 = O.get_potential_energy() niter1 = calc.get_number_of_iterations() print(e1 - e0) assert abs(e1 - e0 - 13.989) < 0.04 energy_tolerance = 0.0002 niter_tolerance = 5 equal(e0, -1.88477, energy_tolerance) equal(e1, 12.11080, energy_tolerance) # The first ionization energy for LDA oxygen is from this paper: # In-Ho Lee, Richard M. Martin, Phys. Rev. B 56 7197 (1997) gpaw-0.11.0.13004/gpaw/test/d2Excdn2.py0000664000175000017500000000150412553643471017315 0ustar jensjjensj00000000000000from __future__ import print_function from gpaw.lrtddft import d2Excdnsdnt, d2Excdn2 import numpy as np dup=np.array([.1,.3]) ddn=np.array([.2,.005]) def equiv(xl,yl): for x,y in zip(xl,yl): # print x,y assert abs(x-y) < 1e-8 out=0 # unpolarised ...................................... expected=[ -0.99599492, -12.51604312] res=d2Excdn2(ddn) if out: print(res) equiv(xl=res,yl=expected) # polarised ........................................ isp=1 ksp=1 expected=[-1.6505808, -0.93437538] res=d2Excdnsdnt(dup,ddn) if out: print(res) equiv(res[isp][ksp],expected) isp=1 ksp=0 expected=[-0.18324442, -0.11948321] res=d2Excdnsdnt(dup,ddn) if out: print(res) equiv(res[isp][ksp],expected) isp=0 ksp=0 expected=[ -1.14670206, -11.02164441] res=d2Excdnsdnt(dup,ddn) if out: print(res) equiv(res[isp][ksp],expected) gpaw-0.11.0.13004/gpaw/test/xc.py0000664000175000017500000000634312553643471016364 0ustar jensjjensj00000000000000import numpy as np from gpaw.xc.libxc import LibXC, short_names from gpaw.xc.kernel import XCKernel, codes from gpaw.test import equal funcs = [] modes = [] for name in short_names: try: LibXC(name) except NameError: continue funcs.append(name) modes.append(0) for name in codes: funcs.append(name) modes.append(1) def create_xc(func, mode): isinstance(func, str) isinstance(mode, int) if mode == 0: xc = LibXC(func) else: xc = XCKernel(func) return xc def f1(n_xg, xc): e_g = np.empty_like(n_xg[0]) n_sg = n_xg[:1] sigma_xg = n_xg[1:2] tau_sg = n_xg[2:] dedn_sg = np.zeros_like(n_sg) dedsigma_xg = np.zeros_like(sigma_xg) dedtau_sg = np.zeros_like(tau_sg) xc.calculate(e_g, n_sg, dedn_sg, sigma_xg, dedsigma_xg, tau_sg, dedtau_sg) return e_g, np.concatenate((dedn_sg, dedsigma_xg, dedtau_sg)) def f2(n_xg, xc): e_g = np.empty_like(n_xg[0]) n_sg = n_xg[:2] sigma_xg = n_xg[2:5] tau_sg = n_xg[5:] dedn_sg = np.zeros_like(n_sg) dedsigma_xg = np.zeros_like(sigma_xg) dedtau_sg = np.zeros_like(tau_sg) xc.calculate(e_g, n_sg, dedn_sg, sigma_xg, dedsigma_xg, tau_sg, dedtau_sg) return e_g, np.concatenate((dedn_sg, dedsigma_xg, dedtau_sg)) eps = 1.0e-6 n_xg = np.array( [[0.2, 0.01, 0.4], [0.2, 0.1, 0.5], [0.01, 0.01, 0.2], [0.1, 0.3, 0.5]]).T.copy() for i, func in enumerate(funcs): xc = create_xc(funcs[i], modes[i]) e0_g, d0_xg = f1(n_xg, xc) d_xg = np.empty_like(d0_xg) for x, n_g in enumerate(n_xg): m_xg = n_xg.copy() m_xg[x] += eps d_xg[x] = 0.5 * f1(m_xg, xc)[0] / eps m_xg[x] -= 2 * eps d_xg[x] -= 0.5 * f1(m_xg, xc)[0] / eps ns_xg = np.empty((7, len(n_g))) ns_xg[:2] = n_xg[0] / 2 ns_xg[2:5] = n_xg[1] / 4 ns_xg[5:] = n_xg[2] / 2 es_g, ds_xg = f2(ns_xg, xc) error = (abs(d0_xg - d_xg).max() + abs(es_g - e0_g).max() + abs(ds_xg[:2] - d0_xg[0]).max() + abs(ds_xg[2:5].sum(0) / 4 - d0_xg[1]).max() + abs(ds_xg[5:] - d0_xg[2]).max()) equal(error, 0, 6e-9) del xc # Numbers from old lxc_xc.py test: na = 2.0 nb = 1.0 sigma0 = 2.0 # (0.0, 1.0, 1.0) sigma1 = 2.0 sigma2 = 5.0 # (1.0, 2.0, 0.0) taua = (3 * np.pi**2)**(2. / 3.) * na**(5. / 3.) / 2 * sigma0 taub = (3 * np.pi**2)**(2. / 3.) * nb**(5. / 3.) / 2 * sigma2 n_xg = np.array( [[na, nb, sigma0, sigma1, sigma2, taua, taub], [0.1, 0.1, 0.025, 0.025, 0.025, 0.25, 0.25], [0.1, 0.1, 0.125, 0.125, 0.125, 0.0025, 0.025], [0.1, 0.1, 0.01, 0.01, 0.01, 0.2, 0.2], [0.1, 0.2, 0.1, -0.08, 0.10, 0.01, 0.05], [0.1, 0.1, 0.1, 0.01, 0.01, 0.01, 0.01], [0.1, 0.1, 0.1, 0.15, 0.20, 0.01, 0.05]]).T.copy() for i, func in enumerate(funcs): xc = create_xc(funcs[i], modes[i]) if xc.type == 'MGGA': N_xg = n_xg[:, :1].copy() else: N_xg = n_xg e0_g, d0_xg = f2(N_xg, xc) d_xg = np.empty_like(d0_xg) for x, n_g in enumerate(N_xg): m_xg = N_xg.copy() m_xg[x] += eps d_xg[x] = 0.5 * f2(m_xg, xc)[0] / eps m_xg[x] -= 2 * eps d_xg[x] -= 0.5 * f2(m_xg, xc)[0] / eps equal(abs(d0_xg - d_xg).max(), 0, 2e-8) del xc gpaw-0.11.0.13004/gpaw/test/setup_derivatives.py0000664000175000017500000000041712553643471021513 0ustar jensjjensj00000000000000from __future__ import print_function from ase.structure import molecule from gpaw import GPAW, PW from gpaw.atom.derivatives import derivatives h2 = molecule('H2O') h2.center(vacuum=3) h2.calc = GPAW(txt='h2o700.txt', mode=PW(700), setups='new') print(derivatives(h2)) gpaw-0.11.0.13004/gpaw/test/graphene_EELS.py0000664000175000017500000001005212553643471020343 0ustar jensjjensj00000000000000import sys import numpy as np from ase.lattice.hexagonal import Graphene #import ase.io as io #from ase import Atoms, Atom from ase.visualize import view from ase.parallel import parprint as pp from gpaw import GPAW, PW, restart from gpaw.response.df import DielectricFunction from gpaw.mpi import world from gpaw.version import version from ase.lattice import bulk system = Graphene(symbol='C', latticeconstant={'a': 2.45,'c': 1.0}, size=(1,1,1)) system.pbc = (1, 1, 0) system.center(axis=2, vacuum=4.0) nkpts = 5 communicator = world.new_communicator(np.array([world.rank])) gpwname = 'dump.graphene.gpw' if world.rank == 0: calc = GPAW(mode='pw', kpts=(nkpts, nkpts, 1), communicator=communicator, xc='oldLDA', nbands=len(system) * 6, txt='gpaw.graphene.txt') system.set_calculator(calc) system.get_potential_energy() calc.write(gpwname, mode='all') world.barrier() parallel = dict(domain=(1, 1, 1), band=1) if world.size == 8: #parallel['domain'] = (1, 1, 2) parallel['band'] = 2 calc = GPAW(gpwname, txt=None, parallel=parallel, idiotproof=False) pp('after restart') q = np.array([1.0 / nkpts, 0., 0.]) w = np.linspace(0, 31.9, 320) dw = w[1] - w[0] def check(name, energies, loss, ref_energy, ref_peakloss): arg = loss.argmax() energy = energies[arg] peakloss = loss[arg] pp('check %s :: energy = %5.2f [%5.2f], peakloss = %.12f [%.12f]' % (name, energy, ref_energy, peakloss, ref_peakloss)) data = dict(name=name, peakloss=peakloss, energy=energy, ref_peakloss=ref_peakloss, ref_energy=ref_energy) return data def getpeak(energies, loss): arg = loss.argmax() energy = energies[arg] peakloss = loss[arg] return energy, peakloss scriptlines = [] loss_errs = [] energy_errs = [] def check(name, energy, peakloss, ref_energy, ref_loss): pp('check %s :: energy = %5.2f [%5.2f], peakloss = %.12f [%.12f]' % (name, energy, ref_energy, peakloss, ref_loss)) energy_errs.append(abs(energy - ref_energy)) loss_errs.append(abs(peakloss - ref_loss)) array = np.array template = """\ check_df('%s', %s, %s, %s, %s, **%s)""" def check_df(name, ref_energy, ref_loss, ref_energy_lfe, ref_loss_lfe, **kwargs_override): kwargs = dict(calc=calc, frequencies=w.copy(), eta=0.5, ecut=30, txt='df.%s.txt' % name) kwargs.update(kwargs_override) df = DielectricFunction(**kwargs) fname = 'dfdump.%s.dat' % name df.get_eels_spectrum('RPA',q_c=q,filename=fname) world.barrier() d = np.loadtxt(fname,delimiter=',') loss = d[:, 1] loss_lfe = d[:, 2] energies = d[:, 0] #import pylab as pl #fig = pl.figure() #ax1 = fig.add_subplot(111) #ax1.plot(d[:, 0], d[:, 1]/np.max(d[:, 1])) #ax1.plot(d[:, 0], d[:, 2]/np.max(d[:, 2])) #ax1.axis(ymin=0, ymax=1) #fig.savefig('fig.%s.pdf' % name) energy, peakloss = getpeak(energies, loss) energy_lfe , peakloss_lfe = getpeak(energies, loss_lfe) check(name, energy, peakloss, ref_energy, ref_loss) check('%s-lfe' % name, energy_lfe, peakloss_lfe, ref_energy_lfe, ref_loss_lfe) line = template % (name, energy, peakloss, energy_lfe, peakloss_lfe, repr(kwargs_override)) scriptlines.append(line) # These lines can be generated by the loop over 'scriptlines' below, # in case new reference values are wanted # The implementation for vcut choices has still to be done check_df('3d', 20.20, 2.505295593820, 26.90, 1.748517033160) #**{'rpad': array([1, 1, 1])}) #, 'vcut': '3D'}) #check_df('2d', 20.10, 2.449662058530, 26.80, 1.538080502420, # **{'rpad': array([1, 1, 1]), 'vcut': '2D'}) pp() pp('Insert lines into script to set new reference values:') for line in scriptlines: pp(line) pp() for err in energy_errs: # with the current grid this error just means assert err < dw / 4.0, err for err in loss_errs: assert err < 1e-6, err gpaw-0.11.0.13004/gpaw/test/lrtddft3.py0000664000175000017500000000762412553643471017503 0ustar jensjjensj00000000000000from __future__ import print_function import sys import re import numpy as np from ase.structure import molecule from ase.units import Hartree from gpaw import GPAW from gpaw.mpi import rank, world from gpaw.test import equal from gpaw.gauss import Gauss from gpaw.lrtddft import LrTDDFT, photoabsorption_spectrum from gpaw.lrtddft.kssingle import KSSingles try: from StringIO import StringIO # Python 2 except ImportError: from io import StringIO L = 10.0 txt=None txt='-' N2 = molecule('N2') N2.set_cell([L, L, L]) #N2.set_pbc(True) N2.center() try: calc = GPAW('N2_wfs.gpw', txt=txt, parallel={'domain': world.size}) calc.converge_wave_functions() except: calc = GPAW(h=0.25, nbands=-5, spinpol=True, xc='PBE', txt=txt, eigensolver='cg', parallel={'domain': world.size}) N2.set_calculator(calc) E0 = N2.get_potential_energy() calc.write('N2_wfs.gpw', 'all') # selections for obj in [KSSingles, LrTDDFT]: # selection using state numbers el = obj(calc, istart=3, jend=6, txt=txt) if hasattr(obj, 'diagonalize'): el.diagonalize() # print "*************** obj, len(obj)", obj.__name__, len(el) assert len(el) == 8 # selection using an energy range el = obj(calc, energy_range=8, txt=txt) if hasattr(obj, 'diagonalize'): el.diagonalize() # print "*************** obj, len(obj)", obj.__name__, len(el) assert len(el) == 4 el = obj(calc, energy_range=11.5, txt=txt) # print "*************** obj, len(obj)", obj.__name__, len(el) if hasattr(obj, 'diagonalize'): el.diagonalize() assert len(el) == 18 if hasattr(obj, 'diagonalize'): el.diagonalize(energy_range=8) assert len(el) == 4 lr = LrTDDFT(calc, nspins=2) lr.write('lrtddft3.dat.gz') lr.diagonalize() world.barrier() # This is done to test if writing and reading again yields the same result lr2 = LrTDDFT('lrtddft3.dat.gz') lr2.diagonalize() # Unfortunately not all of the lrtddft code is parallel if rank == 0: Epeak = 19.5# The peak we want to investigate (this is alone) Elist = np.asarray([lrsingle.get_energy() * Hartree for lrsingle in lr]) n = np.argmin(np.abs(Elist - Epeak)) # Index of the peak E = lr[n].get_energy() * Hartree osz = lr[n].get_oscillator_strength() print('Original object :', E, osz[0]) # Test the output of analyse origstdout = sys.stdout sys.stdout = sio = StringIO() lr.analyse(n) s = sio.getvalue() sys.stdout = origstdout match = re.findall(r'%i: E=([0-9]*\.[0-9]*) eV, f=([0-9]*\.[0-9]*)*' % n, s) Eanalyse = float(match[0][0]) oszanalyse = float(match[0][1]) print('From analyse :', Eanalyse, oszanalyse) equal(E, Eanalyse, 1e-3) # Written precision in analyse equal(osz[0], oszanalyse, 1e-3) E2 = lr2[n].get_energy() * Hartree osz2 = lr2[n].get_oscillator_strength() print('Written and read object:', E2, osz2[0]) # Compare values of original and written/read objects equal(E, E2, 1e-4) for i in range(len(osz)): equal(osz[i], osz2[i], 1.7e-4) width = 0.05 photoabsorption_spectrum(lr, spectrum_file = 'lrtddft3-spectrum.dat', width = width) # We need to be able to check the heights in the spectrum weight = Gauss(width).get(0) spectrum = np.loadtxt('lrtddft3-spectrum.dat', usecols = (0, 1)) idx = (spectrum[:, 0] >= E - 0.1) & (spectrum[:, 0] <= E + 0.1) peak = np.argmax(spectrum[idx, 1]) + np.nonzero(idx)[0][0] Espec = spectrum[peak, 0] oszspec = spectrum[peak, 1] / weight print('Values from spectrum :', Espec, oszspec) # Compare calculated values with values written to file equal(E, Espec, 1e-2) # The spectrum has a low sampling equal(osz[0], oszspec, 1e-2) gpaw-0.11.0.13004/gpaw/test/inducedfield_td.py0000664000175000017500000000473612553643471021064 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW from gpaw.tddft import TDDFT from gpaw.inducedfield.inducedfield_tddft import TDDFTInducedField import numpy as np # Na2 cluster atoms = Atoms(symbols='Na2', positions=[(0, 0, 0), (3.0, 0, 0)], pbc=False) atoms.center(vacuum=3.0) # Standard ground state calculation calc = GPAW(nbands=2, h=0.6, setups={'Na': '1'}) atoms.set_calculator(calc) energy = atoms.get_potential_energy() calc.write('na2_gs.gpw', mode='all') # Standard time-propagation initialization time_step = 10.0 iterations = 60 kick_strength = [1.0e-3, 1.0e-3, 0.0] td_calc = TDDFT('na2_gs.gpw') td_calc.absorption_kick(kick_strength=kick_strength) # Create and attach InducedField object frequencies = [1.0, 2.08] # Frequencies of interest in eV folding = 'Gauss' # Folding function width = 0.1 # Line width for folding in eV ind = TDDFTInducedField(paw=td_calc, frequencies=frequencies, folding=folding, width=width, restart_file='na2_td.ind') # Propagate as usual td_calc.propagate(time_step, iterations/2, 'na2_td_dm.dat', 'na2_td.gpw') # Save TDDFT and InducedField objects td_calc.write('na2_td.gpw', mode='all') ind.write('na2_td.ind') ind.paw = None # Restart and continue td_calc = TDDFT('na2_td.gpw') # Load and attach InducedField object ind = TDDFTInducedField(filename='na2_td.ind', paw=td_calc, restart_file='na2_td.ind') # Continue propagation as usual td_calc.propagate(time_step, iterations/2, 'na2_td_dm.dat', 'na2_td.gpw') # Calculate induced electric field ind.calculate_induced_field(gridrefinement=2, from_density='comp') # Test from gpaw.test import equal tol = 0.0001 val1 = ind.fieldgd.integrate(ind.Ffe_wg[0]) val2 = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[0][0])) val3 = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[0][1])) val4 = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[0][2])) val5 = ind.fieldgd.integrate(ind.Ffe_wg[1]) val6 = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[1][0])) val7 = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[1][1])) val8 = ind.fieldgd.integrate(np.abs(ind.Fef_wvg[1][2])) equal(val1, 3307.77279745, tol) equal(val2, 2.24614158834, tol) equal(val3, 2.20381741663, tol) equal(val4, 1.69244172329, tol) equal(val5, 3305.78925228, tol) equal(val6, 2.09432584636, tol) equal(val7, 2.09849354306, tol) equal(val8, 1.59727445257, tol) ind.paw = None gpaw-0.11.0.13004/gpaw/test/bse_MoS2_cut.py0000664000175000017500000000311212553643471020225 0ustar jensjjensj00000000000000import os import numpy as np from ase import * from ase.lattice.hexagonal import Hexagonal from gpaw import * from gpaw.response.bse import BSE from gpaw.mpi import rank calc = GPAW(h=0.2, xc='GLLBSC', nbands=20, setups={'Mo': '6'}, occupations=FermiDirac(0.001), convergence={'bands': -5}, kpts=(9,9,1)) a = 3.1604 c = 10.0 cell = Hexagonal(symbol='Mo', latticeconstant={'a':a, 'c':c}).get_cell() layer = Atoms(symbols='MoS2', cell=cell, pbc=(1,1,1), scaled_positions=[(0, 0, 0), (2/3., 1/3., 0.3), (2/3., 1/3., -0.3)]) pos = layer.get_positions() pos[1][2] = pos[0][2] + 3.172/2 pos[2][2] = pos[0][2] - 3.172/2 layer.set_positions(pos) layer.set_calculator(calc) layer.get_potential_energy() response = calc.hamiltonian.xc.xcs['RESPONSE'] response.calculate_delta_xc() E_ks, dis = response.calculate_delta_xc_perturbation() bse = BSE(calc, w=np.linspace(0., 5., 501), q=np.array([0.0001, 0., 0.]), optical_limit=True, ecut=10, eta=0.02, nv=np.array([8,9]), nc=np.array([9,10]), eshift=dis, nbands=15, mode='BSE', vcut='2D', ) bse.get_dielectric_function('bse_cut.dat') if rank == 0 and os.path.isfile('phi_qaGp'): os.remove('phi_qaGp') d = np.loadtxt('bse_cut.dat') Nw = 88 if d[Nw,2] > d[Nw-1,2] and d[Nw,2] > d[Nw+1,2]: pass else: raise ValueError('Absorption peak not correct ! ') gpaw-0.11.0.13004/gpaw/test/response_pair.py0000664000175000017500000000666212553643471020627 0ustar jensjjensj00000000000000import numpy as np from ase import Atoms from gpaw import GPAW, PW from gpaw.test import equal from gpaw.kpt_descriptor import KPointDescriptor from gpaw.wavefunctions.pw import PWDescriptor from gpaw.response.pair import PairDensity from gpaw.response.math_func import two_phi_nabla_planewave_integrals np.set_printoptions(precision=1) nb = 6 a = Atoms('H', cell=(3 * np.eye(3)), pbc=True) calc = GPAW(mode=PW(600), kpts=[[0, 0, 0], [0.25, 0, 0]]) a.calc = calc a.get_potential_energy() calc.diagonalize_full_hamiltonian(nbands=nb, expert=True) calc.write('a.gpw', 'all') pair = PairDensity('a.gpw', ecut=100) # Check continuity eq. for q_c in [[0, 0, 0], [1. / 4, 0, 0]]: ol = np.allclose(q_c, 0.0) qd = KPointDescriptor([q_c]) pd = PWDescriptor(pair.ecut, calc.wfs.gd, complex, qd) kptpair = pair.get_kpoint_pair(pd, s=0, K=0, n1=0, n2=nb, m1=0, m2=nb) deps_nm = kptpair.get_transition_energies(np.arange(0, nb), np.arange(0, nb)) n_nmG, n_nmv, _ = pair.get_pair_density(pd, kptpair, np.arange(0, nb), np.arange(0, nb), optical_limit=ol) n_nmvG = pair.get_pair_momentum(pd, kptpair, np.arange(0, nb), np.arange(0, nb)) if ol: n2_nmv = np.zeros_like(n_nmv) for n in range(0, nb): n2_nmv[n] = pair.optical_pair_velocity(n, np.arange(0, nb), kptpair.kpt1, kptpair.kpt2) # Check for nan's assert not np.isnan(n_nmG).any() assert not np.isnan(n_nmvG).any() if ol: assert not np.isnan(n_nmv).any() assert not np.isnan(n2_nmv).any() # PAW correction test if ol: print('Checking PAW corrections') # Check that PAW-corrections are # are equal to nabla-PAW corrections G_Gv = pd.get_reciprocal_vectors() for id, atomdata in pair.calc.wfs.setups.setups.items(): nabla_vii = atomdata.nabla_iiv.transpose((2, 0, 1)) Q_vGii = two_phi_nabla_planewave_integrals(G_Gv, atomdata) ni = atomdata.ni Q_vGii.shape = (3, -1, ni, ni) equal(nabla_vii.astype(complex), Q_vGii[:, 0], tolerance=1e-10, msg='Planewave-nabla PAW corrections not equal ' + 'to nabla PAW corrections when q + G = 0!') # Check optical limit nabla matrix elements err = np.abs(n_nmvG[..., 0] - n2_nmv) maxerr = np.max(err) arg = np.unravel_index(np.argmax(err), err.shape) equal(maxerr, 0.0, tolerance=1e-10, msg='G=0 pair densities wrong! ' + str(arg) + ' ') # Check longitudinal part of matrix elements print('Checking continuity eq.') G_Gv = pd.get_reciprocal_vectors() G2_G = np.sum(G_Gv**2.0, axis=1) n2_nmG = np.diagonal(np.dot(G_Gv, n_nmvG), axis1=0, axis2=3).copy() if ol: n2_nmG[..., 0] = n_nmvG[..., 0, 0] # Left hand side and right hand side of # continuity eq.: d/dr x J + d/dt n = 0 lhs_nmG = n2_nmG - G2_G[np.newaxis, np.newaxis] / 2. * n_nmG rhs_nmG = - deps_nm[..., np.newaxis] * n_nmG err = np.abs(lhs_nmG - rhs_nmG) maxerr = np.max(err) arg = np.unravel_index(np.argmax(err), rhs_nmG.shape) equal(maxerr, 0.0, tolerance=1e-3, msg='Calculated current does ' + 'not fulfill the continuity equation! ' + str(arg) + ' ') gpaw-0.11.0.13004/gpaw/test/refine.py0000664000175000017500000000223612553643471017217 0ustar jensjjensj00000000000000"""Test automatically write out of restart files""" from __future__ import print_function import os from gpaw import GPAW from ase import Atom, Atoms from gpaw.test import equal ##endings = ['nc'] endings = ['gpw'] try: import _gpaw_hdf5 endings.append('hdf5') except ImportError: pass for ending in endings: restart_wf = 'gpaw-restart-wf.' + ending # H2 H = Atoms([Atom('H', (0,0,0)), Atom('H', (0,0,1))]) H.center(vacuum=2.0) if 1: calc = GPAW(nbands=2, convergence={'eigenstates': 0.001, 'energy': 0.1, 'density': 0.1}) H.set_calculator(calc) H.get_potential_energy() calc.write(restart_wf, 'all') # refine the result directly calc.set(convergence={'energy': 0.00001}) Edirect = H.get_potential_energy() # refine the result after reading from a file H = GPAW(restart_wf, convergence={'energy': 0.00001}).get_atoms() Erestart = H.get_potential_energy() print(Edirect, Erestart) # Note: the different density mixing introduces small differences equal(Edirect, Erestart, 4e-5) gpaw-0.11.0.13004/gpaw/test/gemv.py0000664000175000017500000001145312553643471016706 0ustar jensjjensj00000000000000from __future__ import print_function import time import numpy as np from gpaw.utilities.blas import gemmdot, dotu, gemv def getrand(shape, dtype): if isinstance(shape, int): shape = (shape,) nelements = np.prod(shape) if dtype == float: return np.random.normal(size=nelements).reshape(shape) elif dtype == complex: return (np.random.uniform(size=nelements) * np.exp(1j \ * np.random.uniform(0,2*np.pi,size=nelements))).reshape(shape) else: raise ValueError('Unsupported dtype "%s".' % dtype) P = 12 Q = 1456 L = 378 G = 5013 dtype = float beta = 0.0 # note that beta=0.0 and beta=1.0 have different gemv subroutines refperf = 1e8 # each test should last roughly 1 s with this performance test_gemmdot = False # gemmdot is unbelievable slow for matrix-vector products mem = 0 itemsize = np.nbytes[np.dtype(dtype)] mem += P*Q*L*itemsize #B_pqL mem += L*itemsize #Y_L mem += P*Q*itemsize #BY_pq mem += Q*G*itemsize #n_qg mem += G*itemsize #x_g mem += Q*itemsize #nx_q print('Estimated memory: %8.5f MB' % (mem/1024**2.,)) B_pqL = getrand((P,Q,L), dtype) Y_L = getrand(L, dtype) n_qg = getrand((Q,G), dtype) x_g = getrand(G, dtype) # ------------------------------------------------------------------- print('\n%s\nBY_pq calculations\n%s\n' % ('='*40, '='*40)) numflop = (dtype==float and 2 or 8)*P*Q*L numreps = 1+int(refperf/numflop) # Reference value BY0_pq = np.dot(B_pqL, Y_L) t = time.time() for n in range(numreps): BY1_pq = np.dot(B_pqL, Y_L) t = time.time()-t performance = numflop*numreps/t print('dot : %8.5f s, %8.5f Mflops' % (t,performance/1024**2.)) assert np.abs(BY0_pq-BY1_pq).max()<5e-12 del BY1_pq if test_gemmdot: BY2_pq = np.empty((P,Q), dtype) t = time.time() for n in range(numreps): BY2_pq.fill(0.0) gemmdot(B_pqL, Y_L, 1.0, beta, BY2_pq) t = time.time()-t performance = numflop*numreps/t print('gemmdot: %8.5f s, %8.5f Mflops' % (t,performance/1024**2.)) assert np.abs(BY0_pq-BY2_pq).max()<5e-12 del BY2_pq BY3_pq = np.empty((P,Q), dtype) t = time.time() for n in range(numreps): BY3_pq.fill(0.0) gemv(1.0, B_pqL, Y_L, beta, BY3_pq, 't') t = time.time()-t performance = numflop*numreps/t print('gemvT : %8.5f s, %8.5f Mflops' % (t,performance/1024**2.)) assert np.abs(BY0_pq-BY3_pq).max()<5e-12 del BY3_pq B_xL = B_pqL.reshape((P*Q,L)) BY4_x = np.empty(P*Q, dtype) t = time.time() for n in range(numreps): BY4_x.fill(0.0) gemv(1.0, B_xL, Y_L, beta, BY4_x, 't') t = time.time()-t performance = numflop*numreps/t print('gemvT2D: %8.5f s, %8.5f Mflops' % (t,performance/1024**2.)) assert np.abs(BY0_pq-BY4_x.reshape((P,Q))).max()<5e-12 del B_xL, BY4_x BT_Lqp = B_pqL.T.copy() BY5T_qp = np.empty((Q,P), dtype) t = time.time() for n in range(numreps): BY5T_qp.fill(0.0) gemv(1.0, BT_Lqp, Y_L, beta, BY5T_qp, 'n') t = time.time()-t performance = numflop*numreps/t print('gemvN : %8.5f s, %8.5f Mflops' % (t,performance/1024**2.)) assert np.abs(BY0_pq-BY5T_qp.T).max()<5e-12 del BT_Lqp, BY5T_qp BT_Lx = B_pqL.T.reshape((L,Q*P)).copy() BY6T_x = np.empty(Q*P, dtype) t = time.time() for n in range(numreps): BY6T_x.fill(0.0) gemv(1.0, BT_Lx, Y_L, beta, BY6T_x, 'n') t = time.time()-t performance = numflop*numreps/t print('gemvN2D: %8.5f s, %8.5f Mflops' % (t,performance/1024**2.)) assert np.abs(BY0_pq-BY6T_x.reshape((Q,P)).T).max()<5e-12 del BT_Lx, BY6T_x # ------------------------------------------------------------------- print('\n%s\nnx_q calculations\n%s\n' % ('='*40, '='*40)) numflop = (dtype==float and 2 or 8)*Q*G numreps = 1+int(refperf/numflop) # Reference value nx0_q = np.dot(n_qg, x_g) t = time.time() for n in range(numreps): nx1_q = np.dot(n_qg, x_g) t = time.time()-t performance = numflop*numreps/t print('dot : %8.5f s, %8.5f Mflops' % (t,performance/1024**2.)) assert np.abs(nx0_q-nx1_q).max()<5e-12 del nx1_q if test_gemmdot: nx2_q = np.empty(Q, dtype) t = time.time() for n in range(numreps): nx2_q.fill(0.0) gemmdot(n_qg, x_g, 1.0, beta, nx2_q) t = time.time()-t performance = numflop*numreps/t print('gemmdot: %8.5f s, %8.5f Mflops' % (t,performance/1024**2.)) assert np.abs(nx0_q-nx2_q).max()<5e-12 del nx2_q nx3_q = np.empty(Q, dtype) t = time.time() for n in range(numreps): nx3_q.fill(0.0) gemv(1.0, n_qg, x_g, beta, nx3_q, 't') t = time.time()-t performance = numflop*numreps/t print('gemvT : %8.5f s, %8.5f Mflops' % (t,performance/1024**2.)) assert np.abs(nx0_q-nx3_q).max()<5e-12 del nx3_q nT_gq = n_qg.T.copy() nx4_q = np.empty(Q, dtype) t = time.time() for n in range(numreps): nx4_q.fill(0.0) gemv(1.0, nT_gq, x_g, beta, nx4_q, 'n') t = time.time()-t performance = numflop*numreps/t print('gemvN : %8.5f s, %8.5f Mflops' % (t,performance/1024**2.)) assert np.abs(nx0_q-nx4_q).max()<5e-12 del nT_gq, nx4_q gpaw-0.11.0.13004/gpaw/test/fileio/0000775000175000017500000000000012553644063016637 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/fileio/restart_density.py0000664000175000017500000000375612553643471022451 0ustar jensjjensj00000000000000from __future__ import print_function import os from gpaw import GPAW, restart from ase import Atoms from gpaw.test import equal from math import sqrt import numpy as np modes = ['gpw'] try: import _gpaw_hdf5 modes.append('hdf5') except ImportError: pass d = 3.0 atoms = Atoms('Na3', positions=[( 0, 0, 0), ( 0, 0, d), ( 0, d*sqrt(3./4.), d/2.)], magmoms=[1.0, 1.0, 1.0], cell=(3.5, 3.5, 4.+2/3.), pbc=True) # Only a short, non-converged calcuation conv = {'eigenstates': 1.e-3, 'energy':1e-2, 'density':1e-1} calc = GPAW(h=0.30, nbands=3, setups={'Na': '1'}, convergence=conv) atoms.set_calculator(calc) e0 = atoms.get_potential_energy() niter0 = calc.get_number_of_iterations() f0 = atoms.get_forces() m0 = atoms.get_magnetic_moments() eig00 = calc.get_eigenvalues(spin=0) eig01 = calc.get_eigenvalues(spin=1) # Write the restart file(s) for mode in modes: calc.write('tmp.%s' % mode) del atoms, calc # Try restarting from all the files for mode in modes: atoms, calc = restart('tmp.%s' % mode) # Force new calculation calc.scf.converged = False e1 = atoms.get_potential_energy() f1 = atoms.get_forces() m1 = atoms.get_magnetic_moments() eig10 = calc.get_eigenvalues(spin=0) eig11 = calc.get_eigenvalues(spin=1) print(e0, e1) equal(e0, e1, 2e-3) print(f0, f1) for ff0, ff1 in zip(f0, f1): err = np.linalg.norm(ff0-ff1) # for forces we use larger tolerance equal(err, 0.0, 4e-2) print(m0, m1) for mm0, mm1 in zip(m0, m1): equal(mm0, mm1, 2e-3) print('A',eig00, eig10) for eig0, eig1 in zip(eig00, eig10): equal(eig0, eig1, 5e-3) print('B',eig01, eig11) for eig0, eig1 in zip(eig01, eig11): equal(eig0, eig1, 2e-2) niter1 = calc.get_number_of_iterations() # Check that after restart everythnig is writable calc.write('tmp2.%s' % mode) gpaw-0.11.0.13004/gpaw/test/fileio/file_reference.py0000664000175000017500000000253112553643471022151 0ustar jensjjensj00000000000000import os from gpaw import GPAW, restart from ase import Atoms from gpaw.test import equal from gpaw.mpi import world, rank from math import sqrt import numpy as np # Test the reading of wave functions as file references modes = ['gpw'] try: import _gpaw_hdf5 modes.append('hdf5') except ImportError: pass d = 3.0 atoms = Atoms('Na3', positions=[( 0, 0, 0), ( 0, 0, d), ( 0, d*sqrt(3./4.), d/2.)], magmoms=[1.0, 1.0, 1.0], cell=(3.5, 3.5, 4.+2/3.), pbc=True) # Only a short, non-converged calcuation conv = {'eigenstates': 1.24, 'energy':2e-1, 'density':1e-1} calc = GPAW(h=0.30, kpts=(1,1,3), setups={'Na': '1'}, nbands=3, convergence=conv) atoms.set_calculator(calc) e0 = atoms.get_potential_energy() wf0 = calc.get_pseudo_wave_function(2, 1, 1, broadcast=True) # Write the restart file(s) for mode in modes: calc.write('tmp.%s' % mode, 'all') del calc # Now read with single process comm = world.new_communicator(np.array((rank,))) for mode in modes: calc = GPAW('tmp.%s' % mode, communicator=comm) wf1 = calc.get_pseudo_wave_function(2, 1, 1) diff = np.abs(wf0 - wf1) assert(np.all(diff < 1e-12)) world.barrier() if rank == 0: for mode in modes: os.remove('tmp.%s' % mode) gpaw-0.11.0.13004/gpaw/test/fileio/hdf5_noncontiguous.py0000664000175000017500000000154612553643471023041 0ustar jensjjensj00000000000000import numpy as np import os from gpaw.io.hdf5_highlevel import File from gpaw.mpi import world, rank # write a slice of NumPy array data = np.arange(10, dtype=float) sub = data[::2] if world.size > 1: comm = world.get_c_object() else: comm = None file = File('tmp.hdf5', 'w', comm=comm) dset = file.create_dataset('noncont', sub.shape, sub.dtype) if rank == 0: selection = 'all' else: selection = None dset.write(sub, selection) dset.close() file.close() # read data back file = File('tmp.hdf5', 'r', comm=comm) dset = file['noncont'] new_data = np.ndarray(dset.shape, dset.dtype, order='C') dset.read(new_data) assert((new_data == sub).all) # read also to noncontiguous array new_data = np.zeros(10, float) new_sub = new_data[::2] dset.read(new_sub) assert((new_sub == sub).all) dset.close() file.close() if rank == 0: os.remove('tmp.hdf5') gpaw-0.11.0.13004/gpaw/test/fileio/parallel.py0000664000175000017500000000237412553643471021015 0ustar jensjjensj00000000000000from gpaw import GPAW, ConvergenceError, restart from gpaw.eigensolvers.rmm_diis_old import RMM_DIIS from gpaw.mixer import MixerSum from gpaw.test import equal from ase.lattice import bulk modes = ['gpw'] try: import _gpaw_hdf5 modes.append('hdf5') except ImportError: pass # bulk Fe with k-point, band, and domain parallelization a = 2.87 atoms = bulk('Fe', 'bcc', a=a) atoms.set_initial_magnetic_moments([2.2,]) calc = GPAW(h=0.20, eigensolver=RMM_DIIS(), mixer=MixerSum(0.1,3), nbands=6, kpts=(4,4,4), parallel={'band' : 2, 'domain' : (2,1,1)}, maxiter=4) atoms.set_calculator(calc) try: atoms.get_potential_energy() except ConvergenceError: pass for mode in modes: calc.write('tmp.%s' % mode, mode='all') # Continue calculation for few iterations for mode in modes: atoms, calc = restart('tmp.%s' % mode, eigensolver=RMM_DIIS(), mixer=MixerSum(0.1,3), parallel={'band' : 2, 'domain' : (1,1,2)}, maxiter=4) try: atoms.get_potential_energy() except ConvergenceError: pass e = calc.hamiltonian.Etot equal(e, -0.372602008394, 0.000001) gpaw-0.11.0.13004/gpaw/test/fileio/__init__.py0000664000175000017500000000000012553643471020740 0ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/fileio/idiotproof_setup.py0000664000175000017500000000054612553643471022616 0ustar jensjjensj00000000000000from ase.structure import molecule from gpaw import GPAW import warnings # Silence those warnings. warnings.filterwarnings('ignore', 'Setup for',) m = molecule('H') m.center(vacuum=2.0) calc = GPAW(mode='lcao') m.set_calculator(calc) m.get_potential_energy() calc.write('r.gpw') calc = GPAW('r.gpw', xc='PBE', idiotproof=False) calc.get_potential_energy() gpaw-0.11.0.13004/gpaw/test/fileio/hdf5_simple.py0000664000175000017500000000527412553643471021422 0ustar jensjjensj00000000000000import numpy as np import os from gpaw.io.hdf5_highlevel import File, HyperslabSelection from gpaw.mpi import world, rank, size # data to be written attrs = {'int' : 42, 'float' : 6.2, 'complex' : 1.0 + 2.0j, 'bool1' : False, 'bool2' : True, 'data' : np.array(((1,2),(3,4)))} datasize = 4 data = {} for dtype in ['int', 'float', 'complex']: data[dtype] = np.arange(rank * datasize, rank * datasize + datasize, dtype = dtype) data['bool'] = np.array([True, False, False, True]) def write(attrs, data, file, parallel): file_title = 'test file' file.attrs['title'] = file_title grp = file.create_group('group1') # write attributes for key, val in attrs.items(): grp.attrs[key] = val # write datasets shape = (datasize * size,) for key, val in data.items(): dset = grp.create_dataset(key, shape, val.dtype) indices = slice(rank * datasize, (rank + 1) * datasize) selection = HyperslabSelection(indices, dset.shape) dset.write(val, selection, collective=parallel) def read(attrs, data, file, parallel): file_title = file.attrs['title'] assert(file_title == 'test file') grp = file['group1'] # read attributes for key, val in attrs.items(): new_val = grp.attrs[key] if key == 'data': assert((new_val == val).all()) else: assert(new_val == val) # read data for key, val in data.items(): dset = grp[key] indices = slice((size - rank - 1) * datasize, (size - rank) * datasize) selection = HyperslabSelection(indices, dset.shape) new_val = np.ndarray(selection.mshape, dset.dtype, order='C') dset.read(new_val, selection, collective=parallel) assert((new_val == val).all) # read data in reversed order for key in data: if key == 'bool': continue dset = grp[key] indices = slice((size - rank - 1) * datasize, (size - rank) * datasize) selection = HyperslabSelection(indices, dset.shape) new_val = np.ndarray(selection.mshape, dset.dtype, order='C') dset.read(new_val, selection, collective=parallel) ref_val = np.arange((size - rank - 1) * datasize, (size - rank) * datasize, dtype=key) assert((new_val == ref_val).all) if world.size > 1: comm = world.get_c_object() parallel = True else: comm = None parallel = False file = File('tmp.hdf5', 'w', comm=comm) write(attrs, data, file, parallel) file.close() file = File('tmp.hdf5', 'r', comm=comm) read(attrs, data, file, parallel) file.close() if rank == 0: os.remove('tmp.hdf5') gpaw-0.11.0.13004/gpaw/test/atomize.py0000664000175000017500000000500512553643471017414 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atom, Atoms from gpaw import GPAW, PoissonSolver from gpaw.test import equal from gpaw.xc.hybrid import HybridXC a = 6. # Size of unit cell (Angstrom) c = a / 2 # Hydrogen atom: atom = Atoms([Atom('H', (c, c, c), magmom=1)], cell=(a, a, a), pbc=False) # gpaw calculator: calc = GPAW(gpts=(32, 32, 32), nbands=1, xc='PBE', txt='H.txt', convergence=dict(eigenstates=3.3e-8)) atom.set_calculator(calc) e1 = atom.get_potential_energy() niter1 = calc.get_number_of_iterations() de1t = calc.get_xc_difference('TPSS') de1m = calc.get_xc_difference('M06L') de1x = calc.get_xc_difference(HybridXC('EXX', finegrid=True)) de1xb = calc.get_xc_difference(HybridXC('EXX', finegrid=False)) # Hydrogen molecule: d = 0.74 # Experimental bond length molecule = Atoms([Atom('H', (c - d / 2, c, c)), Atom('H', (c + d / 2, c, c))], cell=(a, a, a), pbc=False) calc.set(txt='H2.txt') molecule.set_calculator(calc) e2 = molecule.get_potential_energy() niter2 = calc.get_number_of_iterations() de2t = calc.get_xc_difference('TPSS') de2m = calc.get_xc_difference('M06L') de2x = calc.get_xc_difference(HybridXC('EXX', finegrid=True)) de2xb = calc.get_xc_difference(HybridXC('EXX', finegrid=False)) print('hydrogen atom energy: %5.2f eV' % e1) print('hydrogen molecule energy: %5.2f eV' % e2) print('atomization energy: %5.2f eV' % (2 * e1 - e2)) print('atomization energy TPSS: %5.2f eV' % (2 * (e1 + de1t) - (e2 + de2t))) print('atomization energy M06L: %5.2f eV' % (2 * (e1 + de1m) - (e2 + de2m))) print('atomization energy EXX: %5.2f eV' % (2 * (e1 + de1x) - (e2 + de2x))) print('atomization energy EXX: %5.2f eV' % (2 * (e1 + de1xb) - (e2 + de2xb))) PBETPSSdifference = (2 * e1 - e2) - (2 * (e1 + de1t) - (e2 + de2t)) PBEM06Ldifference = (2 * e1 - e2) - (2 * (e1 + de1m) - (e2 + de2m)) PBEEXXdifference = (2 * e1 - e2) - (2 * (e1 + de1x) - (e2 + de2x)) PBEEXXbdifference = (2 * e1 - e2) - (2 * (e1 + de1xb) - (e2 + de2xb)) print(PBETPSSdifference) print(PBEM06Ldifference) print(PBEEXXdifference) print(PBEEXXbdifference) # TPSS value is from JCP 120 (15) 6898, 2004 # e.g. Table VII: DE(PBE - TPSS) = (104.6-112.9)*kcal/mol # EXX value is from PRL 77, 3865 (1996) equal(PBETPSSdifference, -0.3599, 0.04) equal(PBEM06Ldifference, -0.169, 0.01) equal(PBEEXXdifference, 0.91, 0.005) equal(PBEEXXbdifference, 0.91, 0.005) energy_tolerance = 0.0002 niter_tolerance = 0 equal(e1, -1.081638, energy_tolerance) equal(e2, -6.726356, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/__init__.py0000664000175000017500000006040012553643471017503 0ustar jensjjensj00000000000000import os import gc import sys import time import signal import traceback import numpy as np from ase.utils import devnull from gpaw.atom.generator import Generator from gpaw.atom.configurations import parameters, tf_parameters from gpaw.utilities import compiled_with_sl from gpaw import setup_paths from gpaw import mpi import gpaw def equal(x, y, tolerance=0, fail=True, msg=''): """Compare x and y.""" if not np.isfinite(x - y).any() or (np.abs(x - y) > tolerance).any(): msg = (msg + '%s != %s (error: |%s| > %.9g)' % (x, y, x - y, tolerance)) if fail: raise AssertionError(msg) else: sys.stderr.write('WARNING: %s\n' % msg) def findpeak(x, y): dx = x[1] - x[0] i = y.argmax() a, b, c = np.polyfit([-1, 0, 1], y[i - 1:i + 2], 2) assert a < 0 x = -0.5 * b / a return dx * (i + x), a * x**2 + b * x + c def gen(symbol, exx=False, name=None, **kwargs): if mpi.rank == 0: if 'scalarrel' not in kwargs: kwargs['scalarrel'] = True g = Generator(symbol, **kwargs) if 'orbital_free' in kwargs: g.run(exx=exx, name=name, use_restart_file=False, **tf_parameters.get(symbol, {'rcut': 0.9})) else: g.run(exx=exx, name=name, use_restart_file=False, **parameters[symbol]) mpi.world.barrier() if setup_paths[0] != '.': setup_paths.insert(0, '.') def wrap_pylab(names=[]): """Use Agg backend and prevent windows from popping up.""" import matplotlib matplotlib.use('Agg') import pylab def show(names=names): if names: name = names.pop(0) else: name = 'fig.png' pylab.savefig(name) pylab.show = show tests = [ 'gemm_complex.py', 'ase3k_version.py', 'kpt.py', 'mpicomm.py', 'numpy_core_multiarray_dot.py', 'fileio/hdf5_noncontiguous.py', 'cg2.py', 'laplace.py', 'lapack.py', 'eigh.py', 'parallel/submatrix_redist.py', 'second_derivative.py', 'parallel/parallel_eigh.py', 'gp2.py', 'blas.py', 'Gauss.py', 'nabla.py', 'dot.py', 'mmm.py', 'lxc_fxc.py', 'pbe_pw91.py', 'gradient.py', 'erf.py', 'lf.py', 'fsbt.py', 'parallel/compare.py', 'integral4.py', 'zher.py', 'gd.py', 'pw/interpol.py', 'screened_poisson.py', 'xc.py', 'XC2.py', 'yukawa_radial.py', 'dump_chi0.py', 'vdw/potential.py', 'lebedev.py', 'fileio/hdf5_simple.py', 'occupations.py', 'derivatives.py', 'parallel/realspace_blacs.py', 'pw/reallfc.py', 'parallel/pblas.py', 'non_periodic.py', 'spectrum.py', 'pw/lfc.py', 'gauss_func.py', 'multipoletest.py', 'noncollinear/xcgrid3d.py', 'cluster.py', 'poisson.py', 'poisson_asym.py', 'parallel/arraydict_redist.py', 'parallel/overlap.py', 'parallel/scalapack.py', 'gauss_wave.py', 'transformations.py', 'parallel/blacsdist.py', 'pbc.py', 'noncollinear/xccorr.py', 'atoms_too_close.py', 'harmonic.py', 'proton.py', 'atoms_mismatch.py', 'setup_basis_spec.py', 'timing.py', # ~1s 'parallel/ut_parallel.py', # ~1s 'lcao_density.py', # ~1s 'parallel/hamiltonian.py', # ~1s 'pw/stresstest.py', # ~1s 'pw/fftmixer.py', # ~1s 'usesymm.py', # ~1s 'coulomb.py', # ~1s 'xcatom.py', # ~1s 'force_as_stop.py', # ~1s 'vdwradii.py', # ~1s 'ase3k.py', # ~1s 'numpy_zdotc_graphite.py', # ~1s 'eed.py', # ~1s 'lcao_dos.py', # ~1s 'solvation/pbc_pos_repeat.py', # ~1s 'gemv.py', # ~2s 'fileio/idiotproof_setup.py', # ~2s 'ylexpand.py', # ~2s 'keep_htpsit.py', # ~2s 'gga_atom.py', # ~2s 'hydrogen.py', # ~2s 'restart2.py', # ~2s 'aeatom.py', # ~2s 'plt.py', # ~2s 'ds_beta.py', # ~2s 'multipoleH2O.py', # ~2s 'noncollinear/h.py', # ~2s 'stdout.py', # ~2s 'lcao_largecellforce.py', # ~2s 'parallel/scalapack_diag_simple.py', # ~2s 'fixdensity.py', # ~2s 'pseudopotential/ah.py', # ~2s 'lcao_restart.py', # ~2s 'lcao_tddft.py', # ~2s 'wfs_io.py', # ~3s 'lrtddft2.py', # ~3s 'fileio/file_reference.py', # ~3s 'cmrtest/cmr_test2.py', # ~3s 'restart.py', # ~3s 'broydenmixer.py', # ~3s 'pw/fulldiagk.py', # ~3s 'external_potential.py', # ~3s 'lcao_atomic_corrections.py', # ~3s 'mixer.py', # ~3s 'parallel/lcao_projections.py', # ~3s 'lcao_h2o.py', # ~3s 'h2o_xas.py', # ~3s 'wfs_auto.py', # ~3s 'pw/fulldiag.py', # ~3s 'symmetry_ft.py', # ~3s 'aluminum_EELS_RPA.py', # ~3s 'poisson_extended.py', # ~3s 'solvation/vacuum.py', # ~3s 'pseudopotential/sg15_hydrogen.py', # ~4s 'ewald.py', # ~4s 'symmetry.py', # ~4s 'revPBE.py', # ~4s 'nonselfconsistentLDA.py', # ~4s 'aluminum_EELS_ALDA.py', # ~4s 'spin_contamination.py', # ~4s 'inducedfield_lrtddft.py', # ~4s 'H_force.py', # ~4s 'usesymm2.py', # ~4s 'mgga_restart.py', # ~4s 'fixocc.py', # ~4s 'spinFe3plus.py', # ~4s 'fermisplit.py', # ~4s 'Cl_minus.py', # ~4s 'ts09.py', # ~4s 'h2o_xas_recursion.py', # ~5s 'nonselfconsistent.py', # ~5s 'spinpol.py', # ~5s 'exx_acdf.py', # ~5s 'cg.py', # ~5s 'kptpar.py', # ~5s 'elf.py', # ~5s 'blocked_rmm_diis.py', # ~5s 'pw/slab.py', # ~5s 'si.py', # ~5s 'lcao_bsse.py', # ~5s 'parallel/lcao_hamiltonian.py', # ~5s 'degeneracy.py', # ~5s 'refine.py', # ~5s 'solvation/pbc.py', # ~5s 'asym_box.py', # ~5s 'gemm.py', # ~6s 'al_chain.py', # ~6s 'fileio/parallel.py', # ~6s 'fixmom.py', # ~6s 'exx_unocc.py', # ~6s 'davidson.py', # ~6s 'aedensity.py', # ~7s 'pw/h.py', # ~7s 'apmb.py', # ~7s 'pseudopotential/hgh_h2o.py', # ~7s 'ed_wrapper.py', # ~7s 'pw/bulk.py', # ~7s 'ne_gllb.py', # ~7s 'ed.py', # ~7s 'lcao_force.py', # ~7s 'fileio/restart_density.py', # ~8s 'rpa_energy_Ni.py', # ~8s 'be_nltd_ip.py', # ~8s 'test_ibzqpt.py', # ~8s 'si_primitive.py', # ~9s 'inducedfield_td.py', # ~9s 'ehrenfest_nacl.py', # ~9s 'fd2lcao_restart.py', # ~9s 'gw_method.py', # ~9s 'constant_electric_field.py', # ~9s 'complex.py', # ~9s 'vdw/quick.py', # ~9s 'bse_aluminum.py', # ~10s 'Al2_lrtddft.py', # ~10s 'ralda_energy_N2.py', # ~10s 'gw_ppa.py', # ~10s 'parallel/lcao_complicated.py', # ~10s 'bulk.py', # ~10s 'scfsic_h2.py', # ~10s 'lcao_bulk.py', # ~11s '2Al.py', # ~11s 'kssingles_Be.py', # ~11s 'relax.py', # ~11s 'pw/mgo_hybrids.py', # ~11s 'solvation/adm12.py', # ~11s 'dscf_lcao.py', # ~12s '8Si.py', # ~12s 'partitioning.py', # ~12s 'lxc_xcatom.py', # ~12s 'solvation/sfgcm06.py', # ~12s 'solvation/sss09.py', # ~12s 'gllbatomic.py', # ~13s 'guc_force.py', # ~13s 'ralda_energy_Ni.py', # ~13s 'simple_stm.py', # ~13s 'ofdft_pbc.py', # ~13s 'ed_shapes.py', # ~14s 'restart_band_structure.py', # ~14s 'exx.py', # ~14s 'Hubbard_U.py', # ~15s 'rpa_energy_Si.py', # ~15s 'dipole.py', # ~15s 'IP_oxygen.py', # ~15s 'rpa_energy_Na.py', # ~15s 'parallel/fd_parallel.py', # ~15s 'solvation/poisson.py', # ~15s 'solvation/water_water.py', # ~15s 'parallel/lcao_parallel.py', # ~16s 'atomize.py', # ~16s 'excited_state.py', # ~16s 'ne_disc.py', # ~16s 'ofdft.py', # ~17s 'tpss.py', # ~18s 'td_na2.py', # ~18s 'exx_coarse.py', # ~18s 'pplda.py', # ~18s 'si_xas.py', # ~18s 'mgga_sc.py', # ~19s 'Hubbard_U_Zn.py', # ~20s # buildbot > 20 sec tests start here (add tests after lrtddft.py!) 'lrtddft.py', # ~20s 'gllbspin.py', # ~21s 'parallel/fd_parallel_kpt.py', # ~21s 'pw/hyb.py', # ~21s 'Cu.py', # ~21s 'response_na_plasmon.py', # ~22s 'bse_diamond.py', # ~23s 'fermilevel.py', # ~23s 'parallel/ut_hsblacs.py', # ~23s 'ralda_energy_H2.py', # ~23s 'diamond_absorption.py', # ~24s 'ralda_energy_Si.py', # ~24s 'ldos.py', # ~25s 'solvation/swap_atoms.py', # ~25s 'revPBE_Li.py', # ~26s 'ofdft_scale.py', # ~26s 'parallel/lcao_parallel_kpt.py', # ~29s 'h2o_dks.py', # ~30s 'nsc_MGGA.py', # ~32s 'solvation/spinpol.py', # ~32s 'diamond_gllb.py', # ~33s 'MgO_exx_fd_vs_pw.py', # ~37s 'vdw/quick_spin.py', # ~37s 'expert_diag.py', # ~37s 'bse_sym.py', # ~40s 'parallel/ut_hsops.py', # ~41s 'LDA_unstable.py', # ~42s 'au02_absorption.py', # ~44s 'wannierk.py', # ~45s 'bse_vs_lrtddft.py', # ~45s 'aluminum_testcell.py', # ~46s 'pygga.py', # ~47s 'ut_tddft.py', # ~49s 'response_pair.py', # ~50s 'rpa_energy_N2.py', # ~52s 'vdw/ar2.py', # ~53s 'solvation/forces_symmetry.py', # ~56s 'parallel/diamond_gllb.py', # ~59s 'beef.py', 'pw/si_stress.py', # ~61s 'chi0.py', # ~71s 'scfsic_n2.py', # ~73s 'transport.py', # ~73s 'lrtddft3.py', # ~75s 'nonlocalset.py', # ~82s # buildbot > 100 sec tests start here (add tests after lb94.py!) 'lb94.py', # ~84s 'AA_exx_enthalpy.py', # ~119s 'lcao_tdgllbsc.py', # ~132s 'solvation/forces.py', # ~140s 'bse_silicon.py', # ~143s 'gwsi.py', # ~147s 'response_graphene.py', # ~160s 'response_symmetry.py', # ~300s 'pw/moleculecg.py', # duration unknown 'potential.py', # duration unknown 'pes.py', # duration unknown 'lcao_pair_and_coulomb.py', # duration unknown 'asewannier.py', # duration unknown 'exx_q.py', # duration unknown 'pw/davidson_pw.py', # duration unknown 'neb.py', # duration unknown 'diamond_eps.py', # duration unknown 'wannier_ethylene.py', # duration unknown 'muffintinpot.py', # duration unknown 'nscfsic.py', # duration unknown 'coreeig.py', # duration unknown 'bse_MoS2_cut.py', # duration unknown 'parallel/scalapack_mpirecv_crash.py', # duration unknown 'cmrtest/cmr_test.py', # duration unknown 'cmrtest/cmr_test3.py', # duration unknown 'cmrtest/cmr_test4.py', # duration unknown 'cmrtest/cmr_append.py', # duration unknown 'cmrtest/Li2_atomize.py'] # duration unknown # 'fractional_translations.py', # 'graphene_EELS.py', disabled while work is in progress on response code # 'fractional_translations_med.py', # 'fractional_translations_big.py', # 'eigh_perf.py', # Requires LAPACK 3.2.1 or later # XXX https://trac.fysik.dtu.dk/projects/gpaw/ticket/230 # 'parallel/scalapack_pdlasrt_hang.py', # 'dscf_forces.py', # 'stark_shift.py', exclude = [] if mpi.size > 1: exclude += ['pes.py', 'diamond_eps.py', 'nscfsic.py', 'coreeig.py', 'asewannier.py', 'wannier_ethylene.py', 'muffintinpot.py', 'stark_shift.py', 'exx_q.py', 'potential.py', # 'cmrtest/cmr_test3.py', # 'cmrtest/cmr_append.py', # 'cmrtest/Li2_atomize.py', # started to hang May 2014 'lcao_pair_and_coulomb.py', 'bse_MoS2_cut.py', 'pw/moleculecg.py', 'pw/davidson_pw.py', # scipy.weave fails often in parallel due to # ~/.python*_compiled # https://github.com/scipy/scipy/issues/1895 'scipy_test.py'] if mpi.size > 2: exclude += ['neb.py', 'response_pair.py'] if mpi.size < 4: exclude += ['parallel/fd_parallel.py', 'parallel/lcao_parallel.py', 'parallel/pblas.py', 'parallel/scalapack.py', 'parallel/scalapack_diag_simple.py', 'parallel/realspace_blacs.py', 'AA_exx_enthalpy.py', 'bse_aluminum.py', 'bse_diamond.py', 'bse_silicon.py', 'bse_vs_lrtddft.py', 'fileio/parallel.py', 'parallel/diamond_gllb.py', 'parallel/lcao_parallel_kpt.py', 'parallel/fd_parallel_kpt.py'] if mpi.size != 4: exclude += ['parallel/scalapack_mpirecv_crash.py'] exclude += ['parallel/scalapack_pdlasrt_hang.py'] if mpi.size == 1 or not compiled_with_sl(): exclude += ['parallel/submatrix_redist.py'] if mpi.size != 1 and not compiled_with_sl(): exclude += ['ralda_energy_H2.py', 'ralda_energy_N2.py', 'ralda_energy_Ni.py', 'ralda_energy_Si.py', 'bse_sym.py', 'bse_silicon.py', 'gwsi.py', 'rpa_energy_N2.py', 'pw/fulldiag.py', 'pw/fulldiagk.py', 'au02_absorption.py'] if not compiled_with_sl(): exclude.append('lcao_atomic_corrections.py') if np.__version__ < '1.6.0': exclude.append('chi0.py') exclude = set(exclude) class TestRunner: def __init__(self, tests, stream=sys.__stdout__, jobs=1, show_output=False): if mpi.size > 1: assert jobs == 1 self.jobs = jobs self.show_output = show_output self.tests = tests self.failed = [] self.skipped = [] self.garbage = [] if mpi.rank == 0: self.log = stream else: self.log = devnull self.n = max([len(test) for test in tests]) self.setup_paths = setup_paths[:] def run(self): self.log.write('=' * 77 + '\n') if not self.show_output: sys.stdout = devnull ntests = len(self.tests) t0 = time.time() if self.jobs == 1: self.run_single() else: # Run several processes using fork: self.run_forked() sys.stdout = sys.__stdout__ self.log.write('=' * 77 + '\n') self.log.write('Ran %d tests out of %d in %.1f seconds\n' % (ntests - len(self.tests) - len(self.skipped), ntests, time.time() - t0)) self.log.write('Tests skipped: %d\n' % len(self.skipped)) if self.failed: self.log.write('Tests failed: %d\n' % len(self.failed)) else: self.log.write('All tests passed!\n') self.log.write('=' * 77 + '\n') return self.failed def run_single(self): while self.tests: test = self.tests.pop(0) try: self.run_one(test) except KeyboardInterrupt: self.tests.append(test) break def run_forked(self): j = 0 pids = {} while self.tests or j > 0: if self.tests and j < self.jobs: test = self.tests.pop(0) pid = os.fork() if pid == 0: exitcode = self.run_one(test) os._exit(exitcode) else: j += 1 pids[pid] = test else: try: while True: pid, exitcode = os.wait() if pid in pids: break except KeyboardInterrupt: for pid, test in pids.items(): os.kill(pid, signal.SIGHUP) self.write_result(test, 'STOPPED', time.time()) self.tests.append(test) break if exitcode == 512: self.failed.append(pids[pid]) elif exitcode == 256: self.skipped.append(pids[pid]) del pids[pid] j -= 1 def run_one(self, test): exitcode_ok = 0 exitcode_skip = 1 exitcode_fail = 2 if self.jobs == 1: self.log.write('%*s' % (-self.n, test)) self.log.flush() t0 = time.time() filename = gpaw.__path__[0] + '/test/' + test tb = '' skip = False if test in exclude: self.register_skipped(test, t0) return exitcode_skip dirname = test[:-3] if mpi.rank == 0: os.makedirs(dirname) mpi.world.barrier() cwd = os.getcwd() os.chdir(dirname) try: setup_paths[:] = self.setup_paths loc = {} exec(compile(open(filename).read(), filename, 'exec'), loc) loc.clear() del loc self.check_garbage() except KeyboardInterrupt: self.write_result(test, 'STOPPED', t0) raise except ImportError as ex: if sys.version_info[0] >= 3: module = ex.name else: module = ex.args[0].split()[-1].split('.')[0] if module in ['scipy', 'cmr', '_gpaw_hdf5']: skip = True else: tb = traceback.format_exc() except AttributeError as ex: if (ex.args[0] == "'module' object has no attribute 'new_blacs_context'"): skip = True else: tb = traceback.format_exc() except Exception: tb = traceback.format_exc() finally: os.chdir(cwd) mpi.ibarrier(timeout=60.0) # guard against parallel hangs me = np.array(tb != '') everybody = np.empty(mpi.size, bool) mpi.world.all_gather(me, everybody) failed = everybody.any() skip = mpi.world.sum(int(skip)) if failed: self.fail(test, np.argwhere(everybody).ravel(), tb, t0) exitcode = exitcode_fail elif skip: self.register_skipped(test, t0) exitcode = exitcode_skip else: self.write_result(test, 'OK', t0) exitcode = exitcode_ok return exitcode def register_skipped(self, test, t0): self.write_result(test, 'SKIPPED', t0) self.skipped.append(test) def check_garbage(self): gc.collect() n = len(gc.garbage) self.garbage += gc.garbage del gc.garbage[:] assert n == 0, ('Leak: Uncollectable garbage (%d object%s) %s' % (n, 's'[:n > 1], self.garbage)) def fail(self, test, ranks, tb, t0): if mpi.size == 1: text = 'FAILED!\n%s\n%s%s' % ('#' * 77, tb, '#' * 77) self.write_result(test, text, t0) else: tbs = {tb: [0]} for r in range(1, mpi.size): if mpi.rank == r: mpi.send_string(tb, 0) elif mpi.rank == 0: tb = mpi.receive_string(r) if tb in tbs: tbs[tb].append(r) else: tbs[tb] = [r] if mpi.rank == 0: text = ('FAILED! (rank %s)\n%s' % (','.join([str(r) for r in ranks]), '#' * 77)) for tb, ranks in tbs.items(): if tb: text += ('\nRANK %s:\n' % ','.join([str(r) for r in ranks])) text += '%s%s' % (tb, '#' * 77) self.write_result(test, text, t0) self.failed.append(test) def write_result(self, test, text, t0): t = time.time() - t0 if self.jobs > 1: self.log.write('%*s' % (-self.n, test)) self.log.write('%10.3f %s\n' % (t, text)) if __name__ == '__main__': TestRunner(tests).run() gpaw-0.11.0.13004/gpaw/test/big/0000775000175000017500000000000012553644063016131 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/big/analysis.py0000664000175000017500000002161112553643471020331 0ustar jensjjensj00000000000000from __future__ import print_function import os import pickle import numpy as np import matplotlib.pyplot as pl import smtplib try: from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart except ImportError: from email.MIMEMultipart import MIMEMultipart from email.MIMEText import MIMEText """Database structure: dict(testname: [(rev, runtime, info), (rev, runtime, info), ...]) rev: SVN revision runtime: Run time in seconds. Negative for crashed jobs! info: A string describing the outcome """ class DatabaseHandler: """Database class for keeping timings and info for long tests""" def __init__(self, filename): self.filename = filename self.data = dict() def read(self): if os.path.isfile(self.filename): self.data = pickle.load(file(self.filename)) else: print('File does not exist, starting from scratch') def write(self, filename=None): if filename is None: filename = self.filename if os.path.isfile(filename): os.rename(filename, filename + '.old') pickle.dump(self.data, open(filename, 'wb')) def add_data(self, name, rev, runtime, info): if name not in self.data: self.data[name] = [] self.data[name].append((rev, runtime, info)) def get_data(self, name): """Return rev, time_array""" revs, runtimes = [], [] if name in self.data: for datapoint in self.data[name]: revs.append(datapoint[0]) runtimes.append(datapoint[1]) return np.asarray(revs), np.asarray(runtimes) def update(self, queue, rev): """Add all new data to database""" for job in queue.jobs: absname = job.absname tstart = job.tstart if tstart is None: tstart = np.nan tstop = job.tstop if tstop is None: tstop = np.nan info = job.status self.add_data(absname, rev, tstop - tstart, info) class TestAnalyzer: def __init__(self, name, revs, runtimes): self.name = name self.revs = revs self.runtimes = runtimes self.better = [] self.worse = [] self.relchange = None self.abschange = None def analyze(self, reltol=0.1, abstol=5.0): """Analyze timings When looking at a point, attention is needed if it deviates more than 10\% from the median of previous points. If such a point occurs the analysis is restarted. """ self.better = [] self.worse = [] abschange = 0.0 relchange = 0.0 status = 0 current_first = 0 # Point to start analysis from for i in range(1, len(self.runtimes)): tmpruntimes = self.runtimes[current_first:i] median = np.median(tmpruntimes[np.isfinite(tmpruntimes)]) if np.isnan(median): current_first = i elif np.isfinite(self.runtimes[i]): abschange = self.runtimes[i] - median relchange = abschange / median if relchange < -reltol and abschange < -abstol: # Improvement current_first = i self.better.append(i) status = -1 elif relchange > reltol and abschange > abstol: # Regression current_first = i self.worse.append(i) status = 1 else: status = 0 self.status = status self.abschange = abschange self.relchange = relchange * 100 def plot(self, outputdir=None): if outputdir is None: return fig = pl.figure() ax = fig.add_subplot(1, 1, 1) ax.plot(self.revs, self.runtimes, 'ko-') ax.plot(self.revs[self.better], self.runtimes[self.better], 'go', markersize=8) ax.plot(self.revs[self.worse], self.runtimes[self.worse], 'ro', markersize=8) ax.set_title(self.name) if not outputdir.endswith('/'): outputdir += '/' figname = self.name.replace('/', '_') fig.savefig(outputdir + figname + '.png') class MailGenerator: def __init__(self, queue): self.better = [] self.worse = [] self.FAILED = [] self.TIMEOUT = [] def add_test(self, ta): if ta.abschange < 0.0: self.add_better(ta) else: self.add_worse(ta) def add_better(self, ta): self.better.append((ta.name, ta.runtimes[-1], ta.abschange, ta.relchange)) def add_worse(self, ta): self.worse.append((ta.name, ta.runtimes[-1], ta.abschange, ta.relchange)) def add_failed(self, name): self.FAILED.append(name) def add_timeout(self, name): self.TIMEOUT.append(name) def generate_mail(self): mail = '' if len(self.FAILED): mail += 'The following %i tests failed:\n' % len(self.FAILED) for name in self.FAILED: mail += '%s\n' % name mail += '\n' if len(self.TIMEOUT): mail += 'The following %i tests timed out:\n' % len(self.TIMEOUT) for name in self.TIMEOUT: mail += '%s\n' % name mail += '\n' if len(self.FAILED) or len(self.TIMEOUT): mail += 'See attached log for details\n\n' mail += 'Benchmark results from weekly tests:\n\n' if len(self.better): mail += 'The following %i tests improved:\n' % len(self.better) for test in self.better: mail += '%-55s %7.1fs:%+8.1fs (%+7.2f%%)\n' % test else: mail += 'No tests improved!\n' mail += '\n' if len(self.worse): mail += 'The following %i tests regressed:\n' % len(self.worse) for test in self.worse: mail += '%-55s %7.1fs:%+8.1fs (%+7.2f%%)\n' % test else: mail += 'No tests regressed!\n' return mail def generate_subject(self): subject = 'Weekly tests: ' if len(self.FAILED): subject += '%i FAILURES, ' % len(self.FAILED) if len(self.TIMEOUT): subject += '%i TIMEOUTS, ' % len(self.TIMEOUT) subject += '%i regressions, ' % len(self.worse) subject += '%i improvements.' % len(self.better) return subject def send_mail(self, address, server, attachment=None): msg = MIMEMultipart() msg['Subject'] = self.generate_subject() me = os.environ['USER'] + '@' + server msg['From'] = me msg['To'] = address msg.attach(MIMEText(self.generate_mail())) if attachment: a = MIMEText(open(attachment).read()) a.add_header('Content-Disposition', 'attachment', filename='status.log') msg.attach(a) s = smtplib.SMTP(server) s.sendmail(me, [address], msg.as_string()) s.quit() #def csv2database(infile, outfile): # """Use this file once to import the old data from csv""" # csvdata = np.recfromcsv(infile) # db = DatabaseHandler(outfile) # for test in csvdata: # name = test[0] # for i in range(1, len(test) - 1): # runtime = float(test[i]) # info = '' # db.add_data(name, 0, runtime, info) # db.write() def analyse(queue, dbpath, outputdir=None, rev=None, mailto=None, mailserver=None, attachment=None): """Analyse runtimes from testsuite Parameters: queue: AGTSQueue Que to analuze dbpath: str Path to file storing previous results outputdir: str|None If str, figures will be put in this dir rev: int|None GPAW revision. If None time.time() is used mailto: str|None Mailaddres to send results to. If None, results will be printed to stdout. """ if rev is None: import time rev = time.time() db = DatabaseHandler(dbpath) db.read() db.update(queue, rev) db.write() mg = MailGenerator(queue) for job in queue.jobs: name = job.absname if job.status == 'success': revs, runtimes = db.get_data(name) ta = TestAnalyzer(name, revs, runtimes) ta.analyze(abstol=25, reltol=0.04) if ta.status: mg.add_test(ta) ta.plot(outputdir) elif job.status == 'FAILED': mg.add_failed(name) elif job.status == 'TIMEOUT': mg.add_timeout(name) if mailto is not None: mg.send_mail(mailto, mailserver, attachment) else: print(mg.generate_subject()) print(mg.generate_mail()) gpaw-0.11.0.13004/gpaw/test/big/agts.py0000664000175000017500000003216512553643471017452 0ustar jensjjensj00000000000000from __future__ import print_function import os import sys import time import random jobstates = ['waiting', 'submitted', 'running', 'success', 'FAILED', 'disabled', 'TIMEOUT'] class AGTSJob: def __init__(self, dir, script, queueopts=None, ncpus=1, walltime=10 * 60, deps=None, creates=None, show=None): """Advaced GPAW test system job. Example: >>> job = AGTSJob('doc/devel/256H2O', 'b256H2O.py --sl_default=4,4,16') >>> job.dir 'doc/devel/256H2O' >>> job.script 'b256H2O.py' >>> job.args '--sl_default=4,4,16' >>> job.name 'b256H2O.py_--sl_default=4,4,16' >>> job.absname 'doc/devel/256H2O/b256H2O.py_--sl_default=4,4,16' """ if ' ' in script: script, self.args = script.split(' ', 1) else: self.args = '' pathname = os.path.normpath(os.path.join(dir, script)) self.dir, self.script = os.path.split(pathname) if self.dir == '': self.dir = '.' self.absname = pathname if self.args: self.absname += '_' + self.args.replace(' ', '_') dir, self.name = os.path.split(self.absname) # any string valid for the batch system submit script, e.g.: # '-l nodes=2:ppn=4:opteron285' self.queueopts = queueopts self.ncpus = ncpus self.walltime = walltime if deps: if not isinstance(deps, (list, tuple)): deps = [deps] self.deps = deps else: self.deps = [] if creates and not isinstance(creates, (list, tuple)): creates = [creates] self.creates = creates # Filenames to use for pylab.savefig() replacement of pylab.show(): if not show: show = [] self.show = show if os.path.exists('%s.status' % self.absname): self.status = open('%s.status' % self.absname).readline().strip() else: self.status = 'waiting' self.tstart = None self.tstop = None self.exitcode = None self.pbsid = None def set_status(self, status): self.status = status open('%s.status' % self.absname, 'w').write(status + '\n') def check_status(self): name = self.absname if self.status == 'running': if time.time() - self.tstart > self.walltime: self.set_status('TIMEOUT') return 'TIMEOUT' if os.path.exists('%s.done' % name): self.tstop = os.stat('%s.done' % name).st_mtime self.exitcode = int(open('%s.done' % name).readlines()[-1]) if self.exitcode: self.set_status('FAILED') if self.creates: for filename in self.creates: path = os.path.join(self.dir, filename) if os.path.isfile(path): os.remove(path) else: self.set_status('success') if self.creates: for filename in self.creates: path = os.path.join(self.dir, filename) if not os.path.isfile(path): self.set_status('FAILED') break return self.status elif self.status == 'submitted' and os.path.exists('%s.start' % name): self.tstart = os.stat('%s.start' % name).st_mtime self.set_status('running') return 'running' # Nothing happened: return None def clean(self): for name in ['start', 'done', 'status']: try: os.remove(self.absname + '.' + name) except OSError: pass self.status = 'waiting' class Cluster: def write_pylab_wrapper(self, job): """Use Agg backend and prevent windows from popping up.""" fd = open(job.script + '.py', 'w') fd.write('from gpaw.test import wrap_pylab\n') fd.write('wrap_pylab(%s)\n' % job.show) fd.write('exec(open(%r).read())\n' % job.script) fd.close() def tick(self, nrunning): pass class TestCluster(Cluster): def submit(self, job): if random.random() < 0.05: # randomly fail some of the jobs exitcode = 1 else: exitcode = 0 wait = random.randint(1, 12) cmd = 'sleep %s; touch %s.start; ' % (wait, job.absname) if random.random() < 0.05: # randomly time out some of the jobs pass else: duration = random.randint(4, 12) cmd += 'sleep %s; ' % duration if exitcode == 0 and job.creates: for filename in job.creates: cmd += 'echo 42 > %s; ' % os.path.join(job.dir, filename) cmd += 'echo %d > %s.done' % (exitcode, job.absname) os.system('(%s)&' % cmd) class LocalCluster(Cluster): def __init__(self): self.queue = [] def submit(self, job): self.queue.append(job) def tick(self, nrunning): if self.queue and nrunning == 0: job = self.queue.pop(0) dir = os.getcwd() os.chdir(job.dir) self.write_pylab_wrapper(job) os.system('(touch %s.start;' % job.name + 'python %s.py %s > %s.output;' % (job.script, job.args, job.name) + 'echo $? > %s.done)&' % job.name) os.chdir(dir) class AGTSQueue: def __init__(self, sleeptime=60, fd=sys.stdout): self.sleeptime = sleeptime self.jobs = [] if isinstance(fd, str): self.fd = open(fd, 'w') else: self.fd = fd # used by add() method: self._dir = None def count(self): self.N = dict([(state, 0) for state in jobstates]) for j in self.jobs: self.N[j.status] += 1 def log(self, job): self.count() self.fd.write('%s %3d %3d %3d %3d %3d %3d %3d %-49s %s\n' % ((time.strftime('%H:%M:%S'),) + tuple([self.N[state] for state in jobstates]) + (job.absname, job.status))) self.fd.flush() self.status() def add(self, script, dir=None, queueopts=None, ncpus=1, walltime=15, deps=None, creates=None, show=None): """Add job. XXX move docs from doc/devel/testing to here and use Sphinx autodoc.""" if dir is None: dir = self._dir job = AGTSJob(dir, script, queueopts, ncpus, walltime * 60 + self.sleeptime, deps, creates, show) self.jobs.append(job) return job def locate_tests(self): for root, dirs, files in os.walk('.'): if root.startswith('./build'): continue for fname in files: if (fname.endswith('agts.py') and not root.endswith('gpaw/test/big')): yield root, fname def collect(self): """Find agts.py files and collect jobs.""" for dir, agtsfile in self.locate_tests(): _global = {} fname = os.path.join(dir, agtsfile) exec(compile(open(fname).read(), fname, 'exec'), _global) self._dir = dir _global['agts'](self) self.normalize() def normalize(self): """Convert string dependencies to actual job objects.""" for job in self.jobs: for i, dep in enumerate(job.deps): if not isinstance(dep, AGTSJob): absname = os.path.normpath(os.path.join(job.dir, dep)) job.deps[i] = self.find(absname) def find(self, absname): """Find job with a particular name.""" for job in self.jobs: if job.absname == absname: return job raise ValueError def find_job_and_dependencies(self, job): if isinstance(job, str): for j in self.jobs: if j.script == job: job = j break else: raise ValueError jobs = [job] for dep in job.deps: jobs += self.find_job_and_dependencies(dep) return jobs def run(self, cluster): """Run jobs and return the number of unsuccessful jobs.""" self.fd.write('time W S R + - . T job\n') jobs = self.jobs while True: done = True for job in jobs: if job.status == 'waiting': done = False ready = True for dep in job.deps: if dep.status != 'success': ready = False break if ready: cluster.submit(job) job.set_status('submitted') self.log(job) elif job.status in ['running', 'submitted']: done = False if done: break time.sleep(self.sleeptime) nrunning = 0 for job in jobs: newstatus = job.check_status() if newstatus: self.log(job) if newstatus in ['TIMEOUT', 'FAILED']: self.fail(job) if job.status == 'running': nrunning += 1 cluster.tick(nrunning) t = self.get_cpu_time() self.fd.write('CPU time: %d:%02d:%02d\n' % (t // 3600, t // 60 % 60, t % 60)) return len([None for job in self.jobs if job.status != 'success']) def status(self): fd = open('status.log', 'w') fd.write('# job ' + 20 * ' ' + 'status time tmax ncpus deps files id\n') for job in self.jobs: if job.tstop is not None: t = '%5d' % round(job.tstop - job.tstart) else: t = ' ' if job.creates: c = len(job.creates) else: c = 0 if job.pbsid is not None: id = job.pbsid else: id = '' fd.write('%-70s %-10s %s %6d %5d %5d %5d %s\n' % (job.absname, job.status, t, job.walltime, job.ncpus, len(job.deps), c, id)) fd.close() def fail(self, dep): """Recursively disable jobs depending on failed job.""" for job in self.jobs: if dep in job.deps: job.set_status('disabled') self.log(job) self.fail(job) def clean(self): for job in self.jobs: job.clean() def copy_created_files(self, dir): for job in self.jobs: if job.creates: for filename in job.creates: path = os.path.join(job.dir, filename) if os.path.isfile(path): os.system('cp %s %s' % (path, os.path.join(dir, filename))) def get_cpu_time(self): """Calculate CPU time in seconds.""" t = 0 for job in self.jobs: if job.tstop is not None: t += job.ncpus * (job.tstop - job.tstart) return t def main(): from optparse import OptionParser parser = OptionParser(usage='%prog [options] [jobs]', version='%prog 0.1') parser.add_option('-c', '--clean', action='store_true') parser.add_option('-r', '--run') opt, args = parser.parse_args() queue = AGTSQueue() # Find all jobs: queue.collect() if args: # Select specific job(s) and dependencies: newjobs = set() for arg in args: jobs = queue.find_job_and_dependencies(arg) for job in jobs: newjobs.add(job) queue.jobs = list(newjobs) if opt.clean: queue.clean() for job in queue.jobs: job.check_status() queue.count() for state in jobstates: print(('%9s %d' % (state, queue.N[state]))) if opt.run: for job in queue.jobs: if job.status in ['FAILED', 'TIMEOUT', 'disabled']: job.clean() job.set_status('waiting') if opt.run == 'test': # Quick test using dummy cluster and timeout after only 20 seconds: queue.sleeptime = 2.0 for job in queue.jobs: job.walltime = 20 cluster = TestCluster() elif opt.run == 'niflheim': from gpaw.test.big.niflheim import NiflheimCluster cluster = NiflheimCluster() elif opt.run == 'local': cluster = LocalCluster() else: 1 / 0 queue.run(cluster) if __name__ == '__main__': main() gpaw-0.11.0.13004/gpaw/test/big/g2_1/0000775000175000017500000000000012553644063016661 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/big/g2_1/submit.agts.py0000664000175000017500000000057512553643471021504 0ustar jensjjensj00000000000000def agts(queue): #generate = queue.add('generate.py', ncpus=1, walltime=20) G = [queue.add('g21gpaw.py %d' % i, walltime=40 * 60) for i in range(4)] N = [queue.add('g21nwchem.py %d' % i, walltime=10 * 60, queueopts='-l nodes=1:ppn=4:opteron4', ncpus=1) for i in range(4)] queue.add('analyse.py', deps=G + N, creates='g2-1.csv') gpaw-0.11.0.13004/gpaw/test/big/g2_1/analyse.py0000664000175000017500000001454112553643471020676 0ustar jensjjensj00000000000000from __future__ import print_function import numpy as np import ase.db from ase.utils import prnt from ase.data.g2_1 import molecule_names c = ase.db.connect('g2-1.db') def analyse(calc, relaxed): e = {} for d in c.select(natoms=1, calculator=calc): e[d.numbers[0]] = d.energy A = [] for name in molecule_names: d = c.get(name=name, relaxed=relaxed, calculator=calc) ea = sum(e[Z] for Z in d.numbers) - d.energy dist = ((d.positions[0] - d.positions[-1])**2).sum()**0.5 A.append((ea, dist)) return np.array(A).T En0, Dn0 = analyse('nwchem', 0) En1, Dn1 = analyse('nwchem', 1) Eg0, Dg0 = analyse('gpaw', 0) Eg1, Dg1 = analyse('gpaw', 1) print(abs(Eg0 - En0).max(), abs(Eg0 - En0).mean()) print(abs(Eg1 - En1).max(), abs(Eg1 - En1).mean()) print(abs(Dg0 - Dn0).max(), abs(Dg0 - Dn0).mean()) print(abs(Dg1 - Dn1).max(), abs(Dg1 - Dn1).mean()) fd = open('g2-1.csv', 'w') prnt('# Atomization energies and distances. N: NWChem, G: GPAW', file=fd) prnt('# name, E(N, not relaxed), E(N), E(G)-E(N), d(N), d(G)-d(N)', file=fd) for name, en0, en1, eg1, dn1, dg1 in zip(molecule_names, En0, En1, Eg1, Dn1, Dg1): prnt('%11s, %7.3f, %7.3f, %7.3f, %7.3f, %7.3f' % (name, en0, en1, eg1 - en1, dn1, dg1 - dn1), file=fd) # these results are calculated at relaxed geometries ref = {'distance': {'NH3': 1.0212028325017757, 'S2': 1.909226444930773, 'SiH2_s3B1d': 1.4959758117701643, 'CH3OH': 1.103031397032791, 'SiH4': 1.492599477296688, 'Si2H6': 3.1894770187147787, 'PH3': 1.4301222209112225, 'PH2': 1.4346717268375369, 'HF': 0.93024767766719751, 'O2': 1.2177518292845226, 'SiH3': 1.4944876788686847, 'NH': 1.0495566124276352, 'SH2': 1.3513837051001727, 'ClO': 1.5787435668567111, 'H2O2': 1.8958330716525236, 'NO': 1.156790619328925, 'ClF': 1.6500936428996131, 'LiH': 1.6056281159928836, 'HCO': 1.134630847589132, 'CH3': 1.0857934634048991, 'CH4': 1.0954690924956099, 'Cl2': 2.0044430187644329, 'HOCl': 1.7084164068894601, 'SiH2_s1A1d': 1.5369100463950582, 'SiO': 1.5267775155499548, 'F2': 1.4131037387967056, 'P2': 1.9038007151393095, 'Si2': 2.2844499935377716, 'CH': 1.135943649633214, 'CO': 1.1353228578574415, 'CN': 1.1734204501040257, 'LiF': 1.5781425105489659, 'Na2': 3.0849004417809258, 'SO2': 1.4536010904565573, 'NaCl': 2.375956045377166, 'Li2': 2.7269446448266184, 'NH2': 1.0360313462587714, 'CS': 1.5453598419904586, 'C2H6': 2.1839921464514007, 'N2': 1.1020010395108386, 'C2H4': 2.1196102605939493, 'HCN': 1.074902699795437, 'C2H2': 1.0701025663671189, 'CH2_s3B1d': 1.0846126602770281, 'CH3Cl': 1.0934062531916822, 'BeH': 1.3549994786114516, 'CO2': 1.1705025664593323, 'CH3SH': 1.0951914666413829, 'OH': 0.98302300558682143, 'N2H4': 1.9949378750277829, 'H2O': 0.9689957468077689, 'SO': 1.5015729306543228, 'CH2_s1A1d': 1.1216809054426011, 'H2CO': 2.0340405586023551, 'HCl': 1.2882940110553078}, 'energy': {'NH3': -1537.8943922528292, 'S2': -21662.654140653412, 'SiH2_s3B1d': -7903.3690892881705, 'Li': -203.05091256761085, 'CH3OH': -3146.7647944133632, 'SiH4': -7938.4648222008409, 'Si2H6': -15845.082177930506, 'PH3': -9333.4084018049416, 'PH2': -9316.1298787915111, 'HF': -2732.0742553639361, 'O2': -4088.7283614591165, 'SiH3': -7920.9111544133084, 'NH': -1501.4257523508722, 'Be': -398.09853859103947, 'SH2': -10863.938964816221, 'ClO': -14561.296690949923, 'H2O2': -4121.946252450156, 'NO': -3532.6917094247037, 'ClF': -15231.961288082202, 'LiH': -218.97262833348015, 'HCO': -3096.2005211539013, 'CH3': -1082.8017329696315, 'CH4': -1101.1776994482279, 'Cl2': -25035.886547435726, 'Na': -4412.8227996808337, 'HOCl': -14578.981322327132, 'SiH2_s1A1d': -7904.0726269700554, 'SiO': -9920.2118092650708, 'F2': -5426.9009851655201, 'P2': -18569.7100395737, 'Si2': -15744.418687547124, 'C': -1028.5471962651873, 'CH': -1045.8247164754753, 'CO': -3081.4550529867706, 'CN': -2521.0913000695346, 'F': -2712.30655836285, 'H': -13.60405569717515, 'LiF': -2921.3671571474624, 'O': -2041.2483769244884, 'N': -1483.981485107872, 'Na2': -8826.410126700297, 'P': -9282.2144876505899, 'Si': -7870.4445140229245, 'SO2': -14923.501322516569, 'NaCl': -16933.432926277521, 'Li2': -406.96985635618387, 'NH2': -1519.3756700462491, 'CS': -11865.161113573042, 'C2H6': -2169.7998017018276, 'N2': -2978.5280844918202, 'C2H4': -2136.2951883618102, 'HCN': -2540.2803982015039, 'C2H2': -2102.2901648364796, 'CH2_s3B1d': -1064.1920578821023, 'CH3Cl': -13603.223029214254, 'BeH': -414.1082135671578, 'CO2': -5129.0868582477142, 'CH3SH': -11932.535768470407, 'OH': -2059.6213922996608, 'Cl': -12516.517962625088, 'S': -10828.826656949115, 'N2H4': -3042.0346586048404, 'H2O': -2078.6212796010145, 'SO': -12876.201520592005, 'CH2_s1A1d': -1063.5161597336582, 'H2CO': -3113.7397623037459, 'HCl': -12534.742429020402}, 'ea': {'NH3': 13.100740053431537, 'S2': 5.0008267551820609, 'SiH2_s3B1d': 5.7164638708964048, 'CH3OH': 22.552998434986876, 'SiH4': 13.604085389217289, 'Si2H6': 22.568815701608401, 'PH3': 10.381747062827344, 'PH2': 6.7072797465716576, 'HF': 6.1636413039109357, 'O2': 6.2316076101396902, 'SiH3': 9.654473298859557, 'NH': 3.8402115458250137, 'SH2': 7.9041964727566665, 'ClO': 3.5303514003462624, 'H2O2': 12.241387206829131, 'NO': 7.4618473923433157, 'ClF': 3.1367670942636323, 'LiH': 2.3176600686941526, 'HCO': 12.800892267050585, 'CH3': 13.442369612918583, 'CH4': 18.214280394339767, 'Cl2': 2.8506221855495824, 'HOCl': 7.6109270803808613, 'SiH2_s1A1d': 6.4200015527812866, 'SiO': 8.5189183176571532, 'F2': 2.2878684398201585, 'P2': 5.2810642725198704, 'Si2': 3.5296595012750913, 'CH': 3.6734645131127763, 'CO': 11.659479797095173, 'CN': 8.5626186964755107, 'LiF': 6.009686217001672, 'Na2': 0.7645273386297049, 'SO2': 12.177911718477844, 'NaCl': 4.0921639715998026, 'Li2': 0.86803122096216612, 'NH2': 8.1860735440266126, 'CS': 7.7872603587384219, 'C2H6': 31.081074988401724, 'N2': 10.565114276076201, 'C2H4': 24.784573042734792, 'HCN': 14.147661131269615, 'C2H2': 17.987660911754574, 'CH2_s3B1d': 8.4367502225645694, 'CH3Cl': 17.345703232453161, 'BeH': 2.4056192789431634, 'CO2': 18.042908133550554, 'CH3SH': 20.745692467404297, 'OH': 4.7689596779973726, 'N2H4': 19.655465600395473, 'H2O': 10.164791282175884, 'SO': 6.126486718401793, 'CH2_s1A1d': 7.7608520741205211, 'H2CO': 16.736077719720015, 'HCl': 4.6204106981385848}} En10 = [ref['ea'][name] for name in molecule_names] Dn10 = [ref['distance'][name] for name in molecule_names] print(abs(En1 - En10).max()) print(abs(Dn1 - Dn10).max()) gpaw-0.11.0.13004/gpaw/test/big/g2_1/generate.py0000664000175000017500000000026512553643471021032 0ustar jensjjensj00000000000000import os import gpaw elements='H He Li Be B C N O F Ne Na Mg Al Si P S Cl Ar' os.system("gpaw-setup -n --name=nrel -f PBE " + elements) os.system("gpaw-basis -t dzp " + elements) gpaw-0.11.0.13004/gpaw/test/big/g2_1/g21nwchem.py0000664000175000017500000000205012553643471021025 0ustar jensjjensj00000000000000import ase.db from ase.structure import molecule from ase.optimize.bfgs import BFGS from ase.calculators.nwchem import NWChem from ase.data.g2_1 import molecule_names, atom_names c = ase.db.connect('g2-1.db') for name in molecule_names + atom_names: id = c.reserve(name=name, calculator='nwchem') if id is None: continue atoms = molecule(name) atoms.calc = NWChem(command='mpiexec -np 4 nwchem PREFIX.nw > PREFIX.out', geometry='noautosym nocenter noautoz', task='gradient', xc='PBE', grid='nodisk', tolerances='tight', basis='def2-qzvppd', basispar='spherical', direct='noio', label=name) atoms.get_forces() c.write(atoms, name=name, relaxed=False) if len(atoms) > 1: opt = BFGS(atoms, logfile=name + '.nwchem.log') opt.run(0.01) c.write(atoms, name=name, relaxed=True) del c[id] gpaw-0.11.0.13004/gpaw/test/big/g2_1/__init__.py0000664000175000017500000000000012553643471020762 0ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/big/g2_1/g21gpaw.py0000664000175000017500000000164112553643471020507 0ustar jensjjensj00000000000000import ase.db from ase.structure import molecule from ase.optimize.bfgs import BFGS from ase.data.g2_1 import molecule_names, atom_names from gpaw import GPAW, PW, Mixer c = ase.db.connect('g2-1.db') for name in molecule_names + atom_names: id = c.reserve(name=name, calculator='gpaw') if id is None: continue atoms = molecule(name) atoms.cell = [12, 13.01, 14.02] atoms.center() atoms.calc = GPAW(mode=PW(800), xc='PBE', fixmom=True, txt=name + '.txt') if name in ['Na2', 'NaCl', 'NO', 'ClO', 'Cl', 'Si']: atoms.calc.set(eigensolver='dav', mixer=Mixer(0.05, 2)) atoms.get_forces() c.write(atoms, name=name, relaxed=False) if len(atoms) > 1: opt = BFGS(atoms, logfile=name + '.gpaw.log') opt.run(0.01) c.write(atoms, name=name, relaxed=True) del c[id] gpaw-0.11.0.13004/gpaw/test/big/g2_1/pbe_gpaw_nrel_plot.py0000664000175000017500000001637312553643471023111 0ustar jensjjensj00000000000000from __future__ import print_function import os import warnings # silence matplotlib.use() warning warnings.filterwarnings('ignore', '.*This call to matplotlib\.use.*',) import numpy as np import heapq from ase.data.molecules import latex ann_fontsize = 'small' label_fontsize = 12 from ase.data import atomic_numbers from ase.structure import molecule from ase.data.g2_1 import data from gpaw.test.big.g2_1.pbe_nwchem_def2_qzvppd_analyse import ref from gpaw.test.big.g2_1.pbe_gpaw_nrel_analyse import ref as calc from gpaw.test.big.g2_1.pbe_gpaw_nrel_analyse import tag formulas = sorted(ref['ea'].keys()) atoms = [] for f in formulas: m = molecule(f, data=data) atoms.extend(m.get_chemical_symbols()) atoms = list(set(atoms)) anum = [atomic_numbers[a] for a in atoms] # sort according to anum tmpsort = sorted(zip(anum, atoms)) a, atomssorted = zip(*tmpsort) def containatom(atom, formulas, data): molecules = [] for f in formulas: m = molecule(f, data=data) if atom in list(set(m.get_chemical_symbols())): molecules.append(f) return list(set(molecules)) def get_statistics(result, reference): skeys = sorted(result.keys()) res1 = [] res2 = [] for k in skeys: res1.append(k) res2.append(result[k]) skeys = reference.keys() skeys.sort() ref1 = [] ref2 = [] for k in skeys: ref1.append(k) ref2.append(reference[k]) resrm = [] refrm = [] # remove result without reference and reference without result toremove = list(set(res1).symmetric_difference(set(ref1))) for c in toremove: if c in res1: print(result + ' vs ' + reference + ': ' + result + ' removed ' + c) i = res1.index(c) res1.pop(i) res2.pop(i) resrm.append(c) if c in ref1: print(result + ' vs ' + reference + ': ' + reference + ' removed ' + c) i = ref1.index(c) ref1.pop(i) ref2.pop(i) refrm.append(c) # calculate result - reference diff = np.array(res2) - np.array(ref2) all = [(ref1[list(diff).index(e)], e) for e in diff] average = np.average(diff) absaverage = np.average(abs(diff)) std = np.std(diff) nlargest = heapq.nlargest(4, abs(diff)) # n largest errors largest = [] for abse in nlargest: c = ref1[list(abs(diff)).index(abse)] e = diff[ref1.index(c)] largest.append((c, e)) return average, absaverage, std, largest, all, resrm, refrm # prepare plot vs = [ (calc['ea'].copy(), ref['ea'].copy(), 'G2_1'), ] for atom in atoms: calc_atom = {} for a in containatom(atom, formulas, data): calc_atom.update({a: calc['ea'][a]}) ref_atom = {} for a in containatom(atom, formulas, data): ref_atom.update({a: ref['ea'][a]}) vs.append((calc_atom, ref_atom, atom)) no = [] average = [] absaverage = [] std = [] largest = [] all = [] resrm = [] refrm = [] labelsbase = [] labels = [] for n, results in enumerate(vs): label = results[2] labelsbase.append(label) labels.append(label) a, absa, s, l, al, rs, rf = get_statistics(results[0], results[1]) no.append(n) average.append(a) absaverage.append(absa) std.append(s) largest.append(l) resrm.append(rs) refrm.append(rf) all.append(al) #print no #print average #print absaverage #print std #print largest def plot(xdata, ydata, std, title, xlabel, ylabel, label, color, alpha, miny, maxy, num=1, ): import matplotlib #matplotlib.use('Agg') import pylab import matplotlib.font_manager # all goes to figure num pylab.figure(num=num, figsize=(9.5, 9)) pylab.gca().set_position([0.10, 0.20, 0.85, 0.60]) # let the plot have fixed y-axis scale ywindow = maxy - miny #pylab.gca().set_ylim(miny, maxy+ywindow/5.0) pylab.gca().set_ylim(miny, maxy) #pylab.plot(xdata, ydata, 'b.', label=label, color=color) #pylab.plot(xdata, ydata, 'b-', label='_nolegend_', color=color) pylab.bar(xdata, ydata, 0.9, label=label, color=color, alpha=alpha) t = pylab.title(title) # http://old.nabble.com/More-space-between-title-and-secondary-x-axis-td31722298.html t.set_y(1.05) pylab.xlabel(xlabel) pylab.ylabel(ylabel) prop = matplotlib.font_manager.FontProperties(size=12) leg = pylab.legend(loc='upper right', fancybox=True, prop=prop) leg.get_frame().set_alpha(0.5) #pylab.savefig(directory_name + os.path.sep + out_prefix +'.eps', format='eps') def plot_save(directory_name, out_prefix): from os.path import exists assert exists(directory_name) import pylab pylab.savefig(directory_name + os.path.sep + out_prefix +'.png', bbox_inches='tight') import matplotlib matplotlib.use('Agg') from matplotlib import pylab, ticker # print scaling results num=1 miny = -0.3 maxy = 0.3 plot( no, average, std, 'Atomization energy: E(atoms) - E(molecule)', 'Subsets contain', 'Calculated - Reference [eV]', 'Average (avg)', 'blue', 0.5, miny, maxy, num=1, ) plot( no, absaverage, std, 'Atomization energy: E(atoms) - E(molecule)', 'Subsets contain', 'Calculated - Reference [eV]', 'Average absolute (abs)', 'green', 0.2, miny, maxy, num=1, ) zero = [0.0 for i in range(len(no))] pylab.plot(no, zero, 'k-', label='_nolegend_') ay1=pylab.gca() ay1.xaxis.set_ticks([n + 0.5 for n in no]) ay1.xaxis.set_ticklabels(labels) ay1.yaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator()) for label in ay1.get_xticklabels() + ay1.get_yticklabels(): label.set_fontsize(label_fontsize) def errorslocation(n, n1): return (n + 0.1, 0.25 - 0.05 * n1) def formulaslocation(n, n1): return (n + 0.3, - 0.10 - 0.05 * n1) for n in range(len(no)): label = '' for n1, v in enumerate(['average', 'absaverage', 'std']): l = { 'average': '\navg\n', 'absaverage': '\nabs\n', 'std': '\nstd\n', }[v] value = { 'average': average, 'absaverage': absaverage, 'std': std, }[v] label += l + ' ' + str(round(value[n], 3)) + '\n' pylab.annotate(label, xy=(n + 0.0, 0.0), xytext=errorslocation(n, n1), arrowprops=None, horizontalalignment='left', verticalalignment='center', fontsize=ann_fontsize, ) # plot compounds with largest errors for n, l in enumerate(largest): for n1, (c, e) in enumerate(l): name = latex(c) + '\n' # matplotlib.pyparsing.ParseFatalException: Expected end of math '$' # $\rm{SiH}2_\rm{s}3\rm{B}1\rm{d}$ (at char 0), (line:1, col:1) name = name.replace('\\rm', '') label = name + ' ' + str(round(e, 2)) pylab.annotate(label, xy=(n + 0.05, e), xytext=formulaslocation(n, n1), arrowprops=dict(width=0.05, headwidth=5.0, facecolor='black', shrink=1.00), horizontalalignment='left', verticalalignment='center', fontsize=ann_fontsize, ) #pylab.show() plot_save(".", tag + '_ea_vs') #pylab.close(1) gpaw-0.11.0.13004/gpaw/test/big/niflheim6.py0000664000175000017500000001243212553643471020370 0ustar jensjjensj00000000000000import os import subprocess from gpaw.test.big.agts import Cluster class NiflheimCluster(Cluster): def __init__(self, asepath='', setuppath='$GPAW_SETUP_PATH'): self.asepath = asepath self.setuppath = setuppath def submit(self, job): dir = os.getcwd() os.chdir(job.dir) self.write_pylab_wrapper(job) gpaw_platform = os.environ['FYS_PLATFORM'].replace('-el6', '-2.6') if job.queueopts is None: if job.ncpus < 4: ppn = '%d:opteron4' % job.ncpus nodes = 1 arch = 'linux-x86_64-x3455-2.6' elif job.ncpus % 16 == 0: ppn = '16:xeon16' nodes = job.ncpus // 16 arch = 'linux-x86_64-sl230s-2.6' elif job.ncpus % 8 == 0: ppn = '8:xeon8' nodes = job.ncpus // 8 arch = 'linux-x86_64-dl160g6-2.6' else: assert job.ncpus % 4 == 0 ppn = '4:opteron4' nodes = job.ncpus // 4 arch = 'linux-x86_64-x3455-2.6' queueopts = '-l nodes=%d:ppn=%s' % (nodes, ppn) else: queueopts = job.queueopts # the oldest, hopefully (?) common platform arch = 'linux-x86_64-x3455-2.6' gpaw_python = os.path.join(dir, 'gpaw', 'build', 'bin.' + arch, 'gpaw-python') submit_pythonpath = ':'.join([ self.asepath, dir + '/gpaw', '%s/gpaw/build/lib.%s' % (dir, arch), '$PYTHONPATH']) run_command = '. /home/opt/modulefiles/modulefiles_el6.sh&& ' run_command += 'module load NUMPY/1.7.1-1&& ' run_command += 'module load SCIPY/0.12.0-1&& ' run_command += 'module load MATPLOTLIB/1.4.0-1&& ' run_command += 'module load povray&& ' run_command += 'module load bader&& ' run_command += 'module load ABINIT&& ' run_command += 'module load DACAPO&& ' run_command += 'module load SCIENTIFICPYTHON&& ' run_command += 'module load NWCHEM&& ' run_command += 'module load AIMS&& ' # force gpaw/gpaw/fftw.py to use the right libfftw3.so # see https://listserv.fysik.dtu.dk/pipermail/gpaw-developers/2012-July/003045.html if 0: # libfftw3.so crashes run_command += 'module load intel-compilers&& ' run_command += 'module load openmpi&& ' # intel version! fftw = 'fftw/3.3.3-' + gpaw_platform.replace('-2.6', '') fftw += '-tm-gfortran-openmpi-1.6.3-1' run_command += 'module load ' + fftw + '&& ' run_command += 'export GPAW_FFTWSO="libfftw3.so"&& ' if 0: # libmkl_intel_lp64.so causes scipy crash? run_command += 'module unload fftw&& ' # all fftw must be unloaded! fftw = 'intel-mkl' run_command += 'module load ' + fftw + '&& ' run_command += 'export GPAW_FFTWSO="libmkl_rt.so"&& ' if 1: # numpy fftw has most chances to work run_command += 'module unload fftw&& ' # all fftw must be unloaded run_command += 'export GPAW_FFTWSO=""&& ' # and use numpy fftw # disable mpi_warn_on_fork - causes crashes on xeon16! run_command += 'export OMPI_MCA_mpi_warn_on_fork=0&& ' if job.ncpus == 1: # don't use mpiexec here, # this allows one to start mpi inside the *.agts.py script run_command += 'module load intel-compilers&& ' run_command += 'module load openmpi&& ' run_command += ' export PYTHONPATH=' + submit_pythonpath + '&&' run_command += ' export GPAW_SETUP_PATH=' + self.setuppath + '&&' # we want to run GPAW/ASE scripts + gpaw-python with os.system! run_command += ' PATH=%s/ase/tools:$PATH' % dir + '&&' run_command += ' PATH=%s/gpaw/tools:$PATH' % dir + '&&' run_command += ' PATH=%s/gpaw/build/bin.%s:$PATH' % (dir, arch) + '&&' # we run other codes with asec run_command += ' export ASE_ABINIT_COMMAND="mpiexec abinit < PREFIX.files > PREFIX.log"&&' run_command += ' export ASE_AIMS_COMMAND="mpiexec ${AIMS_COMMAND} > aims.out"&&' else: run_command += 'module load intel-compilers&& ' run_command += 'module load openmpi&& ' run_command += 'mpiexec --mca mpi_paffinity_alone 1' run_command += ' -x PYTHONPATH=' + submit_pythonpath run_command += ' -x GPAW_SETUP_PATH=' + self.setuppath run_command += ' -x OMP_NUM_THREADS=1' p = subprocess.Popen( ['/usr/local/bin/qsub', '-V', queueopts, '-l', 'walltime=%d:%02d:00' % (job.walltime // 3600, job.walltime % 3600 // 60), '-N', job.name], stdin=subprocess.PIPE, stdout=subprocess.PIPE) out, err = p.communicate( 'touch %s.start\n' % job.name + run_command + ' %s %s.py %s > %s.output\n' % (gpaw_python, job.script, job.args, job.name) + 'echo $? > %s.done\n' % job.name) assert p.returncode == 0 id = out.split('.')[0] job.pbsid = id os.chdir(dir) gpaw-0.11.0.13004/gpaw/test/big/hsk/0000775000175000017500000000000012553644063016716 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/big/hsk/hsk.py0000664000175000017500000000626612553643471020071 0ustar jensjjensj00000000000000"""Collection of bulk systems. From this paper: Judith Harl, Laurids Schimka, and Georg Kresse Assessing the quality of the random phase approximation for lattice constants and atomization energies of solids PHYSICAL REVIEW B 81, 115126 (2010) """ # The data is: Crystal structure, 6 lattice constants (PBE, LDA, # EXX, RPA, RPA+, experiment), 6 cohesive energies and PBE bulk # modulus: data = { 'C': ['diamond', 3.569, 3.534, 3.540, 3.572, 3.578, 3.553, 7.72, 9.01, 5.18, 7.00, 6.93, 7.55, 434], 'Si': ['diamond', 5.466, 5.404, 5.482, 5.432, 5.445, 5.421, 4.55, 5.34, 2.82, 4.39, 4.33, 4.68, 89], 'Ge': ['diamond', 5.765, 5.627, 5.701, 5.661, 5.676, 5.644, 3.71, 4.62, 1.95, 3.59, 3.53, 3.92, 58], 'SiC': ['zincblende', 4.378, 4.332, 4.351, 4.365, 4.374, 4.346, 6.40, 7.45, 4.36, 6.04, 5.96, 6.48, 212], 'AlN': ['zincblende', 4.397, 4.344, 4.346, 4.394, 4.402, 4.368, 5.72, 6.68, 3.65, 5.46, 5.39, 5.85, 194], 'AlP': ['zincblende', 5.501, 5.435, 5.513, 5.467, 5.479, 5.451, 4.09, 4.87, 2.53, 4.07, 4.02, 4.32, 83], 'AlAs': ['zincblende', 5.727, 5.630, 5.698, 5.675, 5.690, 5.649, 3.69, 4.52, 2.15, 3.67, 3.61, 3.82, 67], 'GaN': ['zincblende', 4.551, 4.460, 4.485, 4.519, 4.528, 4.520, 4.37, 5.46, 2.22, 4.23, 4.17, 4.55, 171], 'GaP': ['zincblende', 5.507, 5.396, 5.519, 5.442, 5.456, 5.439, 3.48, 4.39, 1.83, 3.48, 3.46, 3.61, 76], 'GaAs': ['zincblende', 5.749, 5.611, 5.706, 5.661, 5.675, 5.640, 3.14, 4.09, 1.51, 3.14, 3.09, 3.34, 60], 'InP': ['zincblende', 5.955, 5.827, 5.940, 5.867, 5.882, 5.858, 3.14, 4.15, 1.56, 3.12, 3.07, 3.47, 59], 'InAs': ['zincblende', 6.184, 6.029, 6.120, 6.070, 6.087, 6.047, 2.88, 3.80, 1.31, 2.85, 2.80, 3.08, 49], 'InSb': ['zincblende', 6.633, 6.452, 6.585, 6.494, 6.514, 6.468, 2.63, 3.50, 1.10, 2.59, 2.55, 2.81, 37], 'MgO': ['rocksalt', 4.259, 4.169, 4.173, 4.225, 4.233, 4.189, 4.98, 5.88, 3.47, 4.91, 4.83, 5.20, 149], 'LiF': ['rocksalt', 4.069, 3.913, 3.991, 3.998, 4.010, 3.972, 4.33, 4.94, 3.25, 4.20, 4.15, 4.46, 68], 'NaF': ['rocksalt', 4.707, 4.511, 4.614, 4.625, 4.635, 4.582, 3.82, 4.38, 2.79, 3.77, 3.71, 3.97, 45], 'LiCl': ['rocksalt', 5.149, 4.967, 5.272, 5.074, 5.091, 5.070, 3.37, 3.83, 2.68, 3.36, 3.31, 3.59, 32], 'NaCl': ['rocksalt', 5.697, 5.469, 5.778, 5.588, 5.607, 5.569, 3.10, 3.50, 2.54, 3.15, 3.11, 3.34, 24], 'Na': ['bcc', 4.196, 4.056, 4.494, 4.182, 4.208, 4.214, 1.08, 1.26, 0.23, 1.00, 0.98, 1.12, 8], 'Al': ['fcc', 4.035, 3.983, 4.104, 4.037, 4.052, 4.018, 3.44, 4.04, 1.33, 3.22, 3.14, 3.43, 77], 'Cu': ['fcc', 3.634, 3.523, 3.968, 3.597, 3.606, 3.595, 3.48, 4.55, 0.03, 3.36, 3.30, 3.52, 138], 'Rh': ['fcc', 3.824, 3.753, 3.748, 3.811, 3.819, 3.794, 5.74, 7.67, -2.88, 5.05, 4.97, 5.78, 255], 'Pd': ['fcc', 3.935, 3.830, 4.003, 3.896, 3.905, 3.876, 3.74, 5.08, -1.26, 3.41, 3.35, 3.94, 162], 'Ag': ['fcc', 4.146, 4.002, 4.507, 4.087, 4.098, 4.062, 2.52, 3.64, 0.52, 2.64, 2.58, 2.98, 90]} gpaw-0.11.0.13004/gpaw/test/big/hsk/__init__.py0000664000175000017500000000000012553643471021017 0ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/big/scf/0000775000175000017500000000000012553644063016704 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/big/scf/dcdft_pbe_pw_jacapo.py0000664000175000017500000000316612553643471023223 0ustar jensjjensj00000000000000import sys from ase.calculators.jacapo.pw91_psp import defaultpseudopotentials as psp from ase.test.tasks.dcdft import DeltaCodesDFTTask from ase.tasks.calcfactory import calculator_factory if len(sys.argv) == 1: xc = 'PBE' run = None elif len(sys.argv) == 2: xc = 'PBE' run = sys.argv[1] elif len(sys.argv) == 3: xc = sys.argv[1] run = sys.argv[2] if run is not None: tag = 'scf_dcdft_%s_pw_%s' % (xc.lower(), run) else: tag = 'scf_dcdft_%s_pw_jacapo' % (xc.lower()) if run is not None: tag += '_%s' % run class Task(DeltaCodesDFTTask): def __init__(self, **kwargs): DeltaCodesDFTTask.__init__(self, **kwargs) def calculate(self, name, atoms): data = DeltaCodesDFTTask.calculate(self, name, atoms) try: steps = atoms.get_calculator().get_number_of_iterations() except (AttributeError, NotImplemented): steps = None data['calculator steps'] = steps return data calcfactory = calculator_factory('jacapo', xc=xc, pw=340, dw=340, symmetry=True, ft=0.1, # need to be set explicitly spinpol=True, ) task = Task( calcfactory=calcfactory, tag=tag, use_lock_files=True, ) if __name__ == '__main__': keys = set(psp.keys()).intersection(set(task.collection.names)) for m in ['Zn', 'Zr']: keys.remove(m) # do not converge task.run(keys) gpaw-0.11.0.13004/gpaw/test/big/scf/analyse.py0000664000175000017500000007672612553643471020736 0ustar jensjjensj00000000000000import os import sys import glob from ase.test.tasks.analyse import AnalyseSCFTask as Task rundefs = { # 'm103poisson': 'Mixer(0.10, 3)', # 'm103mp': 'Mixer(0.10, 3)', 'd203mp': 'MixerDif(0.20, 3)', 'dzpd203mp': 'MixerDif(0.20, 3)', 'cgm203mp': 'MixerDif(0.20, 3)', 'cgdzpm203mp': 'MixerDif(0.20, 3)', 'cgdzpd203mp': 'MixerDif(0.20, 3)', # 'm251': 'Mixer(0.25, 1)', 'm252': 'Mixer(0.25, 2)', 'm253': 'Mixer(0.25, 3)', 'm254': 'Mixer(0.25, 4)', 'm255': 'Mixer(0.25, 5)', 'm256': 'Mixer(0.25, 6)', 'm257': 'Mixer(0.25, 7)', # 'm201': 'Mixer(0.20, 1)', 'm202': 'Mixer(0.20, 2)', 'm203': 'Mixer(0.20, 3)', 'm204': 'Mixer(0.20, 4)', 'm205': 'Mixer(0.20, 5)', 'm206': 'Mixer(0.20, 6)', 'm207': 'Mixer(0.20, 7)', # 'm151': 'Mixer(0.15, 1)', 'm152': 'Mixer(0.15, 2)', 'm153': 'Mixer(0.15, 3)', 'm154': 'Mixer(0.15, 4)', 'm155': 'Mixer(0.15, 5)', 'm156': 'Mixer(0.15, 6)', 'm157': 'Mixer(0.15, 7)', # 'inititer00m': 'Mixer()', 'inititer01m': 'Mixer()', 'inititer02m': 'Mixer()', 'inititer03m': 'Mixer()', 'inititer04m': 'Mixer()', 'inititer05m': 'Mixer()', 'inititer06m': 'Mixer()', 'inititer07m': 'Mixer()', 'inititer08m': 'Mixer()', 'inititer09m': 'Mixer()', 'inititer10m': 'Mixer()', 'inititer15m': 'Mixer()', 'inititer20m': 'Mixer()', # 'inititer05m051': 'Mixer(0.05, 1)', 'inititer05m052': 'Mixer(0.05, 2)', 'inititer05m101': 'Mixer(0.10, 1)', 'inititer05m102': 'Mixer(0.10, 2)', 'inititer10m051': 'Mixer(0.05, 1)', 'inititer10m052': 'Mixer(0.05, 2)', 'inititer10m101': 'Mixer(0.10, 1)', 'inititer10m102': 'Mixer(0.10, 2)', 'inititer20m051': 'Mixer(0.05, 1)', 'inititer20m052': 'Mixer(0.05, 2)', 'inititer20m101': 'Mixer(0.10, 1)', 'inititer20m102': 'Mixer(0.10, 2)', # 'inititer00d': 'MixerDif()', 'inititer01d': 'MixerDif()', 'inititer02d': 'MixerDif()', 'inititer03d': 'MixerDif()', 'inititer04d': 'MixerDif()', 'inititer05d': 'MixerDif()', 'inititer06d': 'MixerDif()', 'inititer07d': 'MixerDif()', 'inititer08d': 'MixerDif()', 'inititer09d': 'MixerDif()', 'inititer10d': 'MixerDif()', 'inititer15d': 'MixerDif()', 'inititer20d': 'MixerDif()', # 'inititer05d051': 'MixerDif(0.05, 1)', 'inititer05d052': 'MixerDif(0.05, 2)', 'inititer05d101': 'MixerDif(0.10, 1)', 'inititer05d102': 'MixerDif(0.10, 2)', 'inititer10d051': 'MixerDif(0.05, 1)', 'inititer10d052': 'MixerDif(0.05, 2)', 'inititer10d101': 'MixerDif(0.10, 1)', 'inititer10d102': 'MixerDif(0.10, 2)', 'inititer20d051': 'MixerDif(0.05, 1)', 'inititer20d052': 'MixerDif(0.05, 2)', 'inititer20d101': 'MixerDif(0.10, 1)', 'inititer20d102': 'MixerDif(0.10, 2)', # 'bands00m': 'Mixer()', 'bands01m': 'Mixer()', 'bands02m': 'Mixer()', 'bands03m': 'Mixer()', 'bands04m': 'Mixer()', 'bands05m': 'Mixer()', 'bands06m': 'Mixer()', 'bands07m': 'Mixer()', 'bands08m': 'Mixer()', 'bands09m': 'Mixer()', 'bands10m': 'Mixer()', 'bands15m': 'Mixer()', 'bands20m': 'Mixer()', # 'bands01cgm': 'Mixer()', 'bands02cgm': 'Mixer()', 'bands03cgm': 'Mixer()', 'bands04cgm': 'Mixer()', 'bands05cgm': 'Mixer()', 'bands06cgm': 'Mixer()', 'bands07cgm': 'Mixer()', 'bands08cgm': 'Mixer()', 'bands09cgm': 'Mixer()', 'bands10cgm': 'Mixer()', 'bands15cgm': 'Mixer()', 'bands20cgm': 'Mixer()', # 'mw1': 'Mixer(weight=1)', 'mw25': 'Mixer(weight=25)', 'mw50': 'Mixer(weight=50)', 'mw100': 'Mixer(weight=100)', 'mw200': 'Mixer(weight=200)', # 'm101': 'Mixer(0.10, 1)', 'm102': 'Mixer(0.10, 2)', 'm103': 'Mixer(0.10, 3)', # default 'm104': 'Mixer(0.10, 4)', 'm105': 'Mixer(0.10, 5)', 'm106': 'Mixer(0.10, 6)', 'm107': 'Mixer(0.10, 7)', # 'm051': 'Mixer(0.05, 1)', 'm052': 'Mixer(0.05, 2)', 'm053': 'Mixer(0.05, 3)', 'm054': 'Mixer(0.05, 4)', 'm055': 'Mixer(0.05, 5)', 'm056': 'Mixer(0.05, 6)', 'm057': 'Mixer(0.05, 7)', # 'm302': 'Mixer(0.30, 2)', 'm303': 'Mixer(0.30, 3)', 'm304': 'Mixer(0.30, 4)', 'm305': 'Mixer(0.30, 5)', 'm306': 'Mixer(0.30, 6)', 'm307': 'Mixer(0.30, 7)', 'm308': 'Mixer(0.30, 8)', 'm352': 'Mixer(0.35, 2)', 'm353': 'Mixer(0.35, 3)', 'm354': 'Mixer(0.35, 4)', 'm355': 'Mixer(0.35, 5)', 'm356': 'Mixer(0.35, 6)', 'm357': 'Mixer(0.35, 7)', 'm358': 'Mixer(0.35, 8)', 'm402': 'Mixer(0.40, 2)', 'm403': 'Mixer(0.40, 3)', 'm404': 'Mixer(0.40, 4)', 'm405': 'Mixer(0.40, 5)', 'm406': 'Mixer(0.40, 6)', 'm407': 'Mixer(0.40, 7)', 'm408': 'Mixer(0.40, 8)', # 's102': 'MixerSum(0.10, 2)', 's103': 'MixerSum(0.10, 3)', 's104': 'MixerSum(0.10, 4)', 's105': 'MixerSum(0.10, 5)', 's106': 'MixerSum(0.10, 6)', 's107': 'MixerSum(0.10, 7)', 's203': 'MixerSum(0.20, 3)', 's253': 'MixerSum(0.25, 3)', # 'dzps102': 'MixerSum(0.10, 2)', 'dzps103': 'MixerSum(0.10, 3)', 'dzps104': 'MixerSum(0.10, 4)', 'dzps105': 'MixerSum(0.10, 5)', 'dzps106': 'MixerSum(0.10, 6)', 'dzps107': 'MixerSum(0.10, 7)', 'dzps203': 'MixerSum(0.20, 3)', 'dzps253': 'MixerSum(0.25, 3)', # 'cgdzps102': 'MixerSum(0.10, 2)', 'cgdzps103': 'MixerSum(0.10, 3)', 'cgdzps104': 'MixerSum(0.10, 4)', 'cgdzps105': 'MixerSum(0.10, 5)', 'cgdzps106': 'MixerSum(0.10, 6)', 'cgdzps107': 'MixerSum(0.10, 7)', 'cgdzps203': 'MixerSum(0.20, 3)', 'cgdzps253': 'MixerSum(0.25, 3)', # 'b103': 'BroydenMixer(0.10, 3)', 'b104': 'BroydenMixer(0.10, 4)', 'b105': 'BroydenMixer(0.10, 5)', 'b106': 'BroydenMixer(0.10, 6)', 'b107': 'BroydenMixer(0.10, 7)', 'b203': 'BroydenMixer(0.20, 3)', 'b253': 'BroydenMixer(0.25, 3)', 'b206': 'BroydenMixer(0.20, 6)', 'b256': 'BroydenMixer(0.25, 6)', # 'cgb103': 'BroydenMixer(0.10, 3)', 'cgb104': 'BroydenMixer(0.10, 4)', 'cgb105': 'BroydenMixer(0.10, 5)', 'cgb106': 'BroydenMixer(0.10, 6)', 'cgb107': 'BroydenMixer(0.10, 7)', # 'cgdzpb103': 'BroydenMixer(0.10, 3)', 'cgdzpb104': 'BroydenMixer(0.10, 4)', 'cgdzpb105': 'BroydenMixer(0.10, 5)', 'cgdzpb106': 'BroydenMixer(0.10, 6)', 'cgdzpb107': 'BroydenMixer(0.10, 7)', 'cgdzpb203': 'BroydenMixer(0.20, 3)', 'cgdzpb206': 'BroydenMixer(0.20, 6)', # 'dw1': 'MixerDif(weight=1)', 'dw25': 'MixerDif(weight=25)', 'dw50': 'MixerDif(weight=50)', 'dw100': 'MixerDif(weight=100)', 'd101': 'MixerDif(0.10, 1)', 'd102': 'MixerDif(0.10, 2)', 'd103': 'MixerDif(0.10, 3)', 'd104': 'MixerDif(0.10, 4)', 'd105': 'MixerDif(0.10, 5)', 'd106': 'MixerDif(0.10, 6)', 'd107': 'MixerDif(0.10, 7)', 'd108': 'MixerDif(0.10, 8)', 'd152': 'MixerDif(0.15, 2)', 'd153': 'MixerDif(0.15, 3)', 'd154': 'MixerDif(0.15, 4)', 'd155': 'MixerDif(0.15, 5)', 'd156': 'MixerDif(0.15, 6)', 'd157': 'MixerDif(0.15, 7)', 'd158': 'MixerDif(0.15, 8)', 'd202': 'MixerDif(0.20, 2)', 'd203': 'MixerDif(0.20, 3)', 'd204': 'MixerDif(0.20, 4)', 'd205': 'MixerDif(0.20, 5)', 'd206': 'MixerDif(0.20, 6)', 'd207': 'MixerDif(0.20, 7)', 'd208': 'MixerDif(0.20, 8)', 'd252': 'MixerDif(0.25, 2)', 'd253': 'MixerDif(0.25, 3)', 'd254': 'MixerDif(0.25, 4)', 'd255': 'MixerDif(0.25, 5)', 'd256': 'MixerDif(0.25, 6)', 'd257': 'MixerDif(0.25, 7)', 'd258': 'MixerDif(0.25, 8)', 'd302': 'MixerDif(0.30, 2)', 'd303': 'MixerDif(0.30, 3)', 'd304': 'MixerDif(0.30, 4)', 'd305': 'MixerDif(0.30, 5)', 'd306': 'MixerDif(0.30, 6)', 'd307': 'MixerDif(0.30, 7)', 'd308': 'MixerDif(0.30, 8)', 'd352': 'MixerDif(0.35, 2)', 'd353': 'MixerDif(0.35, 3)', 'd354': 'MixerDif(0.35, 4)', 'd355': 'MixerDif(0.35, 5)', 'd356': 'MixerDif(0.35, 6)', 'd357': 'MixerDif(0.35, 7)', 'd358': 'MixerDif(0.35, 8)', 'd402': 'MixerDif(0.40, 2)', 'd403': 'MixerDif(0.40, 3)', 'd404': 'MixerDif(0.40, 4)', 'd405': 'MixerDif(0.40, 5)', 'd406': 'MixerDif(0.40, 6)', 'd407': 'MixerDif(0.40, 7)', 'd408': 'MixerDif(0.40, 8)', # 'dzpdw1': 'MixerDif(weight=1)', 'dzpdw25': 'MixerDif(weight=25)', 'dzpdw50': 'MixerDif(weight=50)', 'dzpdw100': 'MixerDif(weight=100)', 'dzpd101': 'MixerDif(0.10, 1)', 'dzpd102': 'MixerDif(0.10, 2)', 'dzpd103': 'MixerDif(0.10, 3)', 'dzpd104': 'MixerDif(0.10, 4)', 'dzpd105': 'MixerDif(0.10, 5)', 'dzpd106': 'MixerDif(0.10, 6)', 'dzpd107': 'MixerDif(0.10, 7)', 'dzpd152': 'MixerDif(0.15, 2)', 'dzpd153': 'MixerDif(0.15, 3)', 'dzpd154': 'MixerDif(0.15, 4)', 'dzpd155': 'MixerDif(0.15, 5)', 'dzpd156': 'MixerDif(0.15, 6)', 'dzpd157': 'MixerDif(0.15, 7)', 'dzpd202': 'MixerDif(0.20, 2)', 'dzpd203': 'MixerDif(0.20, 3)', 'dzpd204': 'MixerDif(0.20, 4)', 'dzpd205': 'MixerDif(0.20, 5)', 'dzpd206': 'MixerDif(0.20, 6)', 'dzpd207': 'MixerDif(0.20, 7)', 'dzpd252': 'MixerDif(0.25, 2)', 'dzpd253': 'MixerDif(0.25, 3)', 'dzpd254': 'MixerDif(0.25, 4)', 'dzpd255': 'MixerDif(0.25, 5)', 'dzpd256': 'MixerDif(0.25, 6)', 'dzpd257': 'MixerDif(0.25, 7)', # 'szdzpm': 'Mixer()', 'szpdzpm': 'Mixer()', # 'dzpmw1': 'Mixer(weight=1)', 'dzpmw25': 'Mixer(weight=25)', 'dzpmw50': 'Mixer(weight=50)', 'dzpmw100': 'Mixer(weight=100)', 'dzpm102': 'Mixer(0.10, 2)', 'dzpm103': 'Mixer(0.10, 3)', 'dzpm104': 'Mixer(0.10, 4)', 'dzpm105': 'Mixer(0.10, 5)', 'dzpm106': 'Mixer(0.10, 6)', 'dzpm107': 'Mixer(0.10, 7)', 'dzpm152': 'Mixer(0.15, 2)', 'dzpm153': 'Mixer(0.15, 3)', 'dzpm154': 'Mixer(0.15, 4)', 'dzpm155': 'Mixer(0.15, 5)', 'dzpm202': 'Mixer(0.20, 2)', 'dzpm203': 'Mixer(0.20, 3)', 'dzpm204': 'Mixer(0.20, 4)', 'dzpm205': 'Mixer(0.20, 5)', 'dzpm252': 'Mixer(0.25, 2)', 'dzpm253': 'Mixer(0.25, 3)', 'dzpm254': 'Mixer(0.25, 4)', 'dzpm255': 'Mixer(0.25, 5)', # 'dzpbands00m': 'Mixer()', 'dzpbands01m': 'Mixer()', 'dzpbands02m': 'Mixer()', 'dzpbands03m': 'Mixer()', 'dzpbands04m': 'Mixer()', 'dzpbands05m': 'Mixer()', 'dzpbands06m': 'Mixer()', 'dzpbands07m': 'Mixer()', 'dzpbands08m': 'Mixer()', 'dzpbands09m': 'Mixer()', 'dzpbands10m': 'Mixer()', 'dzpbands15m': 'Mixer()', 'dzpbands20m': 'Mixer()', # 'dzpbands00d': 'MixerDiff()', 'dzpbands01d': 'MixerDiff()', 'dzpbands02d': 'MixerDiff()', 'dzpbands03d': 'MixerDiff()', 'dzpbands04d': 'MixerDiff()', 'dzpbands05d': 'MixerDiff()', 'dzpbands06d': 'MixerDiff()', 'dzpbands07d': 'MixerDiff()', 'dzpbands08d': 'MixerDiff()', 'dzpbands09d': 'MixerDiff()', 'dzpbands10d': 'MixerDiff()', 'dzpbands15d': 'MixerDiff()', 'dzpbands20d': 'MixerDiff()', # 'fm101': 'FFTMixer(0.10, 1)', 'fm102': 'FFTMixer(0.10, 2)', 'fm103': 'FFTMixer(0.10, 3)', 'fm104': 'FFTMixer(0.10, 4)', 'fm105': 'FFTMixer(0.10, 5)', 'fm106': 'FFTMixer(0.10, 6)', 'fm107': 'FFTMixer(0.10, 7)', 'fm108': 'FFTMixer(0.10, 8)', 'fm152': 'FFTMixer(0.15, 2)', 'fm153': 'FFTMixer(0.15, 3)', 'fm154': 'FFTMixer(0.15, 4)', 'fm155': 'FFTMixer(0.15, 5)', 'fm156': 'FFTMixer(0.15, 6)', 'fm157': 'FFTMixer(0.15, 7)', 'fm158': 'FFTMixer(0.15, 8)', 'fm202': 'FFTMixer(0.20, 2)', 'fm203': 'FFTMixer(0.20, 3)', 'fm204': 'FFTMixer(0.20, 4)', 'fm205': 'FFTMixer(0.20, 5)', 'fm206': 'FFTMixer(0.20, 6)', 'fm207': 'FFTMixer(0.20, 7)', 'fm208': 'FFTMixer(0.20, 8)', 'fm252': 'FFTMixer(0.25, 2)', 'fm253': 'FFTMixer(0.25, 3)', 'fm254': 'FFTMixer(0.25, 4)', 'fm255': 'FFTMixer(0.25, 5)', 'fm256': 'FFTMixer(0.25, 6)', 'fm257': 'FFTMixer(0.25, 7)', 'fm258': 'FFTMixer(0.25, 8)', 'fm302': 'FFTMixer(0.30, 2)', 'fm303': 'FFTMixer(0.30, 3)', 'fm304': 'FFTMixer(0.30, 4)', 'fm305': 'FFTMixer(0.30, 5)', 'fm306': 'FFTMixer(0.30, 6)', 'fm307': 'FFTMixer(0.30, 7)', 'fm308': 'FFTMixer(0.30, 8)', 'fm352': 'FFTMixer(0.35, 2)', 'fm353': 'FFTMixer(0.35, 3)', 'fm354': 'FFTMixer(0.35, 4)', 'fm355': 'FFTMixer(0.35, 5)', 'fm356': 'FFTMixer(0.35, 6)', 'fm357': 'FFTMixer(0.35, 7)', 'fm358': 'FFTMixer(0.35, 8)', # 'fs101': 'FFTMixerSum(0.10, 1)', 'fs102': 'FFTMixerSum(0.10, 2)', 'fs103': 'FFTMixerSum(0.10, 3)', 'fs104': 'FFTMixerSum(0.10, 4)', 'fs105': 'FFTMixerSum(0.10, 5)', 'fs106': 'FFTMixerSum(0.10, 6)', 'fs107': 'FFTMixerSum(0.10, 7)', 'fs108': 'FFTMixerSum(0.10, 8)', 'fs152': 'FFTMixerSum(0.15, 2)', 'fs153': 'FFTMixerSum(0.15, 3)', 'fs154': 'FFTMixerSum(0.15, 4)', 'fs155': 'FFTMixerSum(0.15, 5)', 'fs156': 'FFTMixerSum(0.15, 6)', 'fs157': 'FFTMixerSum(0.15, 7)', 'fs158': 'FFTMixerSum(0.15, 8)', 'fs202': 'FFTMixerSum(0.20, 2)', 'fs203': 'FFTMixerSum(0.20, 3)', 'fs204': 'FFTMixerSum(0.20, 4)', 'fs205': 'FFTMixerSum(0.20, 5)', 'fs206': 'FFTMixerSum(0.20, 6)', 'fs207': 'FFTMixerSum(0.20, 7)', 'fs208': 'FFTMixerSum(0.20, 8)', 'fs252': 'FFTMixerSum(0.25, 2)', 'fs253': 'FFTMixerSum(0.25, 3)', 'fs254': 'FFTMixerSum(0.25, 4)', 'fs255': 'FFTMixerSum(0.25, 5)', 'fs256': 'FFTMixerSum(0.25, 6)', 'fs257': 'FFTMixerSum(0.25, 7)', 'fs258': 'FFTMixerSum(0.25, 8)', 'fs302': 'FFTMixerSum(0.30, 2)', 'fs303': 'FFTMixerSum(0.30, 3)', 'fs304': 'FFTMixerSum(0.30, 4)', 'fs305': 'FFTMixerSum(0.30, 5)', 'fs306': 'FFTMixerSum(0.30, 6)', 'fs307': 'FFTMixerSum(0.30, 7)', 'fs308': 'FFTMixerSum(0.30, 8)', 'fs352': 'FFTMixerSum(0.35, 2)', 'fs353': 'FFTMixerSum(0.35, 3)', 'fs354': 'FFTMixerSum(0.35, 4)', 'fs355': 'FFTMixerSum(0.35, 5)', 'fs356': 'FFTMixerSum(0.35, 6)', 'fs357': 'FFTMixerSum(0.35, 7)', 'fs358': 'FFTMixerSum(0.35, 8)', # 'fd101': 'FFTMixerDif(0.10, 1)', 'fd102': 'FFTMixerDif(0.10, 2)', 'fd103': 'FFTMixerDif(0.10, 3)', 'fd104': 'FFTMixerDif(0.10, 4)', 'fd105': 'FFTMixerDif(0.10, 5)', 'fd106': 'FFTMixerDif(0.10, 6)', 'fd107': 'FFTMixerDif(0.10, 7)', 'fd108': 'FFTMixerDif(0.10, 8)', 'fd152': 'FFTMixerDif(0.15, 2)', 'fd153': 'FFTMixerDif(0.15, 3)', 'fd154': 'FFTMixerDif(0.15, 4)', 'fd155': 'FFTMixerDif(0.15, 5)', 'fd156': 'FFTMixerDif(0.15, 6)', 'fd157': 'FFTMixerDif(0.15, 7)', 'fd158': 'FFTMixerDif(0.15, 8)', 'fd202': 'FFTMixerDif(0.20, 2)', 'fd203': 'FFTMixerDif(0.20, 3)', 'fd204': 'FFTMixerDif(0.20, 4)', 'fd205': 'FFTMixerDif(0.20, 5)', 'fd206': 'FFTMixerDif(0.20, 6)', 'fd207': 'FFTMixerDif(0.20, 7)', 'fd208': 'FFTMixerDif(0.20, 8)', 'fd252': 'FFTMixerDif(0.25, 2)', 'fd253': 'FFTMixerDif(0.25, 3)', 'fd254': 'FFTMixerDif(0.25, 4)', 'fd255': 'FFTMixerDif(0.25, 5)', 'fd256': 'FFTMixerDif(0.25, 6)', 'fd257': 'FFTMixerDif(0.25, 7)', 'fd258': 'FFTMixerDif(0.25, 8)', 'fd302': 'FFTMixerDif(0.30, 2)', 'fd303': 'FFTMixerDif(0.30, 3)', 'fd304': 'FFTMixerDif(0.30, 4)', 'fd305': 'FFTMixerDif(0.30, 5)', 'fd306': 'FFTMixerDif(0.30, 6)', 'fd307': 'FFTMixerDif(0.30, 7)', 'fd308': 'FFTMixerDif(0.30, 8)', 'fd352': 'FFTMixerDif(0.35, 2)', 'fd353': 'FFTMixerDif(0.35, 3)', 'fd354': 'FFTMixerDif(0.35, 4)', 'fd355': 'FFTMixerDif(0.35, 5)', 'fd356': 'FFTMixerDif(0.35, 6)', 'fd357': 'FFTMixerDif(0.35, 7)', 'fd358': 'FFTMixerDif(0.35, 8)', # 'cgm101': 'Mixer(0.10, 1)', 'cgm102': 'Mixer(0.10, 2)', 'cgm103': 'Mixer(0.10, 3)', 'cgm104': 'Mixer(0.10, 4)', 'cgm105': 'Mixer(0.10, 5)', 'cgm106': 'Mixer(0.10, 6)', 'cgm107': 'Mixer(0.10, 7)', 'cgm152': 'Mixer(0.15, 2)', 'cgm153': 'Mixer(0.15, 3)', 'cgm154': 'Mixer(0.15, 4)', 'cgm155': 'Mixer(0.15, 5)', 'cgm156': 'Mixer(0.15, 6)', 'cgm157': 'Mixer(0.15, 7)', 'cgm201': 'Mixer(0.20, 2)', 'cgm202': 'Mixer(0.20, 2)', 'cgm203': 'Mixer(0.20, 3)', 'cgm204': 'Mixer(0.20, 4)', 'cgm205': 'Mixer(0.20, 5)', 'cgm206': 'Mixer(0.20, 6)', 'cgm207': 'Mixer(0.20, 7)', 'cgm252': 'Mixer(0.25, 2)', 'cgm253': 'Mixer(0.25, 3)', 'cgm254': 'Mixer(0.25, 4)', 'cgm255': 'Mixer(0.25, 5)', 'cgm256': 'Mixer(0.25, 6)', 'cgm257': 'Mixer(0.25, 7)', # 'cgbands00m': 'Mixer()', 'cgbands01m': 'Mixer()', 'cgbands02m': 'Mixer()', 'cgbands03m': 'Mixer()', 'cgbands04m': 'Mixer()', 'cgbands05m': 'Mixer()', 'cgbands06m': 'Mixer()', 'cgbands07m': 'Mixer()', 'cgbands08m': 'Mixer()', 'cgbands09m': 'Mixer()', 'cgbands10m': 'Mixer()', 'cgbands15m': 'Mixer()', 'cgbands20m': 'Mixer()', # 'cgdzpm102': 'Mixer(0.10, 2)', 'cgdzpm103': 'Mixer(0.10, 3)', 'cgdzpm104': 'Mixer(0.10, 4)', 'cgdzpm105': 'Mixer(0.10, 5)', 'cgdzpm152': 'Mixer(0.15, 2)', 'cgdzpm153': 'Mixer(0.15, 3)', 'cgdzpm154': 'Mixer(0.15, 4)', 'cgdzpm155': 'Mixer(0.15, 5)', 'cgdzpm202': 'Mixer(0.20, 2)', 'cgdzpm203': 'Mixer(0.20, 3)', 'cgdzpm204': 'Mixer(0.20, 4)', 'cgdzpm205': 'Mixer(0.20, 5)', 'cgdzpm252': 'Mixer(0.25, 2)', 'cgdzpm253': 'Mixer(0.25, 3)', 'cgdzpm254': 'Mixer(0.25, 4)', 'cgdzpm255': 'Mixer(0.25, 5)', # 'cgd101': 'MixerDif(0.10, 1)', 'cgd102': 'MixerDif(0.10, 2)', 'cgd103': 'MixerDif(0.10, 3)', 'cgd104': 'MixerDif(0.10, 4)', 'cgd105': 'MixerDif(0.10, 5)', 'cgd106': 'MixerDif(0.10, 6)', 'cgd107': 'MixerDif(0.10, 7)', 'cgd152': 'MixerDif(0.15, 2)', 'cgd153': 'MixerDif(0.15, 3)', 'cgd154': 'MixerDif(0.15, 4)', 'cgd155': 'MixerDif(0.15, 5)', 'cgd156': 'MixerDif(0.15, 6)', 'cgd157': 'MixerDif(0.15, 7)', 'cgd201': 'MixerDif(0.20, 2)', 'cgd202': 'MixerDif(0.20, 2)', 'cgd203': 'MixerDif(0.20, 3)', 'cgd204': 'MixerDif(0.20, 4)', 'cgd205': 'MixerDif(0.20, 5)', 'cgd206': 'MixerDif(0.20, 6)', 'cgd207': 'MixerDif(0.20, 7)', 'cgd253': 'MixerDif(0.25, 3)', 'cgd303': 'MixerDif(0.30, 3)', # 'cgs101': 'MixerSum(0.10, 1)', 'cgs102': 'MixerSum(0.10, 2)', 'cgs103': 'MixerSum(0.10, 3)', 'cgs104': 'MixerSum(0.10, 4)', 'cgs105': 'MixerSum(0.10, 5)', 'cgs106': 'MixerSum(0.10, 6)', 'cgs107': 'MixerSum(0.10, 7)', 'cgs152': 'MixerSum(0.15, 2)', 'cgs153': 'MixerSum(0.15, 3)', 'cgs154': 'MixerSum(0.15, 4)', 'cgs155': 'MixerSum(0.15, 5)', 'cgs156': 'MixerSum(0.15, 6)', 'cgs157': 'MixerSum(0.15, 7)', 'cgs201': 'MixerSum(0.20, 2)', 'cgs202': 'MixerSum(0.20, 2)', 'cgs203': 'MixerSum(0.20, 3)', 'cgs204': 'MixerSum(0.20, 4)', 'cgs205': 'MixerSum(0.20, 5)', 'cgs206': 'MixerSum(0.20, 6)', 'cgs207': 'MixerSum(0.20, 7)', # 'cgdzpd102': 'MixerDif(0.10, 2)', 'cgdzpd103': 'MixerDif(0.10, 3)', 'cgdzpd104': 'MixerDif(0.10, 4)', 'cgdzpd105': 'MixerDif(0.10, 5)', 'cgdzpd106': 'MixerDif(0.10, 6)', 'cgdzpd107': 'MixerDif(0.10, 7)', 'cgdzpd108': 'MixerDif(0.10, 8)', 'cgdzpd152': 'MixerDif(0.15, 2)', 'cgdzpd153': 'MixerDif(0.15, 3)', 'cgdzpd154': 'MixerDif(0.15, 4)', 'cgdzpd155': 'MixerDif(0.15, 5)', 'cgdzpd156': 'MixerDif(0.15, 6)', 'cgdzpd157': 'MixerDif(0.15, 7)', 'cgdzpd158': 'MixerDif(0.15, 8)', 'cgdzpd202': 'MixerDif(0.20, 2)', 'cgdzpd203': 'MixerDif(0.20, 3)', 'cgdzpd204': 'MixerDif(0.20, 4)', 'cgdzpd205': 'MixerDif(0.20, 5)', 'cgdzpd206': 'MixerDif(0.20, 6)', 'cgdzpd207': 'MixerDif(0.20, 7)', 'cgdzpd208': 'MixerDif(0.20, 8)', 'cgdzpd252': 'MixerDif(0.25, 2)', 'cgdzpd253': 'MixerDif(0.25, 3)', 'cgdzpd254': 'MixerDif(0.25, 4)', 'cgdzpd255': 'MixerDif(0.25, 5)', 'cgdzpd256': 'MixerDif(0.25, 6)', 'cgdzpd257': 'MixerDif(0.25, 7)', 'cgdzpd258': 'MixerDif(0.25, 8)', 'cgdzpd302': 'MixerDif(0.30, 2)', 'cgdzpd303': 'MixerDif(0.30, 3)', 'cgdzpd304': 'MixerDif(0.30, 4)', 'cgdzpd305': 'MixerDif(0.30, 5)', 'cgdzpd306': 'MixerDif(0.30, 6)', 'cgdzpd307': 'MixerDif(0.30, 7)', 'cgdzpd308': 'MixerDif(0.30, 8)', 'cgdzpd352': 'MixerDif(0.35, 2)', 'cgdzpd353': 'MixerDif(0.35, 3)', 'cgdzpd354': 'MixerDif(0.35, 4)', 'cgdzpd355': 'MixerDif(0.35, 5)', 'cgdzpd356': 'MixerDif(0.35, 6)', 'cgdzpd357': 'MixerDif(0.35, 7)', 'cgdzpd358': 'MixerDif(0.35, 8)', 'cgdzpd402': 'MixerDif(0.40, 2)', 'cgdzpd403': 'MixerDif(0.40, 3)', 'cgdzpd404': 'MixerDif(0.40, 4)', 'cgdzpd405': 'MixerDif(0.40, 5)', 'cgdzpd406': 'MixerDif(0.40, 6)', 'cgdzpd407': 'MixerDif(0.40, 7)', 'cgdzpd408': 'MixerDif(0.40, 8)', # 'cgfm101': 'FFTMixer(0.10, 1)', 'cgfm102': 'FFTMixer(0.10, 2)', 'cgfm103': 'FFTMixer(0.10, 3)', 'cgfm104': 'FFTMixer(0.10, 4)', 'cgfm105': 'FFTMixer(0.10, 5)', 'cgfm106': 'FFTMixer(0.10, 6)', 'cgfm107': 'FFTMixer(0.10, 7)', 'cgfm152': 'FFTMixer(0.15, 2)', 'cgfm153': 'FFTMixer(0.15, 3)', 'cgfm154': 'FFTMixer(0.15, 4)', 'cgfm155': 'FFTMixer(0.15, 5)', 'cgfm156': 'FFTMixer(0.15, 6)', 'cgfm157': 'FFTMixer(0.15, 7)', 'cgfm201': 'FFTMixer(0.20, 2)', 'cgfm202': 'FFTMixer(0.20, 2)', 'cgfm203': 'FFTMixer(0.20, 3)', 'cgfm204': 'FFTMixer(0.20, 4)', 'cgfm205': 'FFTMixer(0.20, 5)', 'cgfm206': 'FFTMixer(0.20, 6)', 'cgfm207': 'FFTMixer(0.20, 7)', 'cgfm252': 'FFTMixer(0.25, 2)', 'cgfm253': 'FFTMixer(0.25, 3)', 'cgfm254': 'FFTMixer(0.25, 4)', 'cgfm255': 'FFTMixer(0.25, 5)', 'cgfm256': 'FFTMixer(0.25, 6)', 'cgfm257': 'FFTMixer(0.25, 7)', # 'cgfs101': 'FFTMixerSum(0.10, 1)', 'cgfs102': 'FFTMixerSum(0.10, 2)', 'cgfs103': 'FFTMixerSum(0.10, 3)', 'cgfs104': 'FFTMixerSum(0.10, 4)', 'cgfs105': 'FFTMixerSum(0.10, 5)', 'cgfs106': 'FFTMixerSum(0.10, 6)', 'cgfs107': 'FFTMixerSum(0.10, 7)', 'cgfs152': 'FFTMixerSum(0.15, 2)', 'cgfs153': 'FFTMixerSum(0.15, 3)', 'cgfs154': 'FFTMixerSum(0.15, 4)', 'cgfs155': 'FFTMixerSum(0.15, 5)', 'cgfs156': 'FFTMixerSum(0.15, 6)', 'cgfs157': 'FFTMixerSum(0.15, 7)', 'cgfs201': 'FFTMixerSum(0.20, 2)', 'cgfs202': 'FFTMixerSum(0.20, 2)', 'cgfs203': 'FFTMixerSum(0.20, 3)', 'cgfs204': 'FFTMixerSum(0.20, 4)', 'cgfs205': 'FFTMixerSum(0.20, 5)', 'cgfs206': 'FFTMixerSum(0.20, 6)', 'cgfs207': 'FFTMixerSum(0.20, 7)', 'cgfs252': 'FFTMixerSum(0.25, 2)', 'cgfs253': 'FFTMixerSum(0.25, 3)', 'cgfs254': 'FFTMixerSum(0.25, 4)', 'cgfs255': 'FFTMixerSum(0.25, 5)', 'cgfs256': 'FFTMixerSum(0.25, 6)', 'cgfs257': 'FFTMixerSum(0.25, 7)', # 'cgfd101': 'FFTMixerDif(0.10, 1)', 'cgfd102': 'FFTMixerDif(0.10, 2)', 'cgfd103': 'FFTMixerDif(0.10, 3)', 'cgfd104': 'FFTMixerDif(0.10, 4)', 'cgfd105': 'FFTMixerDif(0.10, 5)', 'cgfd106': 'FFTMixerDif(0.10, 6)', 'cgfd107': 'FFTMixerDif(0.10, 7)', 'cgfd152': 'FFTMixerDif(0.15, 2)', 'cgfd153': 'FFTMixerDif(0.15, 3)', 'cgfd154': 'FFTMixerDif(0.15, 4)', 'cgfd155': 'FFTMixerDif(0.15, 5)', 'cgfd156': 'FFTMixerDif(0.15, 6)', 'cgfd157': 'FFTMixerDif(0.15, 7)', 'cgfd201': 'FFTMixerDif(0.20, 2)', 'cgfd202': 'FFTMixerDif(0.20, 2)', 'cgfd203': 'FFTMixerDif(0.20, 3)', 'cgfd204': 'FFTMixerDif(0.20, 4)', 'cgfd205': 'FFTMixerDif(0.20, 5)', 'cgfd206': 'FFTMixerDif(0.20, 6)', 'cgfd207': 'FFTMixerDif(0.20, 7)', 'cgfd252': 'FFTMixerDif(0.25, 2)', 'cgfd253': 'FFTMixerDif(0.25, 3)', 'cgfd254': 'FFTMixerDif(0.25, 4)', 'cgfd255': 'FFTMixerDif(0.25, 5)', 'cgfd256': 'FFTMixerDif(0.25, 6)', 'cgfd257': 'FFTMixerDif(0.25, 7)', # 'davm101': 'Mixer(0.10, 1)', 'davm102': 'Mixer(0.10, 2)', 'davm103': 'Mixer(0.10, 3)', 'davm104': 'Mixer(0.10, 4)', 'davm105': 'Mixer(0.10, 5)', 'davm106': 'Mixer(0.10, 6)', 'davm107': 'Mixer(0.10, 7)', 'davm152': 'Mixer(0.15, 2)', 'davm153': 'Mixer(0.15, 3)', 'davm154': 'Mixer(0.15, 4)', 'davm155': 'Mixer(0.15, 5)', 'davm156': 'Mixer(0.15, 6)', 'davm157': 'Mixer(0.15, 7)', 'davm201': 'Mixer(0.20, 2)', 'davm202': 'Mixer(0.20, 2)', 'davm203': 'Mixer(0.20, 3)', 'davm204': 'Mixer(0.20, 4)', 'davm205': 'Mixer(0.20, 5)', 'davm206': 'Mixer(0.20, 6)', 'davm207': 'Mixer(0.20, 7)', 'davm252': 'Mixer(0.25, 2)', 'davm253': 'Mixer(0.25, 3)', 'davm254': 'Mixer(0.25, 4)', 'davm255': 'Mixer(0.25, 5)', 'davm256': 'Mixer(0.25, 6)', 'davm257': 'Mixer(0.25, 7)', # 'davs101': 'MixerSum(0.10, 1)', 'davs102': 'MixerSum(0.10, 2)', 'davs103': 'MixerSum(0.10, 3)', 'davs104': 'MixerSum(0.10, 4)', 'davs105': 'MixerSum(0.10, 5)', 'davs106': 'MixerSum(0.10, 6)', 'davs107': 'MixerSum(0.10, 7)', 'davs152': 'MixerSum(0.15, 2)', 'davs153': 'MixerSum(0.15, 3)', 'davs154': 'MixerSum(0.15, 4)', 'davs155': 'MixerSum(0.15, 5)', 'davs156': 'MixerSum(0.15, 6)', 'davs157': 'MixerSum(0.15, 7)', 'davs201': 'MixerSum(0.20, 2)', 'davs202': 'MixerSum(0.20, 2)', 'davs203': 'MixerSum(0.20, 3)', 'davs204': 'MixerSum(0.20, 4)', 'davs205': 'MixerSum(0.20, 5)', 'davs206': 'MixerSum(0.20, 6)', 'davs207': 'MixerSum(0.20, 7)', 'davs252': 'MixerSum(0.25, 2)', 'davs253': 'MixerSum(0.25, 3)', 'davs254': 'MixerSum(0.25, 4)', 'davs255': 'MixerSum(0.25, 5)', 'davs256': 'MixerSum(0.25, 6)', 'davs257': 'MixerSum(0.25, 7)', # 'davd101': 'MixerDif(0.10, 1)', 'davd102': 'MixerDif(0.10, 2)', 'davd103': 'MixerDif(0.10, 3)', 'davd104': 'MixerDif(0.10, 4)', 'davd105': 'MixerDif(0.10, 5)', 'davd106': 'MixerDif(0.10, 6)', 'davd107': 'MixerDif(0.10, 7)', 'davd152': 'MixerDif(0.15, 2)', 'davd153': 'MixerDif(0.15, 3)', 'davd154': 'MixerDif(0.15, 4)', 'davd155': 'MixerDif(0.15, 5)', 'davd156': 'MixerDif(0.15, 6)', 'davd157': 'MixerDif(0.15, 7)', 'davd201': 'MixerDif(0.20, 2)', 'davd202': 'MixerDif(0.20, 2)', 'davd203': 'MixerDif(0.20, 3)', 'davd204': 'MixerDif(0.20, 4)', 'davd205': 'MixerDif(0.20, 5)', 'davd206': 'MixerDif(0.20, 6)', 'davd207': 'MixerDif(0.20, 7)', 'davd252': 'MixerDif(0.25, 2)', 'davd253': 'MixerDif(0.25, 3)', 'davd254': 'MixerDif(0.25, 4)', 'davd255': 'MixerDif(0.25, 5)', 'davd256': 'MixerDif(0.25, 6)', 'davd257': 'MixerDif(0.25, 7)', # 'davfm101': 'FFTMixer(0.10, 1)', 'davfm102': 'FFTMixer(0.10, 2)', 'davfm103': 'FFTMixer(0.10, 3)', 'davfm104': 'FFTMixer(0.10, 4)', 'davfm105': 'FFTMixer(0.10, 5)', 'davfm106': 'FFTMixer(0.10, 6)', 'davfm107': 'FFTMixer(0.10, 7)', 'davfm152': 'FFTMixer(0.15, 2)', 'davfm153': 'FFTMixer(0.15, 3)', 'davfm154': 'FFTMixer(0.15, 4)', 'davfm155': 'FFTMixer(0.15, 5)', 'davfm156': 'FFTMixer(0.15, 6)', 'davfm157': 'FFTMixer(0.15, 7)', 'davfm201': 'FFTMixer(0.20, 2)', 'davfm202': 'FFTMixer(0.20, 2)', 'davfm203': 'FFTMixer(0.20, 3)', 'davfm204': 'FFTMixer(0.20, 4)', 'davfm205': 'FFTMixer(0.20, 5)', 'davfm206': 'FFTMixer(0.20, 6)', 'davfm207': 'FFTMixer(0.20, 7)', 'davfm252': 'FFTMixer(0.25, 2)', 'davfm253': 'FFTMixer(0.25, 3)', 'davfm254': 'FFTMixer(0.25, 4)', 'davfm255': 'FFTMixer(0.25, 5)', 'davfm256': 'FFTMixer(0.25, 6)', 'davfm257': 'FFTMixer(0.25, 7)', # 'davfs101': 'FFTMixerSum(0.10, 1)', 'davfs102': 'FFTMixerSum(0.10, 2)', 'davfs103': 'FFTMixerSum(0.10, 3)', 'davfs104': 'FFTMixerSum(0.10, 4)', 'davfs105': 'FFTMixerSum(0.10, 5)', 'davfs106': 'FFTMixerSum(0.10, 6)', 'davfs107': 'FFTMixerSum(0.10, 7)', 'davfs152': 'FFTMixerSum(0.15, 2)', 'davfs153': 'FFTMixerSum(0.15, 3)', 'davfs154': 'FFTMixerSum(0.15, 4)', 'davfs155': 'FFTMixerSum(0.15, 5)', 'davfs156': 'FFTMixerSum(0.15, 6)', 'davfs157': 'FFTMixerSum(0.15, 7)', 'davfs201': 'FFTMixerSum(0.20, 2)', 'davfs202': 'FFTMixerSum(0.20, 2)', 'davfs203': 'FFTMixerSum(0.20, 3)', 'davfs204': 'FFTMixerSum(0.20, 4)', 'davfs205': 'FFTMixerSum(0.20, 5)', 'davfs206': 'FFTMixerSum(0.20, 6)', 'davfs207': 'FFTMixerSum(0.20, 7)', 'davfs252': 'FFTMixerSum(0.25, 2)', 'davfs253': 'FFTMixerSum(0.25, 3)', 'davfs254': 'FFTMixerSum(0.25, 4)', 'davfs255': 'FFTMixerSum(0.25, 5)', 'davfs256': 'FFTMixerSum(0.25, 6)', 'davfs257': 'FFTMixerSum(0.25, 7)', # 'davfd101': 'FFTMixerDif(0.10, 1)', 'davfd102': 'FFTMixerDif(0.10, 2)', 'davfd103': 'FFTMixerDif(0.10, 3)', 'davfd104': 'FFTMixerDif(0.10, 4)', 'davfd105': 'FFTMixerDif(0.10, 5)', 'davfd106': 'FFTMixerDif(0.10, 6)', 'davfd107': 'FFTMixerDif(0.10, 7)', 'davfd152': 'FFTMixerDif(0.15, 2)', 'davfd153': 'FFTMixerDif(0.15, 3)', 'davfd154': 'FFTMixerDif(0.15, 4)', 'davfd155': 'FFTMixerDif(0.15, 5)', 'davfd156': 'FFTMixerDif(0.15, 6)', 'davfd157': 'FFTMixerDif(0.15, 7)', 'davfd201': 'FFTMixerDif(0.20, 2)', 'davfd202': 'FFTMixerDif(0.20, 2)', 'davfd203': 'FFTMixerDif(0.20, 3)', 'davfd204': 'FFTMixerDif(0.20, 4)', 'davfd205': 'FFTMixerDif(0.20, 5)', 'davfd206': 'FFTMixerDif(0.20, 6)', 'davfd207': 'FFTMixerDif(0.20, 7)', 'davfd252': 'FFTMixerDif(0.25, 2)', 'davfd253': 'FFTMixerDif(0.25, 3)', 'davfd254': 'FFTMixerDif(0.25, 4)', 'davfd255': 'FFTMixerDif(0.25, 5)', 'davfd256': 'FFTMixerDif(0.25, 6)', 'davfd257': 'FFTMixerDif(0.25, 7)', # 'jacapo': 'dacapo', } if __name__ == '__main__': import os import warnings # silence matplotlib.use() warning warnings.filterwarnings('ignore', '.*This call to matplotlib\.use.*',) assert len(sys.argv) > 1 if len(sys.argv) == 2: taskname = sys.argv[1] tag = None runs = None if len(sys.argv) == 3: taskname = sys.argv[1] tag = sys.argv[2] runs = None if len(sys.argv) == 4: taskname = sys.argv[1] tag = sys.argv[2] runs = sys.argv[3] if runs is None: # use all json files as runs runs = [] for f in glob.glob(taskname + '-' + tag + '*.json'): runs.append(os.path.splitext(f)[0].split('_')[-1]) else: runs = runs.split(',') labels = [] for n, r in enumerate(runs): l = str(n) + ': ' + rundefs[r] # special cases if r == 'm': l += '\ndefault' elif r.startswith('inititer'): inititer = r[len('inititer'):len('inititer') + 2] if inititer == '00': inititer = 'None' else: inititer = str(int(inititer)) l += '\n initial cg iter:' + inititer elif r.startswith('cgbands'): nbands = r[len('cgbands'):len('cgbands') + 2] if nbands == '00': nbands = 'None' else: nbands = str(-int(nbands)) l += '\nnbands=' + nbands elif r.startswith('dzpbands'): nbands = r[len('dzpbands'):len('dzpbands') + 2] if nbands == '00': nbands = 'None' else: nbands = str(-int(nbands)) l += '\nnbands=' + nbands elif r.startswith('bands'): nbands = r[len('bands'):len('bands') + 2] if nbands == '00': nbands = 'None' else: nbands = str(-int(nbands)) l += '\nnbands=' + nbands elif r.startswith('szdzp'): l += '\nsz(dzp)' elif r.startswith('szpdzp'): l += '\nszp(dzp)' elif r.startswith('dzp'): l += '\ndzp' elif r.startswith('cgdzp'): l += '\ncg dzp' elif r.startswith('cg'): l += '\ncg' elif r.startswith('dav'): l += '\ndav' if 'mp' in r: l += '\nMethfesselPaxton' labels.append(l) steps = 80 t = Task(taskname, ','.join(runs), labels=labels, tag=tag, steps=steps, tunit='h') t.analyse() gpaw-0.11.0.13004/gpaw/test/big/scf/g2_1_pbe0_fd.agts.py0000664000175000017500000000146412553643471022331 0ustar jensjjensj00000000000000runs = [ #'bands05m', 'bands10m', # 'bands20m', # large number of bands bad #'m101', #'m102', #'m103', 'm105', # 'm107', # for Mixer nmaxold matters #'m051', # many steps, and no advantage for this set of systems #'m203', # larger mixing better 's103', 'd103', 'd203', 'd253', # MixerDiff best 'dzpm103', 'dzpm203'] # 'dzpm253', # dzp guess does not help runsstr = ','.join(runs) def agts(queue): run = [queue.add('g2_1_pbe0_fd.py %s' % r, ncpus=4, walltime=40 * 60) for r in runs * 2] queue.add('analyse.py molecule scf_g2_1_pbe0_fd ' + runsstr, ncpus=1, walltime=10, deps=run, creates=['scf_g2_1_pbe0_fd_energy.csv', 'scf_g2_1_pbe0_fd_calculator_steps.png']) gpaw-0.11.0.13004/gpaw/test/big/scf/dcdft_pbe_pw.agts.py0000664000175000017500000000257112553643471022642 0ustar jensjjensj00000000000000runs = [ # 'bands00m', # the default number of bands is bad # #'m051', # slower mixing does not help # #'m103poisson', # no influence # 'm103', 'm105', 'm107', # for Mixer nmaxold matters: large is bad # 'b103', 'd103', 's103', # #'d105', 'd107', 'd203', # for MixerDif nmaxold does not matter # 'inititer10m', # cg steps and switching to rmm-diis does not help # 'cgm103', 'cgm203', # cg helps # #'cgs103', # cg + MixerSum # 'cgd103', 'cgd203', 'cgd253', # cg + MixerDif: the winner # 'dzpm103', # lcao guess does not help # #'cgdzpm103', # lcao + cg # #'cgdzps103', # lcao + cg + MixerSum # #'cgdzpd103', # lcao + cg + MixerDif # 'fm103', # FFT 'davd203', # PW mode winner 'davfd203'] # FFT runsstr = ','.join(runs) runsstr += ',jacapo' def agts(queue): run = [queue.add('dcdft_pbe_pw.py %s' % r, ncpus=1, walltime=30 * 60) for r in runs * 8] jacapo = queue.add('dcdft_pbe_pw_jacapo.py', ncpus=1, walltime=10 * 60) if 0: # we don't run all the runs for the moment queue.add('analyse.py bulk scf_dcdft_pbe_pw ' + runsstr, ncpus=1, walltime=10, deps=run + [jacapo], creates=['scf_dcdft_pbe_pw_energy.csv', 'scf_dcdft_pbe_pw_calculator_steps.png']) gpaw-0.11.0.13004/gpaw/test/big/scf/g2_1_pbe0_fd.py0000664000175000017500000000577512553643471021405 0ustar jensjjensj00000000000000import sys from ase.data.g2_1 import data from ase.data.g2_1 import atom_names from ase.data.g2_1 import molecule_names from ase.tasks.main import run from ase.tasks.molecule import MoleculeTask from ase.structure import molecule from gpaw.test.big.scf.analyse import rundefs class Collection: def __init__(self, data, names, cell): self.data = data self.names = names self.cell = cell def __getitem__(self, name): return self.create_item(name) def keys(self): return self.names def create_item(self, name): m = molecule(name, data=self.data) m.set_cell(self.cell) m.set_pbc((0, 0, 0)) m.center() return m class Task(MoleculeTask): def __init__(self, **kwargs): MoleculeTask.__init__(self, **kwargs) def calculate(self, name, atoms): data = MoleculeTask.calculate(self, name, atoms) try: steps = atoms.get_calculator().get_number_of_iterations() except (AttributeError, NotImplemented): steps = None data['calculator steps'] = steps return data from gpaw.mixer import Mixer, MixerSum, MixerSum2, MixerDif from gpaw.mixer import BroydenMixer, BroydenMixerSum from gpaw.factory import GPAWFactory if len(sys.argv) == 1: run = None else: run = sys.argv[1] cell = (12.01, 12.02, 12.03) tag = 'scf_g2_1_pbe0_fd' if run is not None: tag += '_%s' % run calcopts = { 'mode': 'fd', 'xc': 'PBE0', 'width': 0.0, 'fixmom': True, # allow other mixers 'spinpol': True, # allow for long SCFs 'maxiter': 700, } if run.startswith('bands'): nbands = run[len('bands'):len('bands') + 2] if nbands == '00': calcopts.update({'nbands': None}) else: calcopts.update({'nbands': - int(nbands)}) if run.startswith('cgbands'): nbands = run[len('cgbands'):len('cgbands') + 2] if nbands == '00': calcopts.update({'nbands': None}) else: calcopts.update({'nbands': - int(nbands)}) if run.startswith('dzpbands'): nbands = run[len('dzpbands'):len('dzpbands') + 2] if nbands == '00': calcopts.update({'nbands': None}) else: calcopts.update({'nbands': - int(nbands)}) if run.startswith('szpdzp'): calcopts.update({'basis': 'szp(dzp)'}) if run.startswith('szdzp'): calcopts.update({'basis': 'sz(dzp)'}) if run.startswith('dzp'): calcopts.update({'basis': 'dzp'}) if 'cg' in run: calcopts.update({'eigensolver': 'cg'}) else: calcopts.update({'eigensolver': 'rmm-diis'}) if run.startswith('cgdzp'): calcopts.update({'basis': 'dzp'}) calcopts.update({'mixer': eval(rundefs[run])}) calcfactory = GPAWFactory(**calcopts) collection = Collection(data, atom_names + molecule_names, cell) task = Task(calcfactory=calcfactory, tag=tag, use_lock_files=True, collection=collection, cell=cell, ) keys = collection.keys() for m in ['Na2', 'NaCl']: # those seem to need cg keys.remove(m) task.run(keys) gpaw-0.11.0.13004/gpaw/test/big/scf/dcdft_pbe_pw.py0000664000175000017500000001037412553643471021705 0ustar jensjjensj00000000000000import sys from ase.test.tasks.dcdft import DeltaCodesDFTTask from gpaw.atom.configurations import parameters from gpaw.test.big.scf.analyse import rundefs if len(sys.argv) == 1: xc = 'PBE' run = None elif len(sys.argv) == 2: xc = 'PBE' run = sys.argv[1] elif len(sys.argv) == 3: xc = sys.argv[1] run = sys.argv[2] tag = 'scf_dcdft_%s_pw' % (xc.lower()) if run is not None: tag += '_%s' % run class Task(DeltaCodesDFTTask): def __init__(self, inititer=0, **kwargs): DeltaCodesDFTTask.__init__(self, **kwargs) self.inititer = inititer def calculate(self, name, atoms): data = DeltaCodesDFTTask.calculate(self, name, atoms) try: steps = atoms.get_calculator().get_number_of_iterations() except (AttributeError, NotImplemented): steps = None data['calculator steps'] = steps + self.inititer return data from gpaw import ConvergenceError from gpaw import PW from gpaw.factory import GPAWFactory from gpaw.mixer import Mixer, MixerSum, MixerSum2, MixerDif from gpaw.mixer import FFTMixer, FFTMixerSum, FFTMixerDif from gpaw.mixer import BroydenMixer, BroydenMixerSum from gpaw.poisson import PoissonSolver from gpaw.occupations import FermiDirac, MethfesselPaxton class Factory(GPAWFactory): def __init__(self, show_text_output=False, write_gpw_file=None, inititer=0, **kwargs): GPAWFactory.__init__(self, show_text_output=show_text_output, write_gpw_file=write_gpw_file, **kwargs) self.inititer = inititer self.maxiter = kwargs['maxiter'] self.eigensolver = kwargs['eigensolver'] def __call__(self, name, atoms): calculator = GPAWFactory.__call__(self, name, atoms) if name.split('-')[0] in ['Li', 'Na']: # https://listserv.fysik.dtu.dk/pipermail/gpaw-developers/2012-May/002870.html calculator.set(h=0.11) if self.inititer > 0: try: calculator.set(eigensolver='cg') calculator.set(maxiter=self.inititer) atoms.set_calculator(calculator) atoms.get_potential_energy() except ConvergenceError: pass calculator.set(maxiter=self.maxiter) calculator.set(eigensolver=self.eigensolver) return calculator calcopts = { 'mode': PW(), 'xc': xc, # allow other mixers 'spinpol': True, # allow for long SCFs 'maxiter': 500, 'nbands': -5, } if run.startswith('inititer'): inititer = int(run[len('inititer'):len('inititer') + 2]) calcopts.update({'inititer': inititer}) else: inititer = 0 if run.startswith('bands'): nbands = run[len('bands'):len('bands') + 2] if nbands == '00': calcopts.update({'nbands': None}) else: calcopts.update({'nbands': - int(nbands)}) if run.startswith('cgbands'): nbands = run[len('cgbands'):len('cgbands') + 2] if nbands == '00': calcopts.update({'nbands': None}) else: calcopts.update({'nbands': - int(nbands)}) if run.startswith('dzpbands'): nbands = run[len('dzpbands'):len('dzpbands') + 2] if nbands == '00': calcopts.update({'nbands': None}) else: calcopts.update({'nbands': - int(nbands)}) if run.startswith('szpdzp'): calcopts.update({'basis': 'szp(dzp)'}) if run.startswith('szdzp'): calcopts.update({'basis': 'sz(dzp)'}) if run.startswith('dzp'): calcopts.update({'basis': 'dzp'}) if 'cg' in run: calcopts.update({'eigensolver': 'cg'}) elif 'dav' in run: calcopts.update({'eigensolver': 'dav'}) else: calcopts.update({'eigensolver': 'rmm-diis'}) if run.startswith('cgdzp'): calcopts.update({'basis': 'dzp'}) calcopts.update({'mixer': eval(rundefs[run])}) if 'mp' in run: calcopts.update({'occupations': MethfesselPaxton(0.1)}) if 'poisson' in run: calcopts.update({'poissonsolver': PoissonSolver(eps=1e-12)}) calcfactory = Factory(**calcopts) task = Task( inititer=inititer, calcfactory=calcfactory, tag=tag, use_lock_files=True, ) if __name__ == '__main__': # run systems from collection for which we have setups keys = sorted(set(parameters.keys()).intersection(task.collection.names)) task.run(keys) gpaw-0.11.0.13004/gpaw/test/big/scf/__init__.py0000664000175000017500000000000012553643471021005 0ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/big/kpb/0000775000175000017500000000000012553644063016705 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/big/kpb/check.py0000664000175000017500000000175112553643471020342 0ustar jensjjensj00000000000000from __future__ import print_function import ase.db from ase.units import kcal, mol from ase.data.g2_1_ref import ex_atomization, atomization c = ase.db.connect('results.db') # Energy of atoms: atoms = {} for d in c.select(natoms=1): atoms[d.numbers[0]] = [d.energy, d.exx] maepbe = 0.0 maeexx = 0.0 print(' PBE EXX') print(('-' * 48)) for d in c.select('natoms>1'): epberef = atomization[d.name][2] * kcal / mol eexxref = ex_atomization[d.name][0] * kcal / mol epbe = sum(atoms[atom][0] for atom in d.numbers) - d.energy eexx = sum(atoms[atom][1] for atom in d.numbers) - d.exx maepbe += abs(epbe - epberef) / len(ex_atomization) maeexx += abs(eexx - eexxref) / len(ex_atomization) print(('%-4s %10.3f %10.3f %10.3f %10.3f' % (d.name, epbe, epbe - epberef, eexx, eexx - eexxref))) print(('-' * 48)) print(('MAE %10.3f %10.3f %10.3f %10.3f' % (0, maepbe, 0, maeexx))) assert maepbe < 0.025 assert maeexx < 0.05 gpaw-0.11.0.13004/gpaw/test/big/kpb/molecules.py0000664000175000017500000000507312553643471021256 0ustar jensjjensj00000000000000"""Test exact exchange for 20 small molecules. Compare results to:: S. Kurth, J. P. Perdew, and P. Blaha Molecular and Soild-State Tests of Density Functional Approximations: LSD, GGAs, and Meta-GGAs International Journal of Quantum Chemistry, Vol. 75, 889-909, 1999 """ import ase.db from ase import Atoms from ase.structure import molecule from ase.data.g2_1_ref import diatomic, ex_atomization from gpaw import GPAW, PW from gpaw.xc.exx import EXX # Experimental bondlengths: bondlengths = {'H2': 0.741, 'OH': 0.970, 'HF': 0.9168, 'NO': 1.154, 'P2': 1.893} bondlengths.update((name, d[0]) for name, d in diatomic.items()) extra = { 'CH4': ('CH4', [(0.0000, 0.0000, 0.0000), (0.6276, 0.6276, 0.6276), (0.6276, -0.6276, -0.6276), (-0.6276, 0.6276, -0.6276), (-0.6276, -0.6276, 0.6276)]), 'NH3': ('NH3', [(0.0000, 0.0000, 0.0000), (0.0000, -0.9377, -0.3816), (0.8121, 0.4689, -0.3816), (-0.8121, 0.4689, -0.3816)]), 'H2O': ('OH2', [(0.0000, 0.0000, 0.1173), (0.0000, 0.7572, -0.4692), (0.0000, -0.7572, -0.4692)]), 'C2H2': ('C2H2', [(0.0000, 0.0000, 0.6013), (0.0000, 0.0000, -0.6013), (0.0000, 0.0000, 1.6644), (0.0000, 0.0000, -1.6644)]), 'C2H4': ('C2H4', [(0.0000, 0.0000, 0.6695), (0.0000, 0.0000, -0.6695), (0.0000, 0.9289, 1.2321), (0.0000, -0.9289, 1.2321), (0.0000, 0.9289, -1.2321), (0.0000, -0.9289, -1.2321)]), 'HCN': ('CHN', [(0.0000, 0.0000, 0.0000), (0.0000, 0.0000, 1.0640), (0.0000, 0.0000, -1.1560)]), 'Be2': ('Be2', [(0.0000, 0.0000, 0.0000), (0.0000, 0.0000, 2.460)])} c = ase.db.connect('results.db') for name in ex_atomization.keys() + 'H Li Be B C N O F Cl P'.split(): id = c.reserve(name=name) if id is None: continue if name in extra: a = Atoms(*extra[name]) else: a = molecule(name) if name in bondlengths: a.set_distance(0, 1, bondlengths[name]) a.cell = [11, 12, 13] a.center() a.calc = GPAW(xc='PBE', mode=PW(500), txt=name + '.txt', dtype=complex) a.get_potential_energy() exx = EXX(a.calc) exx.calculate() eexx = exx.get_total_energy() c.write(a, name=name, exx=eexx) del c[id] gpaw-0.11.0.13004/gpaw/test/big/kpb/submit.agts.py0000664000175000017500000000034112553643471021517 0ustar jensjjensj00000000000000def agts(queue): molecules = [queue.add('molecules.py %d' % i, ncpus=1, walltime=2*60) for i in range(2)] queue.add('check.py', deps=molecules) gpaw-0.11.0.13004/gpaw/test/big/kpb/__init__.py0000664000175000017500000000000012553643471021006 0ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/big/niflheim.py0000664000175000017500000000741512553643471020307 0ustar jensjjensj00000000000000import os import subprocess from gpaw.test.big.agts import Cluster class NiflheimCluster(Cluster): def __init__(self, asepath='', setuppath='$GPAW_SETUP_PATH'): self.asepath = asepath self.setuppath = setuppath def submit(self, job): dir = os.getcwd() os.chdir(job.dir) self.write_pylab_wrapper(job) if job.queueopts is None: if job.ncpus < 4: ppn = '%d:opteron:ethernet' % job.ncpus nodes = 1 arch = 'linux-x86_64-opteron-2.4' elif job.ncpus % 8 == 0: ppn = '8:xeon5570' nodes = job.ncpus // 8 arch = 'linux-x86_64-xeon-2.4' else: assert job.ncpus % 4 == 0 ppn = '4:opteron:ethernet' nodes = job.ncpus // 4 arch = 'linux-x86_64-opteron-2.4' queueopts = '-l nodes=%d:ppn=%s' % (nodes, ppn) else: queueopts = job.queueopts arch = 'linux-x86_64-xeon-2.4' gpaw_python = os.path.join(dir, 'gpaw', 'build', 'bin.' + arch, 'gpaw-python') submit_pythonpath = ':'.join([ self.asepath, dir + '/gpaw', '%s/gpaw/build/lib.%s' % (dir, arch), '$PYTHONPATH']) run_command = '. /home/camp/modulefiles.sh&& ' run_command += 'module load MATPLOTLIB&& ' # loads numpy, mpl, ... run_command += 'module load SCIPY&& ' run_command += 'module load povray&& ' run_command += 'module load ABINIT&& ' run_command += 'module load DACAPO&& ' run_command += 'module unload SCIENTIFICPYTHON&& ' run_command += 'module load SCIENTIFICPYTHON/2.8&& ' run_command += 'module use --append /home/niflheim/dulak/NWchem&& ' run_command += 'module load NWCHEM/6.1-27.1.x86_64&& ' if job.ncpus == 1: # don't use mpiexec here, # this allows one to start mpi inside the *.agts.py script run_command += 'module load ' run_command += 'openmpi/1.3.3-1.el5.fys.gfortran43.4.3.2&& ' run_command += ' export PYTHONPATH=' + submit_pythonpath + '&&' run_command += ' export GPAW_SETUP_PATH=' + self.setuppath + '&&' # we want to run GPAW/ASE scripts + gpaw-python with os.system! run_command += ' PATH=%s/ase/tools:$PATH' % dir + '&&' run_command += ' PATH=%s/gpaw/tools:$PATH' % dir + '&&' run_command += ' PATH=%s/gpaw/build/bin.%s:$PATH' % (dir, arch) + '&&' # we run other codes with asec run_command += ' export ASE_ABINIT_COMMAND="mpiexec abinip < PREFIX.files > PREFIX.log"&&' else: run_command += 'module load ' run_command += 'openmpi/1.3.3-1.el5.fys.gfortran43.4.3.2&& ' run_command += 'mpiexec --mca mpi_paffinity_alone 1' run_command += ' -x PYTHONPATH=' + submit_pythonpath run_command += ' -x GPAW_SETUP_PATH=' + self.setuppath run_command += ' -x OMP_NUM_THREADS=1' p = subprocess.Popen( ['/usr/local/bin/qsub', '-V', queueopts, '-l', 'walltime=%d:%02d:00' % (job.walltime // 3600, job.walltime % 3600 // 60), '-N', job.name], stdin=subprocess.PIPE, stdout=subprocess.PIPE) out, err = p.communicate( 'touch %s.start\n' % job.name + run_command + ' %s %s.py %s > %s.output\n' % (gpaw_python, job.script, job.args, job.name) + 'echo $? > %s.done\n' % job.name) assert p.returncode == 0 id = out.split('.')[0] job.pbsid = id os.chdir(dir) gpaw-0.11.0.13004/gpaw/test/big/dcdft/0000775000175000017500000000000012553644063017215 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/big/dcdft/pbe_jacapo.py0000664000175000017500000000321112553643471021651 0ustar jensjjensj00000000000000from ase.calculators.jacapo.pw91_psp import defaultpseudopotentials as psp from ase.tasks.calcfactory import calculator_factory from ase.test.tasks.dcdft import DeltaCodesDFTTask as Task xc = 'PBE' fit = (5, 0.02) w = 0.06 pw = 700 dw = 1000 kd = 8.0 tag = 'dcdft_%s_jacapo' % xc.lower() calcfactory = calculator_factory('jacapo', pw=pw, dw=dw, xc='PBE', #convergence={ #'energy':0.00001, #'density':0.000001, # 0.0001 #'occupation':0.001, # 0.001 #'maxsteps':None, #'maxtime':None #}, ft=w, symmetry=True, spinpol=True, # must set explicitly calculate_stress=False, deletenc=True, # start fresh every time kptdensity=kd, ) taskopts = {} task = Task( calcfactory=calcfactory, tag=tag, fit=fit, use_lock_files=True, **taskopts) if __name__ == '__main__': keys = set(psp.keys()).intersection(set(task.collection.names)) for m in ['Be', 'Cr', 'Kr', 'Xe']: keys.remove(m) # EOS fails: maybe need higher ecut? for m in ['Zn', 'Zr']: keys.remove(m) # do not converge # run just only system to check if scripts work keys = ['Si'] task.run(keys) gpaw-0.11.0.13004/gpaw/test/big/dcdft/pbe_abinit_paw.py0000664000175000017500000000657112553643471022545 0ustar jensjjensj00000000000000import os import sys import time import numpy as np import ase.db from ase.units import Rydberg from ase.utils import opencew from ase.calculators.calculator import kpts2mp from ase.io import Trajectory from ase.calculators.abinit import Abinit from ase.test.tasks.dcdft import DeltaCodesDFTCollection as Collection collection = Collection() if len(sys.argv) == 1: names = collection.names else: names = [sys.argv[1]] c = ase.db.connect('dcdft_abinit_paw.db') ecut = 100 pawecutdg = 300 kptdensity = 16.0 # this is converged kptdensity = 6.0 # just for testing width = 0.01 ecutsm = 0.0 fband = 1.5 tolsym = 1.e-12 linspace = (0.98, 1.02, 5) # eos numpy's linspace linspacestr = ''.join([str(t) + 'x' for t in linspace])[:-1] code = 'abinit' + '-' + '_c' + str(ecut) + str(pawecutdg) + '_e' + linspacestr code = code + '_k' + str(kptdensity) + '_w' + str(width) + '_s' + str(ecutsm) + '_t' + str(tolsym) for name in names: # save all steps in one traj file in addition to the database # we should only used the database c.reserve, but here # traj file is used as another lock ... fd = opencew(name + '_' + code + '.traj') if fd is None: continue traj = Trajectory(name + '_' + code + '.traj', 'w') atoms = collection[name] if name == 'Mn': # fails to find the right magnetic state atoms.set_initial_magnetic_moments([10., 20., -10., -20.]) if name == 'Co': # fails to find the right magnetic state atoms.set_initial_magnetic_moments([10., 10.]) if name == 'Ni': # fails to find the right magnetic state atoms.set_initial_magnetic_moments([10., 10., 10., 10.]) cell = atoms.get_cell() kpts = tuple(kpts2mp(atoms, kptdensity, even=True)) kwargs = {} # loop over EOS linspace for n, x in enumerate(np.linspace(linspace[0], linspace[1], linspace[2])): id = c.reserve(name=name, ecut=ecut, pawecutdg=pawecutdg, linspacestr=linspacestr, kptdensity=kptdensity, width=width, ecutsm=ecutsm, fband=fband, tolsym=tolsym, x=x) if id is None: continue # perform EOS step atoms.set_cell(cell * x, scale_atoms=True) # set calculator atoms.calc = Abinit( pps='paw', # uses highest valence label=name + '_' + code + '_' + str(n), xc='PBE', kpts=kpts, ecut=ecut*Rydberg, pawecutdg=pawecutdg*Rydberg, occopt=3, tsmear=width, ecutsm=ecutsm, toldfe=1.0e-6, nstep=900, pawovlp=-1, # bypass overlap check fband=fband, # http://forum.abinit.org/viewtopic.php?f=8&t=35 chksymbreak=0, tolsym=tolsym, prtwf=0, prtden=0, ) atoms.calc.set(**kwargs) # remaining calc keywords t = time.time() atoms.get_potential_energy() c.write(atoms, name=name, ecut=ecut, pawecutdg=pawecutdg, linspacestr=linspacestr, kptdensity=kptdensity, width=width, ecutsm=ecutsm, fband=fband, tolsym=tolsym, x=x, time=time.time()-t) traj.write(atoms) wfk = name + '_' + code + '_' + str(n) + 'o_WFK' if os.path.exists(wfk): os.remove(wfk) del c[id] gpaw-0.11.0.13004/gpaw/test/big/dcdft/pbe_abinit_hgh.py0000664000175000017500000000642112553643471022516 0ustar jensjjensj00000000000000import os import sys import time import numpy as np import ase.db from ase.units import Rydberg from ase.utils import opencew from ase.calculators.calculator import kpts2mp from ase.io import Trajectory from ase.calculators.abinit import Abinit from ase.test.tasks.dcdft import DeltaCodesDFTCollection as Collection collection = Collection() if len(sys.argv) == 1: names = collection.names else: names = [sys.argv[1]] c = ase.db.connect('dcdft_abinit_hgh.db') ecut = 250 kptdensity = 16.0 # this is converged kptdensity = 6.0 # just for testing width = 0.01 ecutsm = 0.0 fband = 1.5 tolsym = 1.e-12 linspace = (0.98, 1.02, 5) # eos numpy's linspace linspacestr = ''.join([str(t) + 'x' for t in linspace])[:-1] code = 'abinit' + '-' + '_c' + str(ecut) + '_e' + linspacestr code = code + '_k' + str(kptdensity) + '_w' + str(width) + '_s' + str(ecutsm) + '_t' + str(tolsym) for name in names: # save all steps in one traj file in addition to the database # we should only used the database c.reserve, but here # traj file is used as another lock ... fd = opencew(name + '_' + code + '.traj') if fd is None: continue traj = Trajectory(name + '_' + code + '.traj', 'w') atoms = collection[name] if name == 'Mn': # fails to find the right magnetic state atoms.set_initial_magnetic_moments([10., 20., -10., -20.]) if name == 'Co': # fails to find the right magnetic state atoms.set_initial_magnetic_moments([10., 10.]) if name == 'Ni': # fails to find the right magnetic state atoms.set_initial_magnetic_moments([10., 10., 10., 10.]) cell = atoms.get_cell() kpts = tuple(kpts2mp(atoms, kptdensity, even=True)) kwargs = {} # loop over EOS linspace for n, x in enumerate(np.linspace(linspace[0], linspace[1], linspace[2])): id = c.reserve(name=name, ecut=ecut, linspacestr=linspacestr, kptdensity=kptdensity, width=width, ecutsm=ecutsm, fband=fband, tolsym=tolsym, x=x) if id is None: continue # perform EOS step atoms.set_cell(cell * x, scale_atoms=True) # set calculator atoms.calc = Abinit( pps='hgh.k', # uses highest valence hgh.k pps label=name + '_' + code + '_' + str(n), xc='PBE', kpts=kpts, ecut=ecut*Rydberg, occopt=3, tsmear=width, ecutsm=ecutsm, toldfe=1.0e-6, nstep=900, pawovlp=-1, # bypass overlap check fband=fband, # http://forum.abinit.org/viewtopic.php?f=8&t=35 chksymbreak=0, tolsym=tolsym, prtwf=0, prtden=0, ) atoms.calc.set(**kwargs) # remaining calc keywords t = time.time() atoms.get_potential_energy() c.write(atoms, name=name, ecut=ecut, linspacestr=linspacestr, kptdensity=kptdensity, width=width, ecutsm=ecutsm, fband=fband, tolsym=tolsym, x=x, time=time.time()-t) traj.write(atoms) wfk = name + '_' + code + '_' + str(n) + 'o_WFK' if os.path.exists(wfk): os.remove(wfk) del c[id] gpaw-0.11.0.13004/gpaw/test/big/dcdft/pbe_gpaw_pw.py0000664000175000017500000000746312553643471022075 0ustar jensjjensj00000000000000import os import sys import time import numpy as np import ase.db from ase.units import Rydberg from ase.utils import opencew from ase.calculators.calculator import kpts2mp from ase.io import Trajectory from ase.test.tasks.dcdft import DeltaCodesDFTCollection as Collection from gpaw import GPAW, PW from gpaw.mixer import Mixer from gpaw.utilities import h2gpts collection = Collection() if len(sys.argv) == 1: names = collection.names else: names = [sys.argv[1]] c = ase.db.connect('dcdft_gpaw_pw.db') #mode = 'lcao' mode = 'fd' mode = 'pw' e = 0.08 # h -> gpts e = round(100 * Rydberg, 0) kptdensity = 16.0 # this is converged kptdensity = 6.0 # just for testing width = 0.01 relativistic = True constant_basis = True if relativistic: linspace = (0.98, 1.02, 5) # eos numpy's linspace else: linspace = (0.92, 1.08, 7) # eos numpy's linspace linspacestr = ''.join([str(t) + 'x' for t in linspace])[:-1] code = 'gpaw' + '-' + mode + str(e) + '_c' + str(constant_basis) + '_e' + linspacestr code = code + '_k' + str(kptdensity) + '_w' + str(width) code = code + '_r' + str(relativistic) for name in names: # save all steps in one traj file in addition to the database # we should only used the database c.reserve, but here # traj file is used as another lock ... fd = opencew(name + '_' + code + '.traj') if fd is None: continue traj = Trajectory(name + '_' + code + '.traj', 'w') atoms = collection[name] cell = atoms.get_cell() kpts = tuple(kpts2mp(atoms, kptdensity, even=True)) kwargs = {} if mode in ['fd', 'lcao']: if constant_basis: # gives more smooth EOS in fd mode kwargs.update({'gpts': h2gpts(e, cell)}) else: kwargs.update({'h': e}) elif mode == 'pw': if constant_basis: kwargs.update({'mode': PW(e, cell=cell)}) kwargs.update({'gpts': h2gpts(0.10, cell)}) else: kwargs.update({'mode': PW(e)}) if mode == 'pw': if name in ['Li', 'Na']: # https://listserv.fysik.dtu.dk/pipermail/gpaw-developers/2012-May/002870.html if constant_basis: kwargs.update({'gpts': h2gpts(0.05, cell)}) else: kwargs.update({'h': 0.05}) if mode == 'lcao': kwargs.update({'mode': 'lcao'}) kwargs.update({'basis': 'dzp'}) if name in ['He', 'Ne', 'Ar', 'Kr', 'Xe', 'Rn', 'Ca', 'Sr', 'Ba', 'Be']: # results wrong / scf slow with minimal basis kwargs.update({'basis': 'dzp'}) kwargs.update({'nbands': -5}) # loop over EOS linspace for n, x in enumerate(np.linspace(linspace[0], linspace[1], linspace[2])): id = c.reserve(name=name, mode=mode, e=e, linspacestr=linspacestr, kptdensity=kptdensity, width=width, relativistic=relativistic, constant_basis=constant_basis, x=x) if id is None: continue # perform EOS step atoms.set_cell(cell * x, scale_atoms=True) # set calculator atoms.calc = GPAW( txt=name + '_' + code + '_' + str(n) + '.txt', xc='PBE', kpts=kpts, width=width, parallel={'band': 1}, maxiter=777, idiotproof=False) atoms.calc.set(**kwargs) # remaining calc keywords t = time.time() atoms.get_potential_energy() c.write(atoms, name=name, mode=mode, e=e, linspacestr=linspacestr, kptdensity=kptdensity, width=width, relativistic=relativistic, constant_basis=constant_basis, x=x, niter=atoms.calc.get_number_of_iterations(), time=time.time()-t) traj.write(atoms) del c[id] gpaw-0.11.0.13004/gpaw/test/big/dcdft/pbe_aims.py0000664000175000017500000001015412553643471021351 0ustar jensjjensj00000000000000import os import sys import time import numpy as np import ase.db from ase.utils import opencew from ase.calculators.calculator import kpts2mp from ase.io import Trajectory from ase.calculators.aims import Aims from ase.test.tasks.dcdft import DeltaCodesDFTCollection as Collection collection = Collection() if len(sys.argv) == 1: names = collection.names else: names = [sys.argv[1]] c = ase.db.connect('dcdft_aims.db') # select the basis set basis = 'light' #basis = 'tight' #basis = 'really_tight' #basis = 'tier2' kptdensity = 16.0 # this is converged kptdensity = 6.0 # just for testing width = 0.01 basis_threshold = 0.00001 relativistic = 'none' relativistic = 1.e-12 relativistic = 'scalar' sc_accuracy_rho = 1.e-4 sc_accuracy_eev = 5.e-3 if relativistic == 'none': linspace = (0.92, 1.08, 7) # eos numpy's linspace else: linspace = (0.98, 1.02, 5) # eos numpy's linspace linspacestr = ''.join([str(t) + 'x' for t in linspace])[:-1] code = 'aims' + '-' + basis + '_e' + linspacestr code = code + '_k' + str(kptdensity) + '_w' + str(width) code = code + '_t' + str(basis_threshold) + '_r' + str(relativistic) collection = Collection() for name in names: # save all steps in one traj file in addition to the database # we should only used the database c.reserve, but here # traj file is used as another lock ... fd = opencew(name + '_' + code + '.traj') if fd is None: continue traj = Trajectory(name + '_' + code + '.traj', 'w') atoms = collection[name] cell = atoms.get_cell() kpts = tuple(kpts2mp(atoms, kptdensity, even=True)) kwargs = {} if relativistic == 'scalar': kwargs.update({'relativistic': ['atomic_zora', relativistic]}) elif relativistic == 'none': kwargs.update({'relativistic': 'none'}) else: # e.g. 1.0e-12 kwargs.update({'relativistic': ['zora', 'scalar', relativistic]}) if atoms.get_initial_magnetic_moments().any(): # spin-polarization magmom = atoms.get_initial_magnetic_moments().sum() / len(atoms) kwargs.update({'spin': 'collinear'}) # convergence problems for tier2 charge_mix_param = 0.01 basis_threshold = 0.00001 if basis in ['tier2']: if name in ['Cr', 'Fe'] and relativistic == 'none': basis_threshold = 0.00005 sc_accuracy_rho=2.5e-3 sc_accuracy_eev=5.e-3 if name in ['Mn']: charge_mix_param = 0.01 basis_threshold = 0.00005 sc_accuracy_rho=2.5e-3 sc_accuracy_eev=5.e-3 if relativistic == 'none': sc_accuracy_rho=3.0e-3 # loop over EOS linspace for n, x in enumerate(np.linspace(linspace[0], linspace[1], linspace[2])): id = c.reserve(name=name, basis=basis, linspacestr=linspacestr, kptdensity=kptdensity, width=width, basis_threshold=basis_threshold, relativistic=relativistic, x=x) if id is None: continue # perform EOS step atoms.set_cell(cell * x, scale_atoms=True) # set calculator atoms.calc = Aims( label=name + '_' + code + '_' + str(n), species_dir=os.path.join(os.environ['AIMS_SPECIES_DIR'], basis), xc='PBE', kpts=kpts, KS_method='elpa', sc_accuracy_rho=sc_accuracy_rho, sc_accuracy_eev=sc_accuracy_eev, occupation_type=['gaussian', width], override_relativity=True, override_illconditioning=True, basis_threshold=basis_threshold, charge_mix_param=charge_mix_param, sc_iter_limit=9000, ) atoms.calc.set(**kwargs) # remaining calc keywords t = time.time() atoms.get_potential_energy() c.write(atoms, name=name, basis=basis, linspacestr=linspacestr, kptdensity=kptdensity, width=width, basis_threshold=basis_threshold, relativistic=relativistic, x=x, time=time.time()-t) traj.write(atoms) del c[id] gpaw-0.11.0.13004/gpaw/test/big/dcdft/pbe_jacapo.agts.py0000664000175000017500000000124412553643471022612 0ustar jensjjensj00000000000000def agts(queue): run = [queue.add('pbe_jacapo.py %s' % r, queueopts='-l nodes=1:ppn=4:opteron4', ncpus=1, walltime=10*60) for r in range(0)] if 0: # do not perform analysis # we keep once generated files static analyse = queue.add('analyse.py dcdft_pbe_jacapo', ncpus=1, walltime=10, deps=run, creates=['dcdft_pbe_jacapo.csv', 'dcdft_pbe_jacapo.txt', 'dcdft_pbe_jacapo_Delta.txt', 'dcdft_pbe_jacapo_raw.csv']) gpaw-0.11.0.13004/gpaw/test/big/dcdft/pbe_gpaw_pw_verify.py0000664000175000017500000000515012553643471023450 0ustar jensjjensj00000000000000import csv import numpy as np from gpaw.test.big.dcdft.pbe_gpaw_pw import tag # calculated with pw=1200, k-point-density=8, width=0.06, fit=(5, 0.02) data = """ H,17.459,10.34,2.705 He,17.264,1.047,6.06 Li,20.259,14.058,3.365 Be,8.008,123.494,3.348 B,7.241,237.967,3.464 C,11.645,209.686,3.566 N,28.797,54.159,3.694 O,18.525,51.715,3.895 F,19.049,37.197,3.735 Ne,23.938,1.43,6.456 Na,37.321,7.609,-1.136 Mg,22.892,36.231,4.033 Al,16.517,77.66,4.609 Si,20.52,88.516,4.326 P,21.532,68.002,4.348 S,17.187,84.008,4.207 Cl,38.949,19.016,4.378 Ar,52.201,0.788,7.033 K,73.563,3.608,3.772 Ca,42.395,17.422,3.273 Sc,24.573,54.613,3.393 Ti,17.437,112.194,3.594 V,13.543,182.429,3.802 Cr,11.852,161.406,7.241 Mn,11.471,121.43,0.493 Fe,11.472,193.38,5.62 Co,10.91,215.828,5.115 Ni,10.982,203.94,4.947 Cu,12.081,137.188,5.078 Zn,15.122,76.379,5.407 Ga,20.538,49.728,5.378 Ge,23.967,60.21,4.906 As,22.637,68.795,4.294 Se,29.761,47.304,4.481 Br,39.768,22.302,4.866 Kr,66.26,0.636,7.271 Rb,91.121,2.786,3.765 Sr,54.662,12.391,4.328 Y,32.858,41.22,3.014 Zr,23.323,93.99,3.322 Nb,18.034,170.426,3.92 Mo,15.765,259.394,4.367 Ru,13.735,309.531,4.858 Rh,14.137,253.502,5.26 Pd,15.304,169.253,5.614 Ag,17.807,92.333,5.751 Cd,22.575,46.346,6.714 In,27.244,36.05,5.299 Sn,36.581,36.313,4.912 Sb,31.593,50.484,4.485 Te,34.708,45.262,4.716 I,50.594,18.551,5.083 Xe,87.204,0.529,7.235 Cs,117.31,1.961,3.492 Ba,63.575,8.813,2.853 Hf,22.586,108.63,3.452 Ta,18.302,193.805,3.813 W,16.115,304.826,4.245 Re,14.926,365.244,4.435 Os,14.194,400.169,4.813 Ir,14.452,348.912,5.111 Pt,15.613,246.217,5.496 Au,18.208,138.897,5.823 Hg,28.515,10.958,11.346 Tl,31.107,27.488,5.364 Pb,31.872,37.943,4.848 Bi,36.831,42.751,4.64 Rn,93.543,0.523,7.228 """ names = [r.split(',')[0] for r in data.split()][1:] ref = {} for name in names: for l in data.split(): if l.split(',')[0] == name: ref[name] = [float(v) for v in l.split(',')[1:]] csvreader = csv.reader(open(tag + '_raw.csv', 'rb')) calc = {} for r in csvreader: if "#" not in r[0]: calc[r[0]] = [float(v) for v in r[1:]] for name in names: if name in calc.keys(): vref = ref[name][0] vcalc = calc[name][0] errmsg = name + ': ' + str(vref) + ' vs ' + str(vcalc) assert abs(vcalc - vref) / vref < 0.002, errmsg b0ref = ref[name][1] b0calc = calc[name][1] errmsg = name + ': ' + str(b0ref) + ' vs ' + str(b0calc) assert abs(b0calc - b0ref) / b0ref < 0.01, errmsg b1ref = ref[name][2] b1calc = calc[name][2] errmsg = name + ': ' + str(b1ref) + ' vs ' + str(b1calc) assert abs(b1calc - b1ref) / b1ref < 0.05, errmsg gpaw-0.11.0.13004/gpaw/test/big/dcdft/pbe_abinit_paw.agts.py0000664000175000017500000000042512553643471023472 0ustar jensjjensj00000000000000# Note: due to how agts works external executables (abinit, aims, etc.) # must be run on the submission platform (bmaster1), currently opteron4 def agts(queue): queue.add('pbe_abinit_paw.py Au', ncpus=1, queueopts='-l nodes=1:ppn=4:opteron4', walltime=10*60) gpaw-0.11.0.13004/gpaw/test/big/dcdft/analyse.py0000664000175000017500000001021012553643471021217 0ustar jensjjensj00000000000000import os import sys import urllib.request, urllib.parse, urllib.error import urllib.request, urllib.error, urllib.parse import tarfile import zipfile import csv import numpy as np from ase.test import NotAvailable from ase import units from ase.test.tasks.dcdft import DeltaCodesDFTTask as Task dir = 'Delta' if len(sys.argv) == 1: tag = None reffile = os.path.join(dir, 'WIEN2k.txt') else: if len(sys.argv) == 3: tag = sys.argv[1] reffile = sys.argv[2] else: tag = sys.argv[1] reffile = os.path.join(dir, 'WIEN2k.txt') src = 'https://molmod.ugent.be/sites/default/files/Delta_v3-0.zip' name = os.path.basename(src) if not os.path.exists(dir): os.makedirs(dir) os.chdir(dir) if not os.path.exists('calcDelta.py'): try: resp = urllib.request.urlopen(src) urllib.request.urlretrieve(src, filename=name) z = zipfile.ZipFile(name) try: # new in 2.6 z.extractall() except AttributeError: # http://stackoverflow.com/questions/7806563/how-to-unzip-a-zip-file-with-python-2-4 for f in z.namelist(): fd = open(f, "w") fd.write(z.read(f)) fd.close() # AttributeError if unzip not found except (urllib.error.HTTPError, AttributeError): raise NotAvailable('Retrieval of zip failed') os.chdir('..') task = Task( tag=tag, use_lock_files=True, ) # header h = ['#element', 'V0', 'B0', 'B1'] if not os.path.exists('%s_raw.csv' % tag): # read calculated results from json file and write into csv task.read() task.analyse() f1 = open('%s_raw.csv' % tag, 'wb') csvwriter1 = csv.writer(f1) csvwriter1.writerow(h) for n in task.collection.names: row = [n] if n in task.data.keys(): try: v = task.data[n]['dcdft volume'] b0 = task.data[n]['dcdft B0'] / (units.kJ * 1e-24) b1 = task.data[n]['dcdft B1'] row.extend([v, b0, b1]) except KeyError: # completely failed to find eos minimum row.extend(['N/A', 'N/A', 'N/A']) else: # element not calculated row.extend(['N/A', 'N/A', 'N/A']) if 'N/A' not in row: csvwriter1.writerow(row) f1.close() # read raw results csvreader1 = csv.reader(open('%s_raw.csv' % tag, 'r')) data = {} for row in csvreader1: if '#' not in row[0]: data[row[0]] = {'dcdft volume': float(row[1]), 'dcdft B0': float(row[2]), 'dcdft B1': float(row[3])} csvwriter2 = csv.writer(open('%s.csv' % tag, 'wb')) h2 = h + ['%' + h[1], '%' + h[2], '%' + h[3]] csvwriter2.writerow(h2) refs = np.loadtxt(reffile, dtype={'names': ('element', 'V0', 'B0', 'BP'), 'formats': ('S2', np.float, np.float, np.float)}) # convert into dict refsd = {} for e, v, b0, b1 in refs: refsd[e] = [v, b0, b1] rows = [] rowserr = [] for n in task.collection.names: row = [n] if n in data.keys(): if 0: ref = task.collection.ref[n] # don't use collection data else: ref = refsd[n] try: v = round(data[n]['dcdft volume'], 3) b0 = round(data[n]['dcdft B0'], 3) b1 = round(data[n]['dcdft B1'], 3) row.extend([v, b0, b1]) except KeyError: # completely failed to find eos minimum row.extend(['N/A', 'N/A', 'N/A']) else: # element not calculated row.extend(['N/A', 'N/A', 'N/A']) if 'N/A' not in row: v0, b00, b10 = ref ve = round((v - v0) / v0 * 100, 1) b0e = round((b0 - b00) / b00 * 100, 1) b1e = round((b1 - b10) / b10 * 100, 1) rows.append(row) #print row + ref + [ve, b0e, b1e] csvwriter2.writerow(row + [ve, b0e, b1e]) # calculate Delta f = open('%s.txt' % tag, 'wb') csvwriter3 = csv.writer(f, delimiter='\t') for r in rows: csvwriter3.writerow(r) f.close() cmd = 'python ' + os.path.join(dir, 'calcDelta.py') cmd += ' ' + '%s.txt ' % tag + reffile + ' --stdout' cmd += ' > ' + '%s_Delta.txt' % tag os.system(cmd) gpaw-0.11.0.13004/gpaw/test/big/dcdft/pbe_gpaw_pw.agts.py0000664000175000017500000000124212553643471023017 0ustar jensjjensj00000000000000def agts(queue): run = queue.add('pbe_gpaw_pw.py Al', ncpus=4, queueopts='-l nodes=1:ppn=4:opteron4', walltime=60) if 0: # run when new setups ready analyse = queue.add('analyse.py dcdft_pbe_gpaw_pw', ncpus=1, walltime=10, deps=run, creates=['dcdft_pbe_gpaw_pw.csv', 'dcdft_pbe_gpaw_pw.txt', 'dcdft_pbe_gpaw_pw_Delta.txt', 'dcdft_pbe_gpaw_pw_raw.csv']) verify = queue.add('pbe_gpaw_pw_verify.py', ncpus=1, walltime=10, deps=[analyse]) gpaw-0.11.0.13004/gpaw/test/big/dcdft/pbe_abinit_fhi.py0000664000175000017500000000550712553643471022522 0ustar jensjjensj00000000000000import os import time import numpy as np import ase.db from ase.units import Rydberg from ase.utils import opencew from ase.calculators.calculator import kpts2mp from ase.io import Trajectory from ase.calculators.abinit import Abinit from ase.test.tasks.dcdft import DeltaCodesDFTCollection as Collection c = ase.db.connect('dcdft_abinit_fhi.db') ecut = 120 kptdensity = 16.0 width = 0.01 linspace = (0.98, 1.02, 5) # eos numpy's linspace linspacestr = ''.join([str(t) + 'x' for t in linspace])[:-1] code = 'abinit' + '-' + '_c' + str(ecut) + '_e' + linspacestr code = code + '_k' + str(kptdensity) + '_w' + str(width) collection = Collection() for name in collection.names: # save all steps in one traj file in addition to the database # we should only used the database c.reserve, but here # traj file is used as another lock ... fd = opencew(name + '_' + code + '.traj') if fd is None: continue traj = Trajectory(name + '_' + code + '.traj', 'w') atoms = collection[name] if name == 'Mn': # fails to find the right magnetic state atoms.set_initial_magnetic_moments([10., 20., -10., -20.]) if name == 'Co': # fails to find the right magnetic state atoms.set_initial_magnetic_moments([10., 10.]) if name == 'Ni': # fails to find the right magnetic state atoms.set_initial_magnetic_moments([10., 10., 10., 10.]) cell = atoms.get_cell() kpts = tuple(kpts2mp(atoms, kptdensity, even=True)) kwargs = {} # loop over EOS linspace for n, x in enumerate(np.linspace(linspace[0], linspace[1], linspace[2])): id = c.reserve(name=name, ecut=ecut, linspacestr=linspacestr, kptdensity=kptdensity, width=width, x=x) if id is None: continue # perform EOS step atoms.set_cell(cell * x, scale_atoms=True) # set calculator atoms.calc = Abinit( label=name + '_' + code + '_' + str(n), xc='PBE', kpts=kpts, ecut=ecut*Rydberg, occopt=3, tsmear=width, toldfe=1.0e-6, nstep=900, diemix=0.1, fband=0.95, # http://forum.abinit.org/viewtopic.php?f=8&t=35 chksymbreak=0, nsym=1, # various symmetry problems with various abinits ... ) atoms.calc.set(**kwargs) # remaining calc keywords t = time.time() atoms.get_potential_energy() c.write(atoms, name=name, ecut=ecut, linspacestr=linspacestr, kptdensity=kptdensity, width=width, x=x, time=time.time()-t) traj.write(atoms) wfk = name + '_' + code + '_' + str(n) + 'o_WFK' if os.path.exists(wfk): os.remove(wfk) del c[id] gpaw-0.11.0.13004/gpaw/test/big/dcdft/pbe_aims.agts.py0000664000175000017500000000041612553643471022306 0ustar jensjjensj00000000000000# Note: due to how agts works external executables (abinit, aims, etc.) # must be run on the submission platform (bmaster1), currently opteron4 def agts(queue): queue.add('pbe_aims.py Al', ncpus=1, queueopts='-l nodes=1:ppn=4:opteron4', walltime=3*40) gpaw-0.11.0.13004/gpaw/test/big/dcdft/pbe_abinit_hgh.agts.py0000664000175000017500000000042512553643471023451 0ustar jensjjensj00000000000000# Note: due to how agts works external executables (abinit, aims, etc.) # must be run on the submission platform (bmaster1), currently opteron4 def agts(queue): queue.add('pbe_abinit_hgh.py Al', ncpus=1, queueopts='-l nodes=1:ppn=4:opteron4', walltime=10*60) gpaw-0.11.0.13004/gpaw/test/big/dcdft/__init__.py0000664000175000017500000000000012553643471021316 0ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/big/setups/0000775000175000017500000000000012553644063017454 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/big/setups/__init__.py0000664000175000017500000000000012553643471021555 0ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/big/__init__.py0000664000175000017500000000000012553643471020232 0ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/test/multipoletest.py0000664000175000017500000000244712553643471020665 0ustar jensjjensj00000000000000from __future__ import print_function from math import sqrt, pi import numpy as np from gpaw.setup import create_setup from gpaw.grid_descriptor import GridDescriptor from gpaw.localized_functions import create_localized_functions from gpaw.xc import XC n = 60#40 /8 * 10 a = 10.0 gd = GridDescriptor((n, n, n), (a, a, a)) c_LL = np.identity(9, float) a_Lg = gd.zeros(9) nspins = 2 xc = XC('LDA') for soft in [False]: s = create_setup('Cu', xc, lmax=2) ghat_l = s.ghat_l ghat_Lg = create_localized_functions(ghat_l, gd, (0.54321, 0.5432, 0.543)) a_Lg[:] = 0.0 ghat_Lg.add(a_Lg, c_LL) for l in range(3): for m in range(2 * l + 1): L = l**2 + m a_g = a_Lg[L] Q0 = gd.integrate(a_g) / sqrt(4 * pi) Q1_m = -gd.calculate_dipole_moment(a_g) / sqrt(4 * pi / 3) print(Q0) if l == 0: Q0 -= 1.0 Q1_m[:] = 0.0 elif l == 1: Q1_m[(m + 1) % 3] -= 1.0 print(soft, l, m, Q0, Q1_m) assert abs(Q0) < 2e-6 assert np.alltrue(abs(Q1_m) < 3e-5) b_Lg = np.reshape(a_Lg, (9, -1)) S_LL = np.inner(b_Lg, b_Lg) gd.comm.sum(S_LL) S_LL.ravel()[::10] = 0.0 print(max(abs(S_LL).ravel())) assert max(abs(S_LL).ravel()) < 3e-4 gpaw-0.11.0.13004/gpaw/test/h2o_xas_recursion.py0000664000175000017500000000223212553643471021377 0ustar jensjjensj00000000000000from __future__ import print_function from math import pi, cos, sin from ase import Atom, Atoms from gpaw import GPAW, PoissonSolver from gpaw.test import equal, gen # Generate setup for oxygen with half a core-hole: gen('O', name='hch1s', corehole=(1, 0, 0.5)) if 1: a = 5.0 d = 0.9575 t = pi / 180 * 104.51 H2O = Atoms([Atom('O', (0, 0, 0)), Atom('H', (d, 0, 0)), Atom('H', (d * cos(t), d * sin(t), 0))], cell=(a, a, a), pbc=False) H2O.center() calc = GPAW(nbands=10, h=0.2, setups={'O': 'hch1s'}, poissonsolver=PoissonSolver(use_charge_center=True)) H2O.set_calculator(calc) e = H2O.get_potential_energy() niter = calc.get_number_of_iterations() calc.write('h2o.gpw') else: calc = GPAW('h2o.gpw', poissonsolver=PoissonSolver(use_charge_center=True)) calc.initialize_positions() from gpaw.xas import RecursionMethod if 1: r = RecursionMethod(calc) r.run(400) r.write('h2o.pckl') else: r = RecursionMethod(filename='h2o.pckl') print(e, niter) energy_tolerance = 0.0002 niter_tolerance = 0 equal(e, -17.9772, energy_tolerance) gpaw-0.11.0.13004/gpaw/test/rpa_energy_Ni.py0000664000175000017500000000143312553643471020526 0ustar jensjjensj00000000000000from ase.lattice import bulk from gpaw import GPAW, FermiDirac from gpaw.mpi import serial_comm from gpaw.test import equal from gpaw.xc.rpa import RPACorrelation from gpaw.xc.fxc import FXCCorrelation a0 = 5.43 Ni = bulk('Ni', 'fcc') Ni.set_initial_magnetic_moments([0.7]) calc = GPAW(mode='pw', kpts=(3, 3, 3), occupations=FermiDirac(0.001), setups={'Ni': '10'}, communicator=serial_comm) Ni.set_calculator(calc) E = Ni.get_potential_energy() calc.diagonalize_full_hamiltonian(nbands=50) rpa = RPACorrelation(calc, nfrequencies=8, skip_gamma=True) E_rpa = rpa.calculate(ecut=[50]) fxc = FXCCorrelation(calc, nlambda=16, nfrequencies=8, skip_gamma=True) E_fxc = fxc.calculate(ecut=[50]) equal(E_rpa, -7.826, 0.01) equal(E_fxc, -7.826, 0.01) gpaw-0.11.0.13004/gpaw/test/non_periodic.py0000664000175000017500000000107512553643471020417 0ustar jensjjensj00000000000000from gpaw.transformers import Transformer import numpy.random as ra from gpaw.grid_descriptor import GridDescriptor p = 0 n = 20 gd1 = GridDescriptor((n, n, n), (8.0, 8.0, 8.0), pbc_c=p) a1 = gd1.zeros() ra.seed(8) a1[:] = ra.random(a1.shape) gd2 = gd1.refine() a2 = gd2.zeros() i = Transformer(gd1, gd2).apply i(a1, a2) assert abs(gd1.integrate(a1) - gd2.integrate(a2)) < 1e-10 r = Transformer(gd2, gd1).apply a2[0] = 0.0 a2[:, 0] = 0.0 a2[:, :, 0] = 0.0 a2[-1] = 0.0 a2[:, -1] = 0.0 a2[:, :, -1] = 0.0 r(a2, a1) assert abs(gd1.integrate(a1) - gd2.integrate(a2)) < 1e-10 gpaw-0.11.0.13004/gpaw/test/atoms_too_close.py0000664000175000017500000000051512553643472021137 0ustar jensjjensj00000000000000from ase import Atoms from gpaw import GPAW atoms = Atoms('H2', [(0.0, 0.0, 0.0), (0.0, 0.0, 3.995)], cell=(4, 4, 4), pbc=True) calc = GPAW(txt=None) atoms.set_calculator(calc) calc.initialize(atoms) try: calc.set_positions(atoms) except RuntimeError: pass else: assert 2 + 2 == 5 gpaw-0.11.0.13004/gpaw/test/apmb.py0000664000175000017500000000461012553643471016664 0ustar jensjjensj00000000000000from __future__ import print_function from ase import Atom, Atoms from ase.parallel import parprint from gpaw.test import equal from gpaw import GPAW, mpi from gpaw.lrtddft import LrTDDFT import numpy #numpy.seterr(all='raise') txt='-' txt='/dev/null' load = False #load = True if not load: R=0.7 # approx. experimental bond length a = 3 c = 4 H2 = Atoms([Atom('H', (a/2,a/2,(c-R)/2)), Atom('H', (a/2,a/2,(c+R)/2))], cell=(a,a,c)) calc = GPAW(xc='PBE', nbands=2, spinpol=False, txt=txt) H2.set_calculator(calc) H2.get_potential_energy() ## calc.write('H2.gpw', 'all') else: calc = GPAW('H2.gpw', txt=txt) #calc.initialize_wave_functions() #----------------------------------------------------------- # DFT only xc='LDA' # no spin lr = LrTDDFT(calc, xc=xc) lr.diagonalize() lr_ApmB = LrTDDFT(calc, xc=xc, force_ApmB=True) lr_ApmB.diagonalize() parprint('lr=', lr) parprint('ApmB=', lr_ApmB) equal(lr[0].get_energy(), lr_ApmB[0].get_energy(), 5.e-10) # with spin parprint('------ with spin') if not load: c_spin = GPAW(xc='PBE', nbands=2, spinpol=True, parallel={'domain': mpi.world.size}, txt=txt) H2.set_calculator(c_spin) c_spin.calculate(H2) ## c_spin.write('H2spin.gpw', 'all') else: c_spin = GPAW('H2spin.gpw', txt=txt) lr = LrTDDFT(c_spin, xc=xc) lr.diagonalize() lr_ApmB = LrTDDFT(c_spin, xc=xc, force_ApmB=True) lr_ApmB.diagonalize() parprint('lr=', lr) parprint('ApmB=', lr_ApmB) equal(lr[0].get_energy(), lr_ApmB[0].get_energy(), 5.e-10) equal(lr[1].get_energy(), lr_ApmB[1].get_energy(), 5.e-10) # with spin virtual parprint('------ with virtual spin') lr = LrTDDFT(calc, xc=xc, nspins=2) lr.diagonalize() # ApmB lr_ApmB = LrTDDFT(calc, xc=xc, nspins=2) lr_ApmB.diagonalize() parprint('lr=', lr) parprint('ApmB=', lr_ApmB) equal(lr[0].get_energy(), lr_ApmB[0].get_energy(), 5.e-10) equal(lr[1].get_energy(), lr_ApmB[1].get_energy(), 5.e-10) #------------------------------------------------------- # with HF exchange xc='PBE0' parprint('------ with spin xc=', xc) lr_spin = LrTDDFT(c_spin, xc=xc) lr_spin.diagonalize() parprint('lr=', lr_spin) parprint('------ with virtual spin xc=', xc) lr = LrTDDFT(calc, xc=xc, nspins=2) lr.diagonalize() parprint('lr=', lr) equal(lr[0].get_energy(), lr_spin[0].get_energy(), 3.8e-6) equal(lr[1].get_energy(), lr_spin[1].get_energy(), 3.4e-6) gpaw-0.11.0.13004/gpaw/test/lcao_bsse.py0000664000175000017500000000335412553643471017703 0ustar jensjjensj00000000000000from __future__ import print_function from ase.structure import molecule from gpaw import GPAW from gpaw.poisson import PoissonSolver from gpaw.atom.basis import BasisMaker from gpaw.test import equal # Tests basis set super position error correction # Compares a single hydrogen atom to a system of one hydrogen atom # and one ghost hydrogen atom. The systems should have identical properties, # i.e. the ghost orbital should have a coefficient of 0. b = BasisMaker('H').generate(1, 0, energysplit=0.005) system = molecule('H2') system.center(vacuum=6.0) def prepare(setups): calc = GPAW(basis={'H' : b}, mode='lcao', setups=setups, h=0.2, poissonsolver=PoissonSolver('M', relax='GS', eps=1e-5), spinpol=False, nbands=1) system.set_calculator(calc) return calc calc = prepare({0 : 'paw', 1 : 'ghost'}) system.set_calculator(calc) e_bsse = system.get_potential_energy() niter_bsse = calc.get_number_of_iterations() c_nM = calc.wfs.kpt_u[0].C_nM print('coefs') print(c_nM) print('energy', e_bsse) # Reference system which is just a hydrogen sys0 = system[0:1].copy() calc = prepare('paw') sys0.set_calculator(calc) e0 = sys0.get_potential_energy() niter0 = calc.get_number_of_iterations() print('e0, e_bsse = ', e0, e_bsse) # One coefficient should be very small (0.012), the other very large (0.99) assert abs(1.0 - abs(c_nM[0, 0])) < 0.02 assert abs(c_nM[0, 1]) < 0.02 assert abs(e_bsse - e0) < 2e-3 energy_tolerance = 0.0002 niter_tolerance = 1 equal(e_bsse, 0.0287208853911, energy_tolerance) # svnversion 5252 equal(niter_bsse, 7, niter_tolerance) # svnversion 5252 equal(e0, 0.0299220702846, energy_tolerance) # svnversion 5252 equal(niter0, 6, niter_tolerance) # svnversion 5252 gpaw-0.11.0.13004/gpaw/test/asym_box.py0000664000175000017500000000174712553643472017577 0ustar jensjjensj00000000000000"""Check for change in total energy and lowest eigenvalue regarding to box.""" from ase import Atoms from ase.parallel import parprint from gpaw import GPAW, PoissonSolver from gpaw.cluster import Cluster from gpaw.test import equal h = 0.2 s = Cluster(Atoms('He')) s.minimal_box(3, h=h) c = GPAW(charge=1, txt='He_plus.txt', poissonsolver=PoissonSolver(use_charge_center=True), convergence={ # run fast 'energy': 0.001, 'eigenstates': 1e-4, 'density': 1e-3}) s.set_calculator(c) e_small = s.get_potential_energy() eps_small = c.get_eigenvalues()[0] cell = s.get_cell() cell[0] *= 2 s.set_cell(cell) e_big = s.get_potential_energy() eps_big = c.get_eigenvalues()[0] parprint('Energies and Eigenvalues:') parprint(' Small Box Wide Box') parprint('E: {0:9.3f} {1:9.3f}'.format(e_small, e_big)) parprint('eps: {0:9.3f} {1:9.3f}'.format(eps_small, eps_big)) equal(e_small, e_big, 2.5e-4) equal(eps_small, eps_big, 6e-4) gpaw-0.11.0.13004/gpaw/test/bse_silicon.py0000664000175000017500000000311712553643471020237 0ustar jensjjensj00000000000000from __future__ import print_function import os import numpy as np from ase import Atom, Atoms from ase.lattice import bulk from ase.units import Hartree, Bohr from gpaw import GPAW, FermiDirac from gpaw.response.bse import BSE from ase.dft.kpoints import monkhorst_pack from gpaw.mpi import rank GS = 1 bse = 1 check = 1 if GS: kpts = (4,4,4) a = 5.431 # From PRB 73,045112 (2006) atoms = bulk('Si', 'diamond', a=a) calc = GPAW(h=0.2, kpts=kpts, occupations=FermiDirac(0.001), nbands=12, convergence={'bands':-4}) atoms.set_calculator(calc) atoms.get_potential_energy() calc.write('Si.gpw','all') if bse: eshift = 0.8 bse = BSE('Si.gpw', w=np.linspace(0,10,201), q=np.array([0.0001, 0, 0.0]), optical_limit=True, ecut=50., nc=np.array([4,6]), nv=np.array([2,4]), eshift=eshift, nbands=8) bse.get_dielectric_function('Si_bse.dat') if rank == 0 and os.path.isfile('phi_qaGp'): os.remove('phi_qaGp') if check: d = np.loadtxt('Si_bse.dat') Nw1 = 64 Nw2 = 77 if d[Nw1, 2] > d[Nw1-1, 2] and d[Nw1, 2] > d[Nw1+1, 2] \ and d[Nw2, 2] > d[Nw2-1, 2] and d[Nw2, 2] > d[Nw2+1, 2]: pass else: raise ValueError('Absorption peak not correct ! ') if np.abs(d[Nw1, 2] - 53.3382894891) > 1. \ or np.abs(d[Nw2, 2] - 62.7667801949 ) > 2.: print(d[Nw1, 2], d[Nw2, 2]) raise ValueError('Please check spectrum strength ! ') gpaw-0.11.0.13004/gpaw/test/ut_common.py0000664000175000017500000001673312553643472017757 0ustar jensjjensj00000000000000"""Common code base for maintaining backwards compatibility in ut_xxx tests.""" __all__ = ['ase_svnversion', 'shapeopt', 'TestCase', 'TextTestRunner', \ 'CustomTextTestRunner', 'defaultTestLoader', 'initialTestLoader', \ 'create_random_atoms', 'create_parsize_maxbands', 'create_parsize_minbands'] partest = True # ------------------------------------------------------------------- # Maintain backwards compatibility with ASE 3.1.0 svn. rev. 1158 or later try: from ase.svnversion import svnversion as ase_svnversion except ImportError: # Fall back on minimum required ASE svn.rev. ase_svnversion = 1158 else: # From test/ase3k_version.py. full_ase_svnversion = ase_svnversion if ase_svnversion[-1] == 'M': ase_svnversion = ase_svnversion[:-1] if ase_svnversion.rfind(':') != -1: ase_svnversion = ase_svnversion[:ase_svnversion.rfind(':')] ase_svnversion = int(ase_svnversion) def shapegen(size, ndims, ecc=0.5): """Return a generator of an N-dimensional array shape which approximately contains a given number of elements. size: int or long in [1,inf[ The total number of elements ndims=3: int in [1,inf[ The number of dimensions ecc=0.5: float in ]0,1[ The eccentricity of the distribution """ assert type(size) in [int,float] and size>=1 assert isinstance(ndims, int) and ndims>=1 assert type(ecc) in [int,float] and ecc>0 and ecc<1 for i in range(ndims-1): scale = size**(1.0/(ndims-i)) c = round(np.random.uniform((1-ecc)*scale, 1.0/(1-ecc)*scale)) size/=c yield c yield round(size) def shapeopt(maxseed, size, ndims, ecc=0.5): """Return optimal estimate of an N-dimensional array shape which is closest to containing a given number of elements. maxseed: int in [1,inf[ The maximal number of seeds to try size: int or long in [1,inf[ The total number of elements ndims=3: int in [1,inf[ The number of dimensions ecc=0.5: float in ]0,1[ The eccentricity of the distribution """ assert isinstance(maxseed, int) and maxseed>=1 assert type(size) in [int,float] and size>=1 assert isinstance(ndims, int) and ndims>=1 assert type(ecc) in [int,float] and ecc>0 and ecc<1 digits_best = np.inf shape_best = None for seed in range(maxseed): np.random.seed(seed) shape = tuple(shapegen(size, ndims, ecc)) if np.prod(shape) == size: return -np.inf, shape digits = np.log10(abs(np.prod(shape)-size)) if digits < digits_best: (digits_best, shape_best) = (digits, shape) return digits_best, shape_best if partest: from gpaw.test.parunittest import ParallelTestCase as TestCase, \ ParallelTextTestRunner as TextTestRunner, ParallelTextTestRunner as \ CustomTextTestRunner, defaultParallelTestLoader as defaultTestLoader def CustomTextTestRunner(logname, verbosity=1): return TextTestRunner(stream=logname, verbosity=verbosity) else: # Using a features from ASE 3.1.0 svn. rev. 929 or later. from ase.test import CustomTestCase as TestCase, CustomTextTestRunner from unittest import TextTestRunner, defaultTestLoader from copy import copy initialTestLoader = copy(defaultTestLoader) assert hasattr(initialTestLoader, 'testMethodPrefix') initialTestLoader.testMethodPrefix = 'verify' # ------------------------------------------------------------------- import numpy as np from math import sin, cos from ase import Atoms from ase.structure import molecule from ase.units import Bohr from gpaw.mpi import synchronize_atoms, world from gpaw.utilities.tools import md5_array def create_random_atoms(gd, nmolecules=10, name='NH2', mindist=4.5 / Bohr): """Create gas-like collection of atoms from randomly placed molecules. Applies rigid motions to molecules, translating the COM and/or rotating by a given angle around an axis of rotation through the new COM. These atomic positions obey the minimum distance requirement to zero-boundaries. Warning: This is only intended for testing parallel grid/LFC consistency. """ atoms = Atoms(cell=gd.cell_cv * Bohr, pbc=gd.pbc_c) # Store the original state of the random number generator randstate = np.random.get_state() seed = np.array([md5_array(data, numeric=True) for data in [nmolecules, gd.cell_cv, gd.pbc_c, gd.N_c]]).astype(int) #np.random.seed(seed % 4294967296) np.random.seed(seed % 1073741824) for m in range(nmolecules): amol = molecule(name) amol.set_cell(gd.cell_cv * Bohr) # Rotate the molecule around COM according to three random angles # The rotation axis is given by spherical angles phi and theta v,phi,theta = np.random.uniform(0.0, 2*np.pi, 3) # theta [0,pi[ really axis = np.array([cos(phi)*sin(theta), sin(phi)*sin(theta), cos(theta)]) amol.rotate(axis, v) # Find the scaled length we must transverse along the given axes such # that the resulting displacement vector is `mindist` from the cell # face corresponding to that direction (plane with unit normal n_v). sdist_c = np.empty(3) if not gd.orthogonal: for c in range(3): n_v = gd.xxxiucell_cv[c] / np.linalg.norm(gd.xxxiucell_cv[c]) sdist_c[c] = mindist / np.dot(gd.cell_cv[c], n_v) else: sdist_c[:] = mindist / gd.cell_cv.diagonal() assert np.all(sdist_c > 0), 'Displacment vectors must be inside cell.' # Scaled dimensions of the smallest possible box centered on the COM spos_ac = amol.get_scaled_positions() # NB! must not do a "% 1.0" scom_c = np.dot(gd.icell_cv, amol.get_center_of_mass()) sbox_c = np.abs(spos_ac-scom_c[np.newaxis,:]).max(axis=0) sdelta_c = (1-np.array(gd.pbc_c)) * (sbox_c + sdist_c) assert (sdelta_c < 1.0-sdelta_c).all(), 'Box is too tight to fit atoms.' scenter_c = [np.random.uniform(d,1-d) for d in sdelta_c] center_v = np.dot(scenter_c, gd.cell_cv) # Translate the molecule such that COM is located at random center offset_av = (center_v-amol.get_center_of_mass()/Bohr)[np.newaxis,:] amol.set_positions(amol.get_positions()+offset_av*Bohr) assert np.linalg.norm(center_v-amol.get_center_of_mass()/Bohr) < 1e-9 atoms.extend(amol) # Restore the original state of the random number generator np.random.set_state(randstate) synchronize_atoms(atoms, world) return atoms # ------------------------------------------------------------------- from fractions import gcd from gpaw import parsize_domain, parsize_bands def create_parsize_maxbands(nbands, world_size): """Safely parse command line parallel arguments for band parallel case.""" # D: number of domains # B: number of band groups if parsize_bands is None: if parsize_domain is None: B = gcd(nbands, world_size) # largest possible D = world_size // B else: D = parsize_domain B = gcd(nbands, world_size // np.prod(D)) else: B = parsize_bands D = parsize_domain or world_size // B return D, B def create_parsize_minbands(nbands, world_size): __doc__ = create_parsize_maxbands.__doc__ return create_parsize_maxbands(1, world_size) gpaw-0.11.0.13004/gpaw/test/h2o_dks.py0000664000175000017500000000262212553643472017300 0ustar jensjjensj00000000000000from __future__ import print_function from ase.structure import molecule from gpaw import GPAW, FermiDirac, PoissonSolver from gpaw.test import equal, gen # Generate setup for oxygen with a core-hole: gen('O', name='fch1s', xcname='PBE', corehole=(1, 0, 1.0)) atoms = molecule('H2O') atoms.center(vacuum=2.5) calc = GPAW(xc='PBE', poissonsolver=PoissonSolver(use_charge_center=True)) atoms.set_calculator(calc) e1 = atoms.get_potential_energy() + calc.get_reference_energy() niter1 = calc.get_number_of_iterations() atoms[0].magmom = 1 calc.set(charge=-1, setups={'O': 'fch1s'}, occupations=FermiDirac(0.0, fixmagmom=True)) e2 = atoms.get_potential_energy() + calc.get_reference_energy() niter2 = calc.get_number_of_iterations() atoms[0].magmom = 0 calc.set(charge=0, setups={'O': 'fch1s'}, occupations=FermiDirac(0.0, fixmagmom=True), spinpol=True) e3 = atoms.get_potential_energy() + calc.get_reference_energy() niter3 = calc.get_number_of_iterations() print('Energy difference %.3f eV' % (e2 - e1)) print('XPS %.3f eV' % (e3 - e1)) print(e2 - e1) print(e3 - e1) assert abs(e2 - e1 - 533.070) < 0.001 assert abs(e3 - e1 - 538.549) < 0.001 energy_tolerance = 0.0002 niter_tolerance = 1 print(e1, niter1) print(e2, niter2) print(e3, niter3) equal(e1, -2080.3715465, energy_tolerance) equal(e2, -1547.30157798, energy_tolerance) equal(e3, -1541.82252385, energy_tolerance) gpaw-0.11.0.13004/gpaw/io/0000775000175000017500000000000012553644063015020 5ustar jensjjensj00000000000000gpaw-0.11.0.13004/gpaw/io/tar.py0000664000175000017500000002021312553643472016161 0ustar jensjjensj00000000000000import numbers import os import tarfile import time import xml.sax import numpy as np from gpaw.io import FileReference from gpaw.mpi import broadcast as mpi_broadcast from gpaw.mpi import world intsize = 4 floatsize = np.array([1], float).itemsize complexsize = np.array([1], complex).itemsize itemsizes = {'int': intsize, 'float': floatsize, 'complex': complexsize} class Writer: def __init__(self, name, comm=world): self.comm = comm # for possible future use self.dims = {} self.files = {} self.xml1 = ['' % ('big', 'little')[int(np.little_endian)]] self.xml2 = [] if os.path.isfile(name): os.rename(name, name[:-4] + '.old' + name[-4:]) self.tar = tarfile.open(name, 'w') self.mtime = int(time.time()) def dimension(self, name, value): if name in self.dims.keys() and self.dims[name] != value: raise Warning('Dimension %s changed from %s to %s' % (name, self.dims[name], value)) self.dims[name] = value def __setitem__(self, name, value): if isinstance(value, float): value = repr(value) self.xml1 += [' ' % ('name="%s"' % name, value)] def add(self, name, shape, array=None, dtype=None, units=None, parallel=False, write=True): if array is not None: array = np.asarray(array) self.dtype, type, itemsize = self.get_data_type(array, dtype) self.xml2 += [' ' % (name, type)] self.xml2 += [' ' % (self.dims[dim], dim) for dim in shape] self.xml2 += [' '] self.shape = [self.dims[dim] for dim in shape] size = itemsize * int(np.product([self.dims[dim] for dim in shape])) self.write_header(name, size) if array is not None: self.fill(array) def get_data_type(self, array=None, dtype=None): if dtype is None: dtype = array.dtype if dtype in [int, bool]: dtype = np.int32 dtype = np.dtype(dtype) type = {np.int32: 'int', np.float64: 'float', np.complex128: 'complex'}[dtype.type] return dtype, type, dtype.itemsize def fill(self, array, *indices, **kwargs): self.write(np.asarray(array, self.dtype).tostring()) def write_header(self, name, size): assert name not in self.files.keys(), name tarinfo = tarfile.TarInfo(name) tarinfo.mtime = self.mtime tarinfo.size = size self.files[name] = tarinfo self.size = size self.n = 0 self.tar.addfile(tarinfo) def write(self, string): self.tar.fileobj.write(string) self.n += len(string) if self.n == self.size: blocks, remainder = divmod(self.size, tarfile.BLOCKSIZE) if remainder > 0: self.tar.fileobj.write(b'\0' * (tarfile.BLOCKSIZE - remainder)) blocks += 1 self.tar.offset += blocks * tarfile.BLOCKSIZE def close(self): self.xml2 += ['\n'] string = '\n'.join(self.xml1 + self.xml2).encode() self.write_header('info.xml', len(string)) self.write(string) self.tar.close() class Reader(xml.sax.handler.ContentHandler): def __init__(self, name, comm=world): self.comm = comm # used for broadcasting replicated data self.master = (self.comm.rank == 0) self.dims = {} self.shapes = {} self.dtypes = {} self.parameters = {} xml.sax.handler.ContentHandler.__init__(self) self.tar = tarfile.open(name, 'r') f = self.tar.extractfile('info.xml') xml.sax.parse(f, self) def startElement(self, tag, attrs): if tag == 'gpaw_io': self.byteswap = ((attrs['endianness'] == 'little') != np.little_endian) elif tag == 'array': name = attrs['name'] self.dtypes[name] = attrs['type'] self.shapes[name] = [] self.name = name elif tag == 'dimension': n = int(attrs['length']) self.shapes[self.name].append(n) self.dims[attrs['name']] = n else: assert tag == 'parameter' try: value = eval(attrs['value'], {}) except (SyntaxError, NameError): value = str(attrs['value']) self.parameters[attrs['name']] = value def dimension(self, name): return self.dims[name] def __getitem__(self, name): return self.parameters[name] def has_array(self, name): return name in self.shapes def get(self, name, *indices, **kwargs): broadcast = kwargs.pop('broadcast', False) if self.master or not broadcast: fileobj, shape, size, dtype = self.get_file_object(name, indices) array = np.fromstring(fileobj.read(size), dtype) if self.byteswap: array = array.byteswap() if dtype == np.int32: array = np.asarray(array, int) array.shape = shape if shape == (): array = array.item() else: array = None if broadcast: array = mpi_broadcast(array, 0, self.comm) return array def get_reference(self, name, indices, length=None): fileobj, shape, size, dtype = self.get_file_object(name, indices) assert dtype != np.int32 return TarFileReference(fileobj, shape, dtype, self.byteswap, length) def get_file_object(self, name, indices): dtype, type, itemsize = self.get_data_type(name) fileobj = self.tar.extractfile(name) n = len(indices) shape = self.shapes[name] size = itemsize * np.prod(shape[n:], dtype=int) offset = 0 stride = size for i in range(n - 1, -1, -1): offset += indices[i] * stride stride *= shape[i] fileobj.seek(offset) return fileobj, shape[n:], size, dtype def get_data_type(self, name): type = self.dtypes[name] dtype = np.dtype({'int': np.int32, 'float': float, 'complex': complex}[type]) return dtype, type, dtype.itemsize def get_parameters(self): return self.parameters def close(self): self.tar.close() class TarFileReference(FileReference): def __init__(self, fileobj, shape, dtype, byteswap, length): self.fileobj = fileobj self.shape = tuple(shape) self.dtype = dtype self.itemsize = dtype.itemsize self.byteswap = byteswap self.offset = fileobj.tell() self.length = length def __len__(self): return self.shape[0] def __getitem__(self, indices): if isinstance(indices, slice): start, stop, step = indices.indices(len(self)) if start != 0 or step != 1 or stop != len(self): raise NotImplementedError('You can only slice a TarReference ' 'with [:] or [int]') else: indices = () elif isinstance(indices, numbers.Integral): indices = (indices,) else: # Probably tuple or ellipsis raise NotImplementedError('You can only slice a TarReference ' 'with [:] or [int]') n = len(indices) size = np.prod(self.shape[n:], dtype=int) * self.itemsize offset = self.offset stride = size for i in range(n - 1, -1, -1): offset += indices[i] * stride stride *= self.shape[i] self.fileobj.seek(offset) array = np.fromstring(self.fileobj.read(size), self.dtype) if self.byteswap: array = array.byteswap() array.shape = self.shape[n:] if self.length: array = array[..., :self.length].copy() return array gpaw-0.11.0.13004/gpaw/io/fmf.py0000664000175000017500000000476412553643472016160 0ustar jensjjensj00000000000000import os import platform import time from gpaw.version import version class FMF: """Full-Metadata Format Full-Metadata Format after http://www.sir.uni-freiburg.de/repository/2009/SI20090302a/SI20090302a.pdf""" def __init__(self, title='-', creator=None, place=None, escape='#'): self.escape = escape self.estimate_creator(creator) self.title = title self.place = place def header(self): ec = self.escape header = ec + '; -*- fmf version: 1.0 -*-\n' header += ec + '[*reference]\n' header += ec + 'creator: ' + self.creator + '\n' header += ec + 'created: ' + time.strftime('%Y-%m-%d %H:%M') + '\n' title = self.title if isinstance(title, str): title = title.split('\n') for i, line in enumerate(title): if i == 0: header += ec + 'title: ' else: header += ec + ' ' header += line + '\n' header += ec + 'gpaw-version: ' + version + '\n' try: import socket header += ec + 'hostname: ' + socket.gethostname() + '\n' except: pass header += ec + 'architecture: ' + platform.uname()[4] + '\n' return header def data(self, definitions): ec = self.escape data = ec + '[* data definitions]\n' for definition in definitions: data += ec + definition + '\n' data += ec + '[* data]\n' return data def field(self, title, entries): ec = self.escape res = ec + '[' + title + ']\n' for entry in entries: res += ec + entry + '\n' return res def estimate_creator(self, creator=None): if creator is not None: self.creator = creator return try: # get import getpass username = getpass.getuser() try: import pwd gecos = pwd.getpwnam(username).pw_gecos hasalpha = False for letter in gecos: if letter.isalpha(): hasalpha = True if hasalpha: creator = gecos else: creator = username except: creator = username except: creator = 'unknown' self.creator = creator gpaw-0.11.0.13004/gpaw/io/cc1.py0000664000175000017500000000136412553643472016047 0ustar jensjjensj00000000000000from math import pi, cos, sin, sqrt, acos import numpy as np from ase.atoms import Atoms from ase.parallel import paropen def read_cc1(fileobj, index=-1): """Read Chem3D(CC1) format""" if isinstance(fileobj, str): fileobj = open(fileobj) lines = fileobj.readlines() L1 = lines[0].split() del lines[0] natoms = int(L1[0]) images = [] while len(lines) > 0: positions = [] symbols = [] for line in lines[:natoms]: symbol, number, x, y, z = line.split()[:5] symbols.append(symbol) positions.append([float(x), float(y), float(z)]) images.append(Atoms(symbols=symbols, positions=positions)) del lines[:natoms + 1] return images[index] gpaw-0.11.0.13004/gpaw/io/netcdf.py0000664000175000017500000000365512553643472016651 0ustar jensjjensj00000000000000import numpy as np from ase.io.pupynere import NetCDFFile class Reader: def __init__(self, filename, comm): self.nc = NetCDFFile(filename) def dimension(self, name): return self.nc.dimensions[name] def __getitem__(self, name): value = getattr(self.nc, name) if isinstance(value, str): try: value = eval(value) except (SyntaxError, NameError): pass return value else: return value[0] def has_array(self, name): return name in self.nc.variables def get(self, name, *indices): var = self.nc.variables[name] if var.shape == (): return var.getValue() else: if var.dimensions[-1] == 'two': x = var[indices] array = np.empty(x.shape[:-1], complex) array.real = x[..., 0] array.imag = x[..., 1] return array else: return var[indices] def get_reference(self, name, indices): return NetCDFReference(self.nc.variables[name], indices) def close(self): self.nc.close() class NetCDFReference: def __init__(self, var, indices): self.var = var self.indices = indices self.cmplx = (var.dimensions[-1] == 'two') n = len(indices) if self.cmplx: self.shape = var.shape[n:-1] else: self.shape = var.shape[n:] def __len__(self): return self.shape[0] def __getitem__(self, indices): if not isinstance(indices, tuple): indices = (indices,) if self.cmplx: x = self.var[self.indices + indices] array = np.empty(x.shape[:-1], complex) array.real = x[..., 0] array.imag = x[..., 1] return array else: return self.var[self.indices + indices] gpaw-0.11.0.13004/gpaw/io/dummy.py0000664000175000017500000000121512553643472016527 0ustar jensjjensj00000000000000from gpaw.mpi import world class DummyWriter: def __init__(self, name, comm=world): self.comm = comm # for possible future use self.master = (self.comm == 0) # Only master does meaningful I/O if self.master: raise RuntimeError('Dummy writer should not have master!') def dimension(self, name, value): pass def __setitem__(self, name, value): pass def add(self, name, shape, array=None, dtype=None, units=None, parallel=False, write=True): pass def fill(self, array, *indices, **kwargs): pass def close(self): pass gpaw-0.11.0.13004/gpaw/io/etsf.py0000664000175000017500000001445512553643472016347 0ustar jensjjensj00000000000000import numpy as np from ase.units import Hartree from Scientific.IO.NetCDF import NetCDFFile from ase.lattice.spacegroup import Spacegroup from gpaw.wavefunctions.pw import PWDescriptor class ETSFWriter: def __init__(self, filename='gpaw', title='gpaw'): if not filename.endswith('-etsf.nc'): if filename.endswith('.nc'): filename = filename[:-3] + '-etsf.nc' else: filename = filename + '-etsf.nc' self.nc = NetCDFFile(filename, 'w') self.nc.file_format = 'ETSF Nanoquanta' self.nc.file_format_version = np.array([3.3], dtype=np.float32) self.nc.Conventions = 'http://www.etsf.eu/fileformats/' self.nc.history = 'File generated by GPAW' self.nc.title = title def write(self, calc, spacegroup=1): #sg = Spacegroup(spacegroup) #print sg wfs = calc.wfs setups = wfs.setups bd = wfs.bd kd = wfs.kd atoms = calc.atoms natoms = len(atoms) if wfs.kd.symmetry is None: op_scc = np.eye(3, dtype=int).reshape((1, 3, 3)) else: op_scc = wfs.kd.symmetry.op_scc specie_a = np.empty(natoms, np.int32) nspecies = 0 species = {} names = [] symbols = [] numbers = [] charges = [] for a, id in enumerate(setups.id_a): if id not in species: species[id] = nspecies nspecies += 1 names.append(setups[a].symbol) symbols.append(setups[a].symbol) numbers.append(setups[a].Z) charges.append(setups[a].Nv) specie_a[a] = species[id] dimensions = [ ('character_string_length', 80), ('max_number_of_states', bd.nbands), ('number_of_atoms', len(atoms)), ('number_of_atom_species', nspecies), ('number_of_cartesian_directions', 3), ('number_of_components', 1), ('number_of_kpoints', kd.nibzkpts), ('number_of_reduced_dimensions', 3), ('number_of_spinor_components', 1), ('number_of_spins', wfs.nspins), ('number_of_symmetry_operations', len(op_scc)), ('number_of_vectors', 3), ('real_or_complex_coefficients', 2), ('symbol_length', 2)] for name, size in dimensions: print(('%-34s %d' % (name, size))) self.nc.createDimension(name, size) var = self.add_variable var('space_group', (), np.array(spacegroup, dtype=int)) var('primitive_vectors', ('number_of_vectors', 'number_of_cartesian_directions'), wfs.gd.cell_cv, units='atomic units') var('reduced_symmetry_matrices', ('number_of_symmetry_operations', 'number_of_reduced_dimensions', 'number_of_reduced_dimensions'), op_scc.astype(np.int32), symmorphic='yes') var('reduced_symmetry_translations', ('number_of_symmetry_operations', 'number_of_reduced_dimensions'), np.zeros((len(op_scc), 3), dtype=np.int32)) var('atom_species', ('number_of_atoms',), specie_a + 1) var('reduced_atom_positions', ('number_of_atoms', 'number_of_reduced_dimensions'), atoms.get_scaled_positions()) var('atomic_numbers', ('number_of_atom_species',), np.array(numbers, dtype=float)) var('valence_charges', ('number_of_atom_species',), np.array(charges, dtype=float)) var('atom_species_names', ('number_of_atom_species', 'character_string_length'), names) var('chemical_symbols', ('number_of_atom_species', 'symbol_length'), symbols) var('pseudopotential_types', ('number_of_atom_species', 'character_string_length'), ['HGH'] * nspecies) var('fermi_energy', (), calc.occupations.fermilevel, units='atomic units') var('smearing_scheme', ('character_string_length',), 'fermi-dirac') var('smearing_width', (), calc.occupations.width, units='atomic units') var('number_of_states', ('number_of_spins', 'number_of_kpoints'), np.zeros((wfs.nspins, kd.nibzkpts), np.int32) + bd.nbands, k_dependent='no') var('eigenvalues', ('number_of_spins', 'number_of_kpoints', 'max_number_of_states'), np.array([[calc.get_eigenvalues(k, s) / Hartree for k in range(kd.nibzkpts)] for s in range(wfs.nspins)]), units='atomic units') var('occupations', ('number_of_spins', 'number_of_kpoints', 'max_number_of_states'), np.array([[calc.get_occupation_numbers(k, s) / kd.weight_k[k] for k in range(kd.nibzkpts)] for s in range(wfs.nspins)])) var('reduced_coordinates_of_kpoints', ('number_of_kpoints', 'number_of_reduced_dimensions'), kd.ibzk_kc) var('kpoint_weights', ('number_of_kpoints',), kd.weight_k) var('basis_set', ('character_string_length',), 'plane_waves') var('number_of_electrons', (), np.array(wfs.nvalence, dtype=np.int32)) self.nc.close() def add_variable(self, name, dims, data=None, **kwargs): if data is None: char = 'd' else: if isinstance(data, np.ndarray): char = data.dtype.char elif isinstance(data, float): char = 'd' elif isinstance(data, int): char = 'i' else: char = 'c' print(('%-34s %s%s' % ( name, char, tuple([self.nc.dimensions[dim] for dim in dims])))) var = self.nc.createVariable(name, char, dims) for attr, value in kwargs.items(): setattr(var, attr, value) if data is not None: if len(dims) == 0: var.assignValue(data) else: if char == 'c': if len(dims) == 1: var[:len(data)] = data else: for i, x in enumerate(data): var[i, :len(x)] = x else: var[:] = data return var gpaw-0.11.0.13004/gpaw/io/hdf5.py0000664000175000017500000001500312553643472016222 0ustar jensjjensj00000000000000import os import time from gpaw.io.hdf5_highlevel import File, HyperslabSelection from gpaw.io import FileReference import numpy as np intsize = 4 floatsize = np.array([1], float).itemsize complexsize = np.array([1], complex).itemsize itemsizes = {'int': intsize, 'float': floatsize, 'complex': complexsize} class Writer: def __init__(self, name, comm=None): self.comm = comm # for possible future use self.dims = {} try: if self.comm.rank == 0: if os.path.isfile(name): os.rename(name, name[:-5] + '.old' + name[-5:]) self.comm.barrier() except AttributeError: if os.path.isfile(name): os.rename(name, name[:-5] + '.old' + name[-5:]) if self.comm.size > 1: comm = self.comm.get_c_object() else: comm = None self.file = File(name, 'w', comm) self.dims_grp = self.file.create_group("Dimensions") self.params_grp = self.file.create_group("Parameters") self.file.attrs['title'] = 'gpaw_io version="0.1"' self.hdf5 = True def dimension(self, name, value): if name in self.dims.keys() and self.dims[name] != value: raise Warning('Dimension %s changed from %s to %s' % (name, self.dims[name], value)) self.dims[name] = value self.dims_grp.attrs[name] = value def __setitem__(self, name, value): # attributes must be written collectively self.params_grp.attrs[name] = value def add(self, name, shape, array=None, dtype=None, parallel=False, write=True): if array is not None: array = np.asarray(array) # self.dtype, type, itemsize = self.get_data_type(array, dtype) if dtype is None: self.dtype = array.dtype else: self.dtype = dtype shape = [self.dims[dim] for dim in shape] if not shape: shape = [1] self.dset = self.file.create_dataset(name, shape, self.dtype) if array is not None: self.fill(array, parallel=parallel, write=write) def fill(self, array, *indices, **kwargs): parallel = kwargs.pop('parallel', False) write = kwargs.pop('write', True) if parallel: collective = True else: collective = False if not write: selection = None elif indices: selection = HyperslabSelection(indices, self.dset.shape) else: selection = 'all' self.dset.write(array, selection, collective) def get_data_type(self, array=None, dtype=None): if dtype is None: dtype = array.dtype if dtype in [int, bool]: dtype = np.int32 dtype = np.dtype(dtype) type = {np.int32: 'int', np.float64: 'float', np.complex128: 'complex'}[dtype.type] return dtype, type, dtype.itemsize def append(self, name): raise NotImplementedError('Append with HDF5 not available.') def close(self): mtime = int(time.time()) self.file.attrs['mtime'] = mtime self.dims_grp.close() self.params_grp.close() self.dset.close() self.file.close() class Reader: def __init__(self, name, comm): self.comm = comm # used for broadcasting replicated data if self.comm.size > 1: comm = self.comm.get_c_object() else: comm = None self.file = File(name, 'r', comm) self.dims_grp = self.file['Dimensions'] self.params_grp = self.file['Parameters'] self.hdf5 = True def dimension(self, name): value = self.dims_grp.attrs[name] return value def __getitem__(self, name): value = self.params_grp.attrs[name] try: value = eval(value, {}) except (SyntaxError, NameError, TypeError): pass return value def has_array(self, name): return name in self.file.keys() def get(self, name, *indices, **kwargs): parallel = kwargs.pop('parallel', False) read = kwargs.pop('read', True) out = kwargs.pop('out', None) broadcast = kwargs.pop('broadcast', False) assert not kwargs if parallel: collective = True else: collective = False dset = self.file[name] if indices: selection = HyperslabSelection(indices, dset.shape) mshape = selection.mshape else: selection = 'all' mshape = dset.shape if not read: selection = None real2complex = False if out is None: array = np.ndarray(mshape, dset.dtype, order='C') elif out.dtype == complex and dset.dtype == float: # For real to complex reading i.e TDDFT temporary buffer # is also needed array = np.ndarray(mshape, dset.dtype, order='C') real2complex = True else: assert isinstance(out, np.ndarray) # XXX Check the shapes are compatible assert out.shape == mshape assert (out.dtype == dset.dtype or (out.dtype == complex and dset.dtype == float)) array = out dset.read(array, selection, collective) if real2complex: out[:] = array[:] array = out if broadcast: self.comm.broadcast(array, 0) if array.shape == (): return array.item() else: return array def get_reference(self, name, indices, length=None): return HDF5FileReference(self.file, name, indices, length) def get_parameters(self): return self.params_grp.attrs def close(self): self.file.close() class HDF5FileReference(FileReference): def __init__(self, file, name, indices, length): self.file = file self.name = name self.dset = self.file[name] self.dtype = self.dset.dtype self.shape = self.dset.shape self.indices = indices self.length = length def __len__(self): """Length of the first dimension""" return self.shape[0] def __getitem__(self, indices): if not isinstance(indices, tuple): indices = (indices,) ind = self.indices + indices if self.length: return self.dset[ind][..., :self.length].copy() else: return self.dset[ind] gpaw-0.11.0.13004/gpaw/io/cmr_io.py0000664000175000017500000002166712553643472016661 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. import os import time import xml.sax import numpy as np import ase from ase.version import version as ase_version import gpaw from gpaw.version import version_base as gpaw_version try: #new style cmr io import cmr from cmr.base.converter import Converter from cmr.io import Flags from cmr.tools.functions import create_db_filename as cdbfn from cmr.definitions import CALCULATOR_GPAW def get_reader(name): reader = cmr.read(name, mode=Flags.READ_MODE_ORIGINAL_TYPE) return reader def get_writer(): return Converter.get_xml_writer(CALCULATOR_GPAW, calculator_version=gpaw_version) def create_db_filename(param, ext=".db"): return cdbfn(param, ext=ext) except: #old style cmr io import cmr from cmr import create_db_filename as cdbfn from cmr.io import XMLData from cmr.io import READ_DATA from cmr.io import EVALUATE from cmr.io import WRITE_CONVERT from cmr.io import CONVERTION_ORIGINAL from cmr.static import CALCULATOR_GPAW def create_db_filename(param, ext="ignored"): return cdbfn() def get_reader(name): reader = cmr.read(name, read_mode=READ_DATA, evaluation_mode=EVALUATE, convertion_mode=CONVERTION_ORIGINAL) return reader def get_writer(): data = XMLData() data.set_calculator_name(CALCULATOR_GPAW) data.set_write_mode(WRITE_CONVERT) return data class Writer: """ This class is a wrapper to the db output writer and intended to be used with gpaw """ def __init__(self, filename, comm=None): self.comm = comm # for possible future use self.verbose = False self.data = get_writer() self.split_array = None #used when array is not filled at once self.dimensions = {} self.filename = filename self.cmr_params = {} uname = os.uname() self.data['user']=os.getenv('USER', '???') self.data['date']=time.asctime() self.data['architecture']=uname[4] self.data['ase_dir']=os.path.dirname(ase.__file__) self.data['ase_version']=ase_version self.data['numpy_dir']=os.path.dirname(np.__file__) self.data['gpaw_dir']=os.path.dirname(gpaw.__file__) self.data["db_calculator_version"] = gpaw_version self.data['calculator']="gpaw" self.data['location']=uname[1] def dimension(self, name, value): self.dimensions[name]=value self.data[name]=value if self.verbose: print("dimension: ", name, value) def __setitem__(self, name, value): """ sets the value of a variable in the db-file. Note that only values that were defined in the cmr-schema are written. (User defined values have to be added with set_user_variable(name, value) IMPORTANT: CMR does not support None values for numbers, therefore all variables with value None are ignored.""" if self.verbose: print("name value:", name, value) if name == "GridSpacing" and value == "None": return if not value is None: self.data[name]=value def _get_dimension(self, array): """retrieves the dimension of a multidimensional array by using then len() function until fail """ indent = "" measured_dimensions = [] while True: try: measured_dimensions.append(len(array)) if self.verbose: print(indent+"Length:", len(array)) indent += " " array = array[0] except IndexError: break except TypeError: break return measured_dimensions def _close_array(self): """if an array is filled with fill then we don't know the exact end of the array. Therefore we check before adding a new variable if the end was reached.""" if self.split_array is None: return measured_dimensions = self._get_dimension(self.split_array[2]) if self.verbose: print("Dimensions: ", self.split_array[1]) print("Mesured Dimensions: ", measured_dimensions) #make the array fit (only fixes the 1st dimension) res = np.array(self.split_array[2]).reshape(self.split_array[1]) self.data[self.split_array[0]] = res def add(self, name, shape, array=None, dtype=None, units=None, parallel=False, write=True): self._close_array() if self.verbose: print("add:", name, shape, array, dtype, units) if array is None: dimension = [] for a in shape: dimension.append(self.dimensions[a]) self.split_array = (name, dimension, []) else: self.data[name]=array def fill(self, array, *indices, **kwargs): if self.verbose: print("fill (", len(array),"):", array) self.split_array[2].append(array) def set_db_copy_settings(self, make_db_copy, private): """deprecated: This method is going to be removed""" print("Warning: gpaw.cmr.readwriter.set_db_copy_settings is deprecated.") print("Please update gpaw and CMR") pass #if self.verbose: # print "set_db_copy_settings", make_db_copy, private #self.db_copy=make_db_copy #self.private=private #self.data.set_db_copy_settings(make_db_copy, private) def write(self, string, db, private, **kwargs): print("Warning: gpaw.cmr.readwriter.write is deprecated.") print("Please update gpaw and CMR") pass #if self.verbose: # print "write():", string #self.data.write(string, db, private, **kwargs) def write_additional_db_params(self, cmr_params): """writes the user variables and also sets the write attributes for the output file""" self.cmr_params = cmr_params.copy() #cmr.set_params_to_xml_data(self.data, cmr_params) def close(self): if self.verbose: print("close()") self._close_array() if "ase_atoms_var" in self.cmr_params: ase_vars = self.cmr_params["ase_atoms_var"] for key in ase_vars: self.data.set_user_variable(key, ase_vars[key]) self.cmr_params.pop("ase_atoms_var") if self.filename==".db" or self.filename==".cmr": # Note: # .cmr files can currently not be uploaded to the database therefore # it defaults to .db until supported self.cmr_params["output"]=create_db_filename(self.data, ext=".db") else: self.cmr_params["output"]=self.filename try: cmr.runtime.pause_ase_barriers(True) self.data.write(self.cmr_params, ase_barrier=False) except TypeError: # for compatibility with older CMR versions: self.data.write(self.cmr_params) cmr.runtime.pause_ase_barriers(False) return [self.data.get_hash()] class Reader: """ This class allows gpaw to access to read a db-file """ def __init__(self, name, comm): self.verbose = False self.reader = self.parameters = get_reader(name) def dimension(self, name): return self.reader[name] def __getitem__(self, name): if name=='version' and 'version' not in self.reader \ and 'db_calculator_version' in self.reader: return self.reader['db_calculator_version'] return self.reader[name] def has_array(self, name): return name in self.reader def get(self, name, *indices, **kwargs): if self.verbose: print("incides", indices) result = self.reader[name] if indices!=(): for a in indices: result = result[a] return result #gpaw wants expressions evaluated if isinstance(result, str) or isinstance(result, unicode): try: if self.verbose: print("Converting ", result) result = eval(result, {}) except (SyntaxError, NameError): pass return result def get_reference(self, name, indices, length=None): result = self.reader[name] if indices!=(): for a in indices: result = result[a] return result def get_file_object(self, name, indices): result = self.reader.retrieve_file(name) if indices!=(): for a in indices: result = result[a] return result def get_parameters(self): return self.reader.keys() def close(self): pass gpaw-0.11.0.13004/gpaw/io/hdf5_highlevel.py0000664000175000017500000003461112553643472020257 0ustar jensjjensj00000000000000"""Light weight Python interface to HDF5""" # Copyright (C) 2010-2011 CSC - IT Center for Science Ltd. # Please see the accompanying LICENSE file for further information. # The module is heavily inspired by h5py, however, no # h5py code is used directly except where explicitly noted import numpy as np from _gpaw_hdf5 import * def numpy_type_from_h5(datatype): """Simple conversion from HDF5 datatype to NumPy dtype""" cls = h5t_get_class(datatype) if cls == H5T_INTEGER: dtype = int elif cls == H5T_FLOAT: dtype = float elif cls == H5T_COMPOUND: dtype = complex elif cls == H5T_ENUM: dtype = bool elif cls == H5T_STRING: str_size = h5t_get_size(datatype) dtype = np.dtype('|S' + str(str_size)) else: raise RuntimeError('Unsupported HDF5 datatype') return dtype class Iterator: """Iterator over the datasets and subgroups in a File or in a Group.""" def __init__(self, obj): self.idx = 0 self.obj = obj self.nobj = obj.get_num_objs() def __iter__(self): return self def __next__(self): if self.idx == self.nobj: self.obj = None raise StopIteration key = self.obj.get_name_by_idx(self.idx) self.idx += 1 return key next = __next__ # for Python 2 class Group: """This class defines a HDF5 group.""" def __init__(self, loc_id, name, create=False): if create: self.id = h5g_create(loc_id, name) else: self.id = h5g_open(loc_id, name) self.attrs = Attributes(self.id) self.name = name self.opened = True def create_group(self, name): return Group(self.id, name, create=True) def create_dataset(self, name, shape, dtype): """Create a dataset with the NumPy equivalent type and shape. Arguments: ---------- dtype : Python or NumPy type shape : tuple containing the shape of dataset """ return Dataset(self.id, name, dtype, shape, create=True) def get_num_objs(self): return h5g_get_num_objs(self.id) def get_name_by_idx(self, idx): return h5l_get_name_by_idx(self.id, idx) def close(self): h5g_close(self.id) self.opened = False # Dictionary like interface def keys(self): return list(self) def values(self): return [self[x] for x in self.keys()] def items(self): return [(x, self[x]) for x in self.keys()] def __getitem__(self, key): oid = h5o_open(self.id, key) obj_type = h5i_get_type(oid) h5o_close(oid) if obj_type == H5I_GROUP: return Group(self.id, key) elif obj_type == H5I_DATASET: return Dataset(self.id, key) else: # This shoul never happen raise RuntimeError('Accessing unknown object type') def __iter__(self): return Iterator(self) def __len__(self): return self.get_num_objs() def __del__(self): if self.opened: self.close() class File(Group): """This class defines a HDF5 file.""" def __init__(self, name, mode='r', comm=None): """If a communicator is passed as an argument, file is created or opened for parallel IO.""" if comm is None: plist = H5P_DEFAULT else: plist = h5p_create(H5P_FILE_ACCESS) h5p_set_fapl_mpio(plist, comm) if mode == 'r': self.id = h5f_open(name, mode, plist) elif mode == 'w': self.id = h5f_create(name, plist) else: raise RuntimeError('Unsupported file open/create mode') self.attrs = Attributes(self.id) if comm is not None: h5p_close(plist) self.name = name self.opened = True def close(self): h5f_close(self.id) self.opened = False class Dataset(object): """This class defines a HDF5 dataset. Attributes: ============= ============================================= Name Description ============= ============================================= ``shape`` Tuple describing the dataspace of dataset ``dtype`` NumPy equivalent datatype of dataset ``dataspace`` HDF5 dataspace identifier (integer) ``datatype`` HDF5 datatype identifier (integer) ``id`` HDF5 identifier of dataset (integer) ============= ============================================= """ def __init__(self, loc_id, name, dtype=None, shape=None, create=False): if create: self.shape = shape self.dtype = dtype self.dataspace = h5s_create(np.asarray(shape)) self.datatype = h5_type_from_numpy(np.ndarray((1,), dtype)) self.id = h5d_create(loc_id, name, self.datatype, self.dataspace) else: self.id = h5d_open(loc_id, name) self.dataspace = h5d_get_space(self.id) self.datatype = h5d_get_type(self.id) self.shape = h5s_get_shape(self.dataspace) self.dtype = numpy_type_from_h5(self.datatype) self.attrs = Attributes(self.id) self.name = name self.opened = True def write(self, data, selection='all', collective=False): """Write NumPy array data into the dataset. selection can be a hyperslab instance for writing to a part of the dataset or None for no reading collective specifies the use of collective IO.""" if collective: plist = h5p_create(H5P_DATASET_XFER) h5p_set_dxpl_mpio(plist) else: plist = H5P_DEFAULT filespace = self.dataspace memspace = h5s_create(np.asarray(data.shape)) memtype = h5_type_from_numpy(np.ndarray((1,), data.dtype)) if selection is None: h5s_select_none(memspace) h5s_select_none(filespace) if isinstance(selection, HyperslabSelection): selection.select(self) # data array has to be contiguous, if not make a copy if not data.flags.contiguous: data = data.copy() h5d_write(self.id, memtype, memspace, filespace, data, plist) h5s_close(memspace) h5t_close(memtype) if collective: h5p_close(plist) def read(self, data, selection='all', collective=False): """Read the dataset into NumPy array data selection can be a hyperslab instance for reading part of the dataset or None for no reading collective specifies the use of collective IO.""" if collective: plist = h5p_create(H5P_DATASET_XFER) h5p_set_dxpl_mpio(plist) else: plist = H5P_DEFAULT filespace = self.dataspace memspace = h5s_create(np.asarray(data.shape)) memtype = h5_type_from_numpy(np.ndarray((1,), data.dtype)) if selection is None: h5s_select_none(memspace) h5s_select_none(filespace) if isinstance(selection, HyperslabSelection): selection.select(self) # data array has to be contiguous, if not, create a # temporary array if not data.flags.contiguous: data_buf = data.copy() else: data_buf = data h5d_read(self.id, memtype, memspace, filespace, data_buf, plist) if not data.flags.contiguous: data[:] = data_buf[:] h5s_close(memspace) h5t_close(memtype) if collective: h5p_close(plist) # Interface for access with slicing syntax def __setitem__(self, indices, value): sel = HyperslabSelection(indices, self.shape) if not isinstance(value, np.ndarray): value = np.asarray(value) if sel.mshape != value.shape: raise RuntimeError('Shapes not compatible') self.write(value, selection=sel) def __getitem__(self, indices): sel = HyperslabSelection(indices, self.shape) array = np.zeros(sel.mshape, self.dtype) self.read(array, sel) return array def close(self): h5t_close(self.datatype) h5s_close(self.dataspace) h5d_close(self.id) self.opened = False def __del__(self): if self.opened: self.close() class Attributes: """A dictionary like interface to HDF5 attributes. Attributes can be written with the:: attrs['name'] = value and read with the:: value = attrs['name'] syntax. Values are returned always as NumPy arrays. """ def __init__(self, parent_id): self.loc_id = parent_id def __setitem__(self, key, data): # Should we delete existing attributes? # Special treatment for possible None data if data is None: data = repr(data) data = np.asarray(data) dataspace = h5s_create(np.asarray(data.shape)) datatype = h5_type_from_numpy(np.ndarray((1, ), data.dtype)) id = h5a_create(self.loc_id, key, datatype, dataspace) # ensure that data is contiguous data = data.copy() h5a_write(id, datatype, data) h5s_close(dataspace) h5t_close(datatype) h5a_close(id) def __getitem__(self, key): id = h5a_open(self.loc_id, key) dataspace = h5a_get_space(id) datatype = h5a_get_type(id) shape = h5s_get_shape(dataspace) dtype = numpy_type_from_h5(datatype) memtype = h5_type_from_numpy(np.ndarray((1,), dtype)) data = np.empty(shape, dtype) h5a_read(id, memtype, data) h5s_close(dataspace) h5t_close(datatype) h5t_close(memtype) h5a_close(id) if len(shape) == 0: data = np.asscalar(data) return data def __contains__(self, name): return h5a_exists_by_name(self.loc_id, name) # The following four functions # _expand_ellipsis, _translate_int, _translate_slice and _handle_simple # are direct copy-paste from h5py # Copyright (C) 2008 Andrew Collette # http://h5py.alfven.org # License: New BSD def _expand_ellipsis(args, rank): """ Expand ellipsis objects and fill in missing axes. """ n_el = sum(1 for arg in args if arg is Ellipsis) if n_el > 1: raise ValueError("Only one ellipsis may be used.") elif n_el == 0 and len(args) != rank: args = args + (Ellipsis,) final_args = [] n_args = len(args) for idx, arg in enumerate(args): if arg is Ellipsis: final_args.extend( (slice(None,None,None),)*(rank-n_args+1) ) else: final_args.append(arg) if len(final_args) > rank: raise TypeError("Argument sequence too long") return final_args def _translate_int(exp, length): """ Given an integer index, return a 3-tuple (start, count, step) for hyperslab selection """ if exp < 0: exp = length+exp if not 0<=exp= 1 (got %d)" % step) if stop == start: raise ValueError("Zero-length selections are not allowed") if stop < start: raise ValueError("Reverse-order selections are not allowed") if start < 0: start = length+start if stop < 0: stop = length+stop if not 0 <= start <= (length-1): raise ValueError("Start index %s out of range (0-%d)" % (start, length-1)) if not 1 <= stop <= length: raise ValueError("Stop index %s out of range (1-%d)" % (stop, length)) count = (stop-start)//step if (stop-start) % step != 0: count += 1 if start+count > length: raise ValueError("Selection out of bounds (%d; axis has %d)" % (start+count,length)) return start, count, step def _handle_simple(shape, args): """ Process a "simple" selection tuple, containing only slices and integer objects. Return is a 4-tuple with tuples for start, count, step, and a flag which tells if the axis is a "scalar" selection (indexed by an integer). If "args" is shorter than "shape", the remaining axes are fully selected. """ args = _expand_ellipsis(args, len(shape)) start = [] count = [] step = [] scalar = [] for arg, length in zip(args, shape): if isinstance(arg, slice): x,y,z = _translate_slice(arg, length) s = False else: try: x,y,z = _translate_int(int(arg), length) s = True except TypeError: raise TypeError('Illegal index "%s" (must be a slice or number)' % arg) start.append(x) count.append(y) step.append(z) scalar.append(s) return tuple(start), tuple(count), tuple(step), tuple(scalar) class HyperslabSelection: """This class defines a simple hyperslab selection for a HDF5 dataspace. In HDF5, hyperslab is defined by offset, stride, count, and block arguments, in the Python side simple indeces or slices are used (start, stop, step). The block argument of HDF5 is not used here. """ def __init__(self, indices, shape): """Create a hyperslab descriptor.""" if not isinstance(indices, tuple): indices = (indices,) dest_shape = shape self.indices = indices start, count, step, scalar = _handle_simple(dest_shape, indices) # This class follows HDF5 convention offset, stride, count self.hyperslab = (np.array(start), np.array(step), np.array(count)) self.mshape = tuple(x for x, y in zip(count, scalar) if not y) def select(self, dataset): """Make the actual hyperslab selection to the dataspace of dataset.""" dataspace = dataset.dataspace offset, stride, count = self.hyperslab h5s_select_hyperslab(dataspace, offset, stride, count, None) gpaw-0.11.0.13004/gpaw/io/tarext.py0000664000175000017500000001302312553643472016703 0ustar jensjjensj00000000000000 import numpy as np from gpaw.io.tar import Writer, Reader class IncrementalWriter(Writer): _iterkey = 'niter' _partkey = 'part' _iterpattern = '/%06d.part' def __init__(self, name): Writer.__init__(self, name) self.dims[self._iterkey] = 0 self.dims[self._partkey] = 1 self.partitions = {} self.xml3 = [] def partition(self, name, shape, array=None, dtype=None, units=None): if array is not None: array = np.asarray(array) self.dtype, type, itemsize = self.get_data_type(array, dtype) assert self._partkey not in shape shape = (self._partkey,) + shape if name not in self.partitions.keys(): self.xml3 += [' ' % (name, type)] self.xml3 += [' ' % (self.dims[dim], dim) for dim in shape] self.xml3 += [' '] self.partitions[name] = shape self.shape = [self.dims[dim] for dim in shape] else: assert self.partitions[name] == shape size = itemsize * np.product([self.dims[dim] for dim in shape]) name += self._iterpattern % self.dims[self._iterkey] self.write_header(name, size) if array is not None: self.fill(array) def __next__(self): self.dims[self._iterkey] += self.dims[self._partkey] next = __next__ # for Python 2 def close(self): partdim = ' ' % \ (self.dims[self._partkey], self._partkey) iterdim = ' ' % \ (self.dims[self._iterkey], self._iterkey) while partdim in self.xml3: i = self.xml3.index(partdim) self.xml3[i] = iterdim self.xml2 += self.xml3 self.xml3 = [] Writer.close(self) # ------------------------------------------------------------------- class _FakeFileObject(object): def __init__(self, fileparts, partsize): self.fileparts = fileparts self.partsize = partsize self.fileobj = None for fileobj in self.fileparts: assert fileobj.size == partsize self.seek(0) def seek(self, pos, whence=0): self.part, partpos = divmod(pos, self.partsize) self.fileobj = self.fileparts[self.part] self.fileobj.seek(partpos, whence) def tell(self): return self.fileobj.tell() + self.part*self.partsize def read(self, size=None): self.part, partpos = divmod(self.tell(), self.partsize) buf = str() n = self.tell() # read some of initial part partrem = min(self.partsize - partpos, size) buf += self.fileobj.read(partrem) n += partrem # read whole parts while size - n > self.partsize: self.seek(n) buf += self.fileobj.read(self.partsize) n += self.partsize # read some of final part self.seek(n) rem = size - n buf += self.fileobj.read(rem) return buf def close(self): for fileobj in self.fileparts: fileobj.close() class IncrementalReader(Reader): _iterkey = 'niter' _partkey = 'part' _iterpattern = '/%06d.part' def __init__(self, name): self.partitions = {} Reader.__init__(self, name) self.dims[self._partkey] = 1 def startElement(self, tag, attrs): if tag == 'partition': name = attrs['name'] assert name not in self.partitions.keys() self.dtypes[name] = attrs['type'] self.shapes[name] = [] self.name = name self.partitions[name] = tuple() else: if tag == 'dimension' and self.name in self.partitions.keys(): if attrs['name'] == self._iterkey: self.partitions[self.name] += (self._partkey,) else: self.partitions[self.name] += (attrs['name'],) Reader.startElement(self, tag, attrs) def get_file_object(self, name, indices): if name in self.partitions.keys(): # The first index is the partition iterable if len(indices) == 0: return self.get_partition_object(name) i, indices = indices[0], indices[1:] partshape = [self.dims[dim] for dim in self.partitions[name]] name += self._iterpattern % i self.shapes[name] = partshape[1:] #HACK return Reader.get_file_object(self, name, indices) def get_data_type(self, name): if name not in self.dtypes.keys(): try: name, partname = name.rsplit('/',1) except ValueError: raise KeyError(name) assert name in self.partitions.keys() return Reader.get_data_type(self, name) def get_partition_object(self, name): assert name in self.partitions.keys() dtype, type, itemsize = self.get_data_type(name) shape = self.shapes[name] size = itemsize * np.prod(shape, dtype=int) partshape = [self.dims[dim] for dim in self.partitions[name]] partsize = itemsize * np.prod(partshape, dtype=int) fileobjs = [] for i in range(self.dims[self._iterkey]): fileobj = self.tar.extractfile(name + self._iterpattern % i) fileobjs.append(fileobj) return _FakeFileObject(fileobjs, partsize), shape, size, dtype gpaw-0.11.0.13004/gpaw/io/__init__.py0000664000175000017500000007403412553643472017144 0ustar jensjjensj00000000000000"""GPAW I/O Change log for version: 1) Initial version. 2) GridPoints array added when gpts is used. 3) Different k-points now have different number of plane-waves. Added PlaneWaveIndices array. 4) Removed "UseSymmetry" and added "Symmetry" switches. 5) Added "ForcesConvergenceCriterion". """ import os import warnings from ase.units import AUT from ase.units import Bohr, Hartree from ase.data import atomic_names from ase.atoms import Atoms import numpy as np import gpaw.mpi as mpi from gpaw.io.dummy import DummyWriter def open(filename, mode='r', comm=mpi.world): parallel_io = False if filename.endswith('.nc'): import gpaw.io.netcdf as io elif filename.endswith('.db') or filename.endswith('.cmr'): import gpaw.io.cmr_io as io elif filename.endswith('.hdf5'): import gpaw.io.hdf5 as io parallel_io = True else: if not filename.endswith('.gpw'): filename += '.gpw' import gpaw.io.tar as io # comm is used to eliminate replicated reads, hence it should never be None # it is not required for writes at the moment, but this is likely to change # in the future if mode == 'r': if comm is None: raise RuntimeError('Warning: Communicator needed for reads/writes') return io.Reader(filename, comm) elif mode == 'w': if parallel_io or comm.rank == 0: return io.Writer(filename, comm) else: return DummyWriter(filename, comm) else: raise ValueError("Illegal mode! Use 'r' or 'w'.") def write_atomic_matrix(writer, X_asp, name, master): all_X_asp = X_asp.deepcopy() all_X_asp.redistribute(all_X_asp.partition.as_serial()) writer.add(name, ('nspins', 'nadm'), dtype=float) if master: writer.fill(all_X_asp.toarray(axis=1)) def wave_function_name_template(mode): try: ftype, template = mode.split(':') except: ftype = mode template = 'wfs/psit_Gs%dk%dn%d' return ftype, template def write(paw, filename, mode, cmr_params=None, **kwargs): """Write state to file. The `mode` argument should be one of: ``''``: Don't write the wave functions. ``'all'``: Write also the wave functions to the file. ``'nc'`` or ``'gpw'``: Write wave functions as separate files (the default filenames are ``'psit_Gs%dk%dn%d.nc' % (s, k, n)`` for ``'nc'``, where ``s``, ``k`` and ``n`` are spin, **k**-point and band indices). XXX ``'nc:mywfs/psit_Gs%dk%dn%d'``: Defines the filenames to be ``'mywfs/psit_Gs%dk%dn%d' % (s, k, n)``. The directory ``mywfs`` is created if not present. XXX cmr_params specifies the parameters that should be used for CMR. (Computational Materials Repository) Please note: mode argument is ignored by CMR. """ timer = paw.timer timer.start('Write') wfs = paw.wfs scf = paw.scf density = paw.density hamiltonian = paw.hamiltonian world = paw.wfs.world domain_comm = wfs.gd.comm kpt_comm = wfs.kd.comm band_comm = wfs.band_comm master = (world.rank == 0) parallel = (world.size > 1) atoms = paw.atoms natoms = len(atoms) magmom_a = paw.get_magnetic_moments() hdf5 = filename.endswith('.hdf5') # defaults for replicated writes with HDF5 timer.start('Meta data') # Note that HDF5 and GPW-writers behave very differently here. # - real GPW-writer is created only on the master task, other # tasks use dummy writer # - HDF5 writer is created on all MPI tasks. # - GPW-writer always writes from master # - HDF-writer writes full distributed data from all task, replicated data # from master, and partially replicated-data from domain_comm.rank == 0. # These types of writes are call Datasets. # - HDF-writer writes parameters and dimensions as Attributes, not # Datasets. # Attributes must be written by all MPI tasks. w = open(filename, 'w', world) w['history'] = 'GPAW restart file' w['version'] = 5 w['lengthunit'] = 'Bohr' w['energyunit'] = 'Hartree' try: tag_a = atoms.get_tags() if tag_a is None: raise KeyError except KeyError: tag_a = np.zeros(natoms, int) w.dimension('natoms', natoms) w.dimension('3', 3) w.add('AtomicNumbers', ('natoms',), atoms.get_atomic_numbers(), write=master) w.add('CartesianPositions', ('natoms', '3'), atoms.get_positions() / Bohr, write=master) w.add('MagneticMoments', ('natoms',), magmom_a, write=master) w.add('Tags', ('natoms',), tag_a, write=master) w.add('BoundaryConditions', ('3',), atoms.get_pbc(), write=master) w.add('UnitCell', ('3', '3'), atoms.get_cell() / Bohr, write=master) if atoms.get_velocities() is not None: w.add('CartesianVelocities', ('natoms', '3'), atoms.get_velocities() * AUT / Bohr, write=master) w.add('PotentialEnergy', (), hamiltonian.Etot + 0.5 * hamiltonian.S, write=master) if paw.forces.F_av is not None: w.add('CartesianForces', ('natoms', '3'), paw.forces.F_av, write=master) # Write the k-points: if wfs.kd.N_c is not None: w.add('NBZKPoints', ('3'), wfs.kd.N_c, write=master) w.add('MonkhorstPackOffset', ('3'), wfs.kd.offset_c, write=master) w.dimension('nbzkpts', len(wfs.kd.bzk_kc)) w.dimension('nibzkpts', len(wfs.kd.ibzk_kc)) w.add('BZKPoints', ('nbzkpts', '3'), wfs.kd.bzk_kc, write=master) w.add('IBZKPoints', ('nibzkpts', '3'), wfs.kd.ibzk_kc, write=master) w.add('IBZKPointWeights', ('nibzkpts',), wfs.kd.weight_k, write=master) # Create dimensions for varioius netCDF variables: ng = wfs.gd.get_size_of_global_array() w.dimension('ngptsx', ng[0]) w.dimension('ngptsy', ng[1]) w.dimension('ngptsz', ng[2]) ng = density.finegd.get_size_of_global_array() w.dimension('nfinegptsx', ng[0]) w.dimension('nfinegptsy', ng[1]) w.dimension('nfinegptsz', ng[2]) w.dimension('nspins', wfs.nspins) w.dimension('nbands', wfs.bd.nbands) nproj = sum([setup.ni for setup in wfs.setups]) nadm = sum([setup.ni * (setup.ni + 1) // 2 for setup in wfs.setups]) w.dimension('nproj', nproj) w.dimension('nadm', nadm) if wfs.dtype == float: w['DataType'] = 'Float' else: w['DataType'] = 'Complex' p = paw.input_parameters if p.gpts is not None: w.add('GridPoints', ('3'), p.gpts, write=master) if p.h is None: w['GridSpacing'] = repr(None) else: w['GridSpacing'] = p.h / Bohr # Write various parameters: (w['KohnShamStencil'], w['InterpolationStencil']) = p['stencils'] w['PoissonStencil'] = paw.hamiltonian.poisson.get_stencil() w['XCFunctional'] = paw.hamiltonian.xc.name w['Charge'] = p['charge'] w['FixMagneticMoment'] = paw.occupations.fixmagmom w['SymmetryOnSwitch'] = wfs.kd.symmetry.point_group w['SymmetrySymmorphicSwitch'] = wfs.kd.symmetry.symmorphic w['SymmetryTimeReversalSwitch'] = wfs.kd.symmetry.time_reversal w['SymmetryToleranceCriterion'] = wfs.kd.symmetry.tol w['Converged'] = scf.converged w['FermiWidth'] = paw.occupations.width w['MixClass'] = density.mixer.__class__.__name__ w['MixBeta'] = density.mixer.beta w['MixOld'] = density.mixer.nmaxold w['MixWeight'] = density.mixer.weight w['MaximumAngularMomentum'] = p.lmax w['SoftGauss'] = False w['FixDensity'] = p.fixdensity w['DensityConvergenceCriterion'] = p.convergence['density'] w['EnergyConvergenceCriterion'] = p.convergence['energy'] / Hartree w['EigenstatesConvergenceCriterion'] = p.convergence['eigenstates'] w['NumberOfBandsToConverge'] = p.convergence['bands'] if p.convergence['forces'] is not None: force_unit = (Hartree / Bohr) w['ForcesConvergenceCriterion'] = p.convergence['forces'] / force_unit else: w['ForcesConvergenceCriterion'] = None w['Ekin'] = hamiltonian.Ekin w['Epot'] = hamiltonian.Epot w['Ebar'] = hamiltonian.Ebar w['Eext'] = hamiltonian.Eext w['Exc'] = hamiltonian.Exc w['S'] = hamiltonian.S try: if paw.occupations.fixmagmom: w['FermiLevel'] = paw.occupations.get_fermi_levels_mean() w['FermiSplit'] = paw.occupations.get_fermi_splitting() else: w['FermiLevel'] = paw.occupations.get_fermi_level() except ValueError: # Zero temperature calculation - don't write Fermi level: pass # write errors w['DensityError'] = scf.density_error w['EnergyError'] = scf.energy_error w['EigenstateError'] = scf.eigenstates_error # Try to write time and kick strength in time-propagation TDDFT: for attr, name in [('time', 'Time'), ('niter', 'TimeSteps'), ('kick_strength', 'AbsorptionKick')]: if hasattr(paw, attr): value = getattr(paw, attr) if isinstance(value, np.ndarray): # replicated write here w.add(name, ('3',), value, write=master) else: w[name] = value # Try to write FDTD-related data use_fdtd = hasattr(paw.hamiltonian.poisson, 'get_description') and \ paw.hamiltonian.poisson.get_description() == 'FDTD+TDDFT' w['FDTD'] = use_fdtd if use_fdtd: paw.hamiltonian.poisson.write(paw, w) # Write fingerprint (md5-digest) for all setups: for setup in wfs.setups.setups.values(): key = atomic_names[setup.Z] + 'Fingerprint' if setup.type != 'paw': key += '(%s)' % setup.type w[key] = setup.fingerprint setup_types = p['setups'] if isinstance(setup_types, str): setup_types = {None: setup_types} for key, value in setup_types.items(): if not isinstance(value, str): # Setups which are not strings are assumed to be # runtime-dependent and should *not* be saved. We'll # just discard the whole dictionary setup_types = None break w['SetupTypes'] = repr(setup_types) basis = p['basis'] # And similarly for basis sets if isinstance(basis, dict): for key, value in basis.items(): if not isinstance(value, str): basis = None w['BasisSet'] = repr(basis) dtype = {float: float, complex: complex}[wfs.dtype] timer.stop('Meta data') # Write projections: timer.start('Projections') w.add('Projections', ('nspins', 'nibzkpts', 'nbands', 'nproj'), dtype=dtype) if hdf5: # Domain masters write parallel over spin, kpoints and band groups all_P_ni = np.empty((wfs.bd.mynbands, nproj), dtype=wfs.dtype) cumproj_a = np.cumsum([0] + [setup.ni for setup in wfs.setups]) for kpt in wfs.kpt_u: requests = [] indices = [kpt.s, kpt.k] indices.append(wfs.bd.get_slice()) do_write = (domain_comm.rank == 0) if domain_comm.rank == 0: P_ani = {} for a in range(natoms): ni = wfs.setups[a].ni if wfs.atom_partition.rank_a[a] == 0: P_ani[a] = kpt.P_ani[a] else: P_ani[a] = np.empty((wfs.bd.mynbands, ni), dtype=wfs.dtype) rank = wfs.atom_partition.rank_a[a] requests.append(domain_comm.receive(P_ani[a], rank, 1303 + a, block=False)) else: for a, P_ni in kpt.P_ani.items(): requests.append(domain_comm.send(P_ni, 0, 1303 + a, block=False)) domain_comm.waitall(requests) if domain_comm.rank == 0: for a in range(natoms): all_P_ni[:, cumproj_a[a]:cumproj_a[a + 1]] = P_ani[a] w.fill(all_P_ni, parallel=parallel, write=do_write, *indices) else: for s in range(wfs.nspins): for k in range(wfs.kd.nibzkpts): all_P_ni = wfs.collect_projections(k, s) if master: w.fill(all_P_ni, s, k) del all_P_ni # delete a potentially large matrix timer.stop('Projections') # Write atomic density matrices and non-local part of hamiltonian: timer.start('Atomic matrices') write_atomic_matrix(w, density.D_asp, 'AtomicDensityMatrices', master) write_atomic_matrix(w, hamiltonian.dH_asp, 'NonLocalPartOfHamiltonian', master) timer.stop('Atomic matrices') # Write the eigenvalues and occupation numbers: timer.start('Band energies') for name, var in [('Eigenvalues', 'eps_n'), ('OccupationNumbers', 'f_n')]: w.add(name, ('nspins', 'nibzkpts', 'nbands'), dtype=float) for s in range(wfs.nspins): for k in range(wfs.kd.nibzkpts): # if hdf5: XXX Figure this out later # indices = [s, k] # indices.append(wfs.bd.get_slice()) # u = wfs.kd.where_is(s,k) # a_nx = getattr(wfs.kpt_u[u], var) # w.fill(a_nx, *indices, parallel=True) # else: a_n = wfs.collect_array(var, k, s) if master: w.fill(a_n, s, k) timer.stop('Band energies') # Attempt to read the number of delta-scf orbitals: if hasattr(paw.occupations, 'norbitals'): norbitals = paw.occupations.norbitals else: norbitals = None # Write the linear expansion coefficients for Delta SCF: if mode == 'all' and norbitals is not None: timer.start('dSCF expansions') w.dimension('norbitals', norbitals) w.add('LinearExpansionOccupations', ('nspins', 'nibzkpts', 'norbitals'), dtype=float) for s in range(wfs.nspins): for k in range(wfs.kd.nibzkpts): ne_o = wfs.collect_auxiliary('ne_o', k, s, shape=norbitals) if master: w.fill(ne_o, s, k) w.add('LinearExpansionCoefficients', ('nspins', 'nibzkpts', 'norbitals', 'nbands'), dtype=complex) for s in range(wfs.nspins): for k in range(wfs.kd.nibzkpts): for o in range(norbitals): c_n = wfs.collect_array('c_on', k, s, subset=o) if master: w.fill(c_n, s, k, o) timer.stop('dSCF expansions') # Write the pseudodensity on the coarse grid: timer.start('Pseudo-density') w.add('PseudoElectronDensity', ('nspins', 'ngptsx', 'ngptsy', 'ngptsz'), dtype=float) for s in range(wfs.nspins): if hdf5: do_write = (kpt_comm.rank == 0) and (band_comm.rank == 0) indices = [s] + wfs.gd.get_slice() w.fill(density.nt_sG[s], parallel=parallel, write=do_write, *indices) elif kpt_comm.rank == 0: nt_sG = wfs.gd.collect(density.nt_sG[s]) if master: w.fill(nt_sG, s) timer.stop('Pseudo-density') # Write the pseudopotential on the coarse grid: timer.start('Pseudo-potential') w.add('PseudoPotential', ('nspins', 'ngptsx', 'ngptsy', 'ngptsz'), dtype=float) for s in range(wfs.nspins): if hdf5: do_write = (kpt_comm.rank == 0) and (band_comm.rank == 0) indices = [s] + wfs.gd.get_slice() w.fill(hamiltonian.vt_sG[s], parallel=parallel, write=do_write, *indices) elif kpt_comm.rank == 0: vt_sG = wfs.gd.collect(hamiltonian.vt_sG[s]) if master: w.fill(vt_sG, s) timer.stop('Pseudo-potential') hamiltonian.xc.write(w, natoms) if mode in ['', 'all']: timer.start('Pseudo-wavefunctions') wfs.write(w, write_wave_functions=(mode == 'all')) timer.stop('Pseudo-wavefunctions') elif mode != '': w['Mode'] = 'fd' # Write the wave functions as seperate files # check if we need subdirs and have to create them ftype, template = wave_function_name_template(mode) dirname = os.path.dirname(template) if dirname: if master and not os.path.isdir(dirname): if not os.path.exists(dirname): os.makedirs(dirname) else: raise RuntimeError("Can't create subdir " + dirname) else: dirname = '.' # the slaves have to wait until the directory is created world.barrier() paw.text('Writing wave functions to', dirname, 'using mode=', mode) ngd = wfs.gd.get_size_of_global_array() for s in range(wfs.nspins): for k in range(wfs.kd.nibzkpts): for n in range(wfs.bd.nbands): psit_G = wfs.get_wave_function_array(n, k, s) if master: fname = template % (s, k, n) + '.' + ftype wpsi = open(fname, 'w') wpsi.dimension('1', 1) wpsi.dimension('ngptsx', ngd[0]) wpsi.dimension('ngptsy', ngd[1]) wpsi.dimension('ngptsz', ngd[2]) wpsi.add('PseudoWaveFunction', ('1', 'ngptsx', 'ngptsy', 'ngptsz'), dtype=dtype) wpsi.fill(psit_G) wpsi.close() db = False if filename.endswith('.db') or filename.endswith('.cmr'): from cmr.tools.functions import get_ase_atoms_as_dict atoms_var = get_ase_atoms_as_dict(paw.get_atoms()) if cmr_params is None: c = {} else: c = cmr_params.copy() c["ase_atoms_var"] = atoms_var if master: w.write_additional_db_params(cmr_params=c) elif cmr_params is not None and 'db' in cmr_params: db = cmr_params['db'] timer.start('Close') # Close the file here to ensure that the last wave function is # written to disk: w.close() # We don't want the slaves to start reading before the master has # finished writing: world.barrier() timer.stop('Close') timer.stop('Write') # Creates a db file for CMR, if requested if db and not filename.endswith('.db'): # Write a db copy to the database write(paw, '.db', mode='', cmr_params=cmr_params, **kwargs) elif db and not filename.endswith('.cmr'): # Write a db copy to the database (Note currently only *.db are # accepted for a check-in) write(paw, '.db', mode='', cmr_params=cmr_params, **kwargs) def read(paw, reader, read_projections=True): r = reader timer = paw.timer timer.start('Read') wfs = paw.wfs density = paw.density hamiltonian = paw.hamiltonian natoms = len(paw.atoms) world = paw.wfs.world gd = wfs.gd kd = wfs.kd bd = wfs.bd master = (world.rank == 0) parallel = (world.size > 1) version = r['version'] hdf5 = hasattr(r, 'hdf5') # Verify setup fingerprints and count projectors and atomic matrices: for setup in wfs.setups.setups.values(): try: key = atomic_names[setup.Z] + 'Fingerprint' if setup.type != 'paw': key += '(%s)' % setup.type if setup.fingerprint != r[key]: str = 'Setup for %s (%s) not compatible with restart file.' \ % (setup.symbol, setup.filename) if paw.input_parameters['idiotproof']: raise RuntimeError(str) else: warnings.warn(str) except (AttributeError, KeyError): str = 'Fingerprint of setup for %s (%s) not in restart file.' \ % (setup.symbol, setup.filename) if paw.input_parameters['idiotproof']: raise RuntimeError(str) else: warnings.warn(str) nproj = sum([setup.ni for setup in wfs.setups]) nadm = sum([setup.ni * (setup.ni + 1) // 2 for setup in wfs.setups]) # Verify dimensions for minimally required netCDF variables: ng = gd.get_size_of_global_array() shapes = {'ngptsx': ng[0], 'ngptsy': ng[1], 'ngptsz': ng[2], 'nspins': wfs.nspins, 'nproj': nproj, 'nadm': nadm} for name, dim in shapes.items(): if r.dimension(name) != dim: raise ValueError('shape mismatch: expected %s=%d' % (name, dim)) timer.start('Density') density.read(r, parallel, wfs.kptband_comm) timer.stop('Density') timer.start('Hamiltonian') hamiltonian.read(r, parallel) timer.stop('Hamiltonian') from gpaw.utilities.partition import AtomPartition atom_partition = AtomPartition(gd.comm, np.zeros(natoms, dtype=int)) # let's set some variables directly on some objects! wfs.atom_partition = atom_partition density.atom_partition = atom_partition hamiltonian.atom_partition = atom_partition if version > 0.3: Etot = hamiltonian.Etot energy_error = r['EnergyError'] if energy_error is not None: paw.scf.energies = [Etot, Etot + energy_error, Etot] wfs.eigensolver.error = r['EigenstateError'] if version < 1: wfs.eigensolver.error *= gd.dv else: paw.scf.converged = r['Converged'] if version > 0.6: if paw.occupations.fixmagmom: if 'FermiLevel' in r.get_parameters(): paw.occupations.set_fermi_levels_mean(r['FermiLevel']) if 'FermiSplit' in r.get_parameters(): paw.occupations.set_fermi_splitting(r['FermiSplit']) else: if 'FermiLevel' in r.get_parameters(): paw.occupations.set_fermi_level(r['FermiLevel']) else: if (not paw.input_parameters.fixmom and 'FermiLevel' in r.get_parameters()): paw.occupations.set_fermi_level(r['FermiLevel']) # Try to read the current time and kick strength in time-propagation TDDFT: for attr, name in [('time', 'Time'), ('niter', 'TimeSteps'), ('kick_strength', 'AbsorptionKick')]: if hasattr(paw, attr): try: if r.has_array(name): value = r.get(name, read=master) else: value = r[name] setattr(paw, attr, value) except KeyError: pass # Try to read FDTD-related data try: use_fdtd = r['FDTD'] except: use_fdtd = False if use_fdtd: from gpaw.fdtd.poisson_fdtd import FDTDPoissonSolver # fdtd_poisson will overwrite the poisson at a later stage paw.hamiltonian.fdtd_poisson = FDTDPoissonSolver(restart_reader=r, paw=paw) # Try to read the number of Delta SCF orbitals try: norbitals = r.dimension('norbitals') paw.occupations.norbitals = norbitals except (AttributeError, KeyError): norbitals = None nibzkpts = r.dimension('nibzkpts') nbands = r.dimension('nbands') nslice = bd.get_slice() if (nibzkpts != len(wfs.kd.ibzk_kc) or nbands != bd.comm.size * bd.mynbands): paw.scf.reset() else: # Verify that symmetries for for k-point reduction hasn't changed: tol = 1e-12 if master: bzk_kc = r.get('BZKPoints', read=master) weight_k = r.get('IBZKPointWeights', read=master) assert np.abs(bzk_kc - kd.bzk_kc).max() < tol assert np.abs(weight_k - kd.weight_k).max() < tol for kpt in wfs.kpt_u: # Eigenvalues and occupation numbers: timer.start('Band energies') k = kpt.k s = kpt.s if hdf5: # fully parallelized over spins, k-points do_read = (gd.comm.rank == 0) indices = [s, k] indices.append(nslice) kpt.eps_n = r.get('Eigenvalues', parallel=parallel, read=do_read, *indices) gd.comm.broadcast(kpt.eps_n, 0) kpt.f_n = r.get('OccupationNumbers', parallel=parallel, read=do_read, *indices) gd.comm.broadcast(kpt.f_n, 0) else: eps_n = r.get('Eigenvalues', s, k, read=master) f_n = r.get('OccupationNumbers', s, k, read=master) kpt.eps_n = eps_n[nslice].copy() kpt.f_n = f_n[nslice].copy() timer.stop('Band energies') if norbitals is not None: # XXX will probably fail for hdf5 timer.start('dSCF expansions') kpt.ne_o = np.empty(norbitals, dtype=float) kpt.c_on = np.empty((norbitals, bd.mynbands), dtype=complex) for o in range(norbitals): kpt.ne_o[o] = r.get('LinearExpansionOccupations', s, k, o, read=master) c_n = r.get('LinearExpansionCoefficients', s, k, o, read=master) kpt.c_on[o, :] = c_n[nslice] timer.stop('dSCF expansions') if (r.has_array('PseudoWaveFunctions') and paw.input_parameters.mode != 'lcao'): timer.start('Pseudo-wavefunctions') wfs.read(r, hdf5) timer.stop('Pseudo-wavefunctions') if (r.has_array('WaveFunctionCoefficients') and paw.input_parameters.mode == 'lcao'): wfs.read_coefficients(r) timer.start('Projections') if hdf5 and read_projections: # Domain masters read parallel over spin, kpoints and band groups cumproj_a = np.cumsum([0] + [setup.ni for setup in wfs.setups]) all_P_ni = np.empty((bd.mynbands, cumproj_a[-1]), dtype=wfs.dtype) for kpt in wfs.kpt_u: kpt.P_ani = {} indices = [kpt.s, kpt.k] indices.append(bd.get_slice()) do_read = (gd.comm.rank == 0) # timer.start('ProjectionsCritical(s=%d,k=%d)' % (kpt.s,kpt.k)) r.get('Projections', out=all_P_ni, parallel=parallel, read=do_read, *indices) # timer.stop('ProjectionsCritical(s=%d,k=%d)' % (kpt.s,kpt.k)) if gd.comm.rank == 0: for a in range(natoms): ni = wfs.setups[a].ni P_ni = np.empty((bd.mynbands, ni), dtype=wfs.dtype) P_ni[:] = all_P_ni[:, cumproj_a[a]:cumproj_a[a + 1]] kpt.P_ani[a] = P_ni del all_P_ni # delete a potentially large matrix elif read_projections and r.has_array('Projections'): wfs.read_projections(r) timer.stop('Projections') # Manage mode change: paw.scf.check_convergence(density, wfs.eigensolver, wfs, hamiltonian, paw.forces) newmode = paw.input_parameters.mode try: oldmode = r['Mode'] if oldmode == 'pw': from gpaw.wavefunctions.pw import PW oldmode = PW(ecut=r['PlaneWaveCutoff'] * Hartree) except (AttributeError, KeyError): oldmode = 'fd' # This is an old gpw file from before lcao existed if newmode == 'lcao': spos_ac = paw.atoms.get_scaled_positions() % 1.0 wfs.load_lazily(hamiltonian, spos_ac) if newmode != oldmode: paw.scf.reset() # Get the forces from the old calculation: if r.has_array('CartesianForces'): paw.forces.F_av = r.get('CartesianForces', broadcast=True) else: paw.forces.reset() hamiltonian.xc.read(r) timer.stop('Read') def read_atoms(reader): positions = reader.get('CartesianPositions', broadcast=True) * Bohr numbers = reader.get('AtomicNumbers', broadcast=True) cell = reader.get('UnitCell', broadcast=True) * Bohr pbc = reader.get('BoundaryConditions', broadcast=True) tags = reader.get('Tags', broadcast=True) magmoms = reader.get('MagneticMoments', broadcast=True) # Create instance of Atoms object, and set_tags and magnetic moments atoms = Atoms(positions=positions, numbers=numbers, cell=cell, pbc=pbc) if tags.any(): atoms.set_tags(tags) if magmoms.any(): atoms.set_initial_magnetic_moments(magmoms) if reader.has_array('CartesianVelocities'): velocities = reader.get('CartesianVelocities', broadcast=True) * Bohr / AUT atoms.set_velocities(velocities) return atoms def read_atomic_matrices(all_M_sp, setups): M_asp = {} p1 = 0 for a, setup in enumerate(setups): ni = setup.ni p2 = p1 + ni * (ni + 1) // 2 M_asp[a] = all_M_sp[:, p1:p2].copy() p1 = p2 return M_asp def read_wave_function(gd, s, k, n, mode): """Read the wave function for spin s, kpoint k and index n from a sperate file. The filename is determined from the mode in the same way as in write() (see above)""" ftype, template = wave_function_name_template(mode) fname = template % (s, k, n) + '.' + ftype i = gd.get_slice() r = open(fname, 'r') psit_G = r.get('PseudoWaveFunction', 0)[i] r.close() return psit_G class FileReference: """Common base class for having reference to a file. The actual I/O classes implementing the referencing should be inherited from this class.""" def __init__(self): raise NotImplementedError('Should be implemented in derived classes') def __len__(self): raise NotImplementedError('Should be implemented in derived classes') def __iter__(self): for i in range(len(self)): yield self[i] def __getitem__(self): raise NotImplementedError('Should be implemented in derived classes') def __array__(self): return self[::] gpaw-0.11.0.13004/gpaw/preconditioner.py0000664000175000017500000000431012553643471020007 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. from math import pi import numpy as np from gpaw.transformers import Transformer from gpaw.fd_operators import Laplace from gpaw.utilities.blas import axpy class Preconditioner: def __init__(self, gd0, kin0, dtype=float, block=1): gd1 = gd0.coarsen() gd2 = gd1.coarsen() self.kin0 = kin0 self.kin1 = Laplace(gd1, -0.5, 1, dtype) self.kin2 = Laplace(gd2, -0.5, 1, dtype) self.scratch0 = gd0.zeros((2, block), dtype, False) self.scratch1 = gd1.zeros((3, block),dtype, False) self.scratch2 = gd2.zeros((3, block), dtype, False) self.step = 0.66666666 / kin0.get_diagonal_element() self.restrictor_object0 = Transformer(gd0, gd1, 1,dtype) self.restrictor_object1 = Transformer(gd1, gd2, 1, dtype) self.interpolator_object2 = Transformer(gd2, gd1, 1, dtype) self.interpolator_object1 = Transformer(gd1, gd0, 1, dtype) self.restrictor0 = self.restrictor_object0.apply self.restrictor1 = self.restrictor_object1.apply self.interpolator2 = self.interpolator_object2.apply self.interpolator1 = self.interpolator_object1.apply def calculate_kinetic_energy(self, psit_xG, kpt): return None def __call__(self, residuals, kpt, ekin=None): nb = len(residuals) # number of bands phases = kpt.phase_cd step = self.step d0, q0 = self.scratch0[:,:nb] r1, d1, q1 = self.scratch1[:, :nb] r2, d2, q2 = self.scratch2[:, :nb] self.restrictor0(-residuals, r1, phases) d1[:] = 4 * step * r1 self.kin1.apply(d1, q1, phases) q1 -= r1 self.restrictor1(q1, r2, phases) d2 = 16 * step * r2 self.kin2.apply(d2, q2, phases) q2 -= r2 d2 -= 16 * step * q2 self.interpolator2(d2, q1, phases) d1 -= q1 self.kin1.apply(d1, q1, phases) q1 -= r1 d1 -= 4 * step * q1 self.interpolator1(-d1, d0, phases) self.kin0.apply(d0, q0, phases) q0 -= residuals axpy(-step, q0, d0) # d0 -= step * q0 d0 *= -1.0 return d0 gpaw-0.11.0.13004/gpaw/__init__.py0000664000175000017500000002367112553643470016534 0ustar jensjjensj00000000000000# Copyright (C) 2003 CAMP # Please see the accompanying LICENSE file for further information. """Main gpaw module.""" import os import sys from distutils.util import get_platform from os.path import join, isfile import numpy as np assert not np.version.version.startswith('1.6.0') __all__ = ['GPAW', 'Calculator', 'Mixer', 'MixerSum', 'MixerDif', 'MixerSum2', 'CG', 'Davidson', 'RMM_DIIS', 'DirectLCAO', 'PoissonSolver', 'FermiDirac', 'MethfesselPaxton', 'PW', 'LCAO', 'restart'] class ConvergenceError(Exception): pass class KohnShamConvergenceError(ConvergenceError): pass class PoissonConvergenceError(ConvergenceError): pass # Check for special command line arguments: debug = False trace = False dry_run = 0 memory_estimate_depth = 2 parsize_domain = None parsize_bands = None sl_default = None sl_diagonalize = None sl_inverse_cholesky = None sl_lcao = None sl_lrtddft = None buffer_size = None extra_parameters = {} profile = False i = 1 while len(sys.argv) > i: arg = sys.argv[i] if arg.startswith('--gpaw-'): # Found old-style gpaw command line argument: arg = '--' + arg[7:] raise RuntimeError('Warning: Use %s instead of %s.' % (arg, sys.argv[i])) if arg == '--trace': trace = True elif arg == '--debug': debug = True elif arg.startswith('--dry-run'): dry_run = 1 if len(arg.split('=')) == 2: dry_run = int(arg.split('=')[1]) elif arg.startswith('--memory-estimate-depth'): memory_estimate_depth = -1 if len(arg.split('=')) == 2: memory_estimate_depth = int(arg.split('=')[1]) elif arg.startswith('--domain-decomposition='): parsize_domain = [int(n) for n in arg.split('=')[1].split(',')] if len(parsize_domain) == 1: parsize_domain = parsize_domain[0] else: assert len(parsize_domain) == 3 elif arg.startswith('--state-parallelization='): parsize_bands = int(arg.split('=')[1]) elif arg.startswith('--sl_default='): # --sl_default=nprow,npcol,mb,cpus_per_node # use 'd' for the default of one or more of the parameters # --sl_default=default to use all default values sl_args = [n for n in arg.split('=')[1].split(',')] if len(sl_args) == 1: assert sl_args[0] == 'default' sl_default = ['d'] * 3 else: sl_default = [] assert len(sl_args) == 3 for sl_args_index in range(len(sl_args)): assert sl_args[sl_args_index] is not None if sl_args[sl_args_index] is not 'd': assert int(sl_args[sl_args_index]) > 0 sl_default.append(int(sl_args[sl_args_index])) else: sl_default.append(sl_args[sl_args_index]) elif arg.startswith('--sl_diagonalize='): # --sl_diagonalize=nprow,npcol,mb,cpus_per_node # use 'd' for the default of one or more of the parameters # --sl_diagonalize=default to use all default values sl_args = [n for n in arg.split('=')[1].split(',')] if len(sl_args) == 1: assert sl_args[0] == 'default' sl_diagonalize = ['d'] * 3 else: sl_diagonalize = [] assert len(sl_args) == 3 for sl_args_index in range(len(sl_args)): assert sl_args[sl_args_index] is not None if sl_args[sl_args_index] is not 'd': assert int(sl_args[sl_args_index]) > 0 sl_diagonalize.append(int(sl_args[sl_args_index])) else: sl_diagonalize.append(sl_args[sl_args_index]) elif arg.startswith('--sl_inverse_cholesky='): # --sl_inverse_cholesky=nprow,npcol,mb,cpus_per_node # use 'd' for the default of one or more of the parameters # --sl_inverse_cholesky=default to use all default values sl_args = [n for n in arg.split('=')[1].split(',')] if len(sl_args) == 1: assert sl_args[0] == 'default' sl_inverse_cholesky = ['d'] * 3 else: sl_inverse_cholesky = [] assert len(sl_args) == 3 for sl_args_index in range(len(sl_args)): assert sl_args[sl_args_index] is not None if sl_args[sl_args_index] is not 'd': assert int(sl_args[sl_args_index]) > 0 sl_inverse_cholesky.append(int(sl_args[sl_args_index])) else: sl_inverse_cholesky.append(sl_args[sl_args_index]) elif arg.startswith('--sl_lcao='): # --sl_lcao=nprow,npcol,mb,cpus_per_node # use 'd' for the default of one or more of the parameters # --sl_lcao=default to use all default values sl_args = [n for n in arg.split('=')[1].split(',')] if len(sl_args) == 1: assert sl_args[0] == 'default' sl_lcao = ['d'] * 3 else: sl_lcao = [] assert len(sl_args) == 3 for sl_args_index in range(len(sl_args)): assert sl_args[sl_args_index] is not None if sl_args[sl_args_index] is not 'd': assert int(sl_args[sl_args_index]) > 0 sl_lcao.append(int(sl_args[sl_args_index])) else: sl_lcao.append(sl_args[sl_args_index]) elif arg.startswith('--sl_lrtddft='): # --sl_lcao=nprow,npcol,mb,cpus_per_node # use 'd' for the default of one or more of the parameters # --sl_lcao=default to use all default values sl_args = [n for n in arg.split('=')[1].split(',')] if len(sl_args) == 1: assert sl_args[0] == 'default' sl_lrtddft = ['d'] * 3 else: sl_lrtddft = [] assert len(sl_args) == 3 for sl_args_index in range(len(sl_args)): assert sl_args[sl_args_index] is not None if sl_args[sl_args_index] is not 'd': assert int(sl_args[sl_args_index]) > 0 sl_lrtddft.append(int(sl_args[sl_args_index])) else: sl_lrtddft.append(sl_args[sl_args_index]) elif arg.startswith('--buffer_size='): # Buffer size for MatrixOperator in MB buffer_size = int(arg.split('=')[1]) elif arg.startswith('--gpaw='): extra_parameters = eval('dict(%s)' % arg[7:]) elif arg == '--gpaw': extra_parameters = eval('dict(%s)' % sys.argv.pop(i + 1)) elif arg.startswith('--profile='): profile = arg.split('=')[1] else: i += 1 continue # Delete used command line argument: del sys.argv[i] if debug: np.seterr(over='raise', divide='raise', invalid='raise', under='ignore') oldempty = np.empty def empty(*args, **kwargs): a = oldempty(*args, **kwargs) try: a.fill(np.nan) except ValueError: a.fill(-1000000) return a np.empty = empty build_path = join(__path__[0], '..', 'build') arch = '%s-%s' % (get_platform(), sys.version[0:3]) # If we are running the code from the source directory, then we will # want to use the extension from the distutils build directory: sys.path.insert(0, join(build_path, 'lib.' + arch)) def get_gpaw_python_path(): paths = os.environ['PATH'].split(os.pathsep) paths.insert(0, join(build_path, 'bin.' + arch)) for path in paths: if isfile(join(path, 'gpaw-python')): return path raise RuntimeError('Could not find gpaw-python!') try: setup_paths = os.environ['GPAW_SETUP_PATH'].split(os.pathsep) except KeyError: if os.pathsep == ';': setup_paths = [r'C:\gpaw-setups'] else: setup_paths = ['/usr/local/share/gpaw-setups', '/usr/share/gpaw-setups'] from gpaw.aseinterface import GPAW from gpaw.mixer import Mixer, MixerSum, MixerDif, MixerSum2 from gpaw.eigensolvers import Davidson, RMM_DIIS, CG, DirectLCAO from gpaw.poisson import PoissonSolver from gpaw.occupations import FermiDirac, MethfesselPaxton from gpaw.wavefunctions.lcao import LCAO from gpaw.wavefunctions.pw import PW class Calculator(GPAW): def __init__(self, *args, **kwargs): sys.stderr.write('Please start using GPAW instead of Calculator!\n') GPAW.__init__(self, *args, **kwargs) def restart(filename, Class=GPAW, **kwargs): calc = Class(filename, **kwargs) atoms = calc.get_atoms() return atoms, calc if trace: indent = ' ' path = __path__[0] from gpaw.mpi import parallel, rank if parallel: indent = 'CPU%d ' % rank def f(frame, event, arg): global indent f = frame.f_code.co_filename if not f.startswith(path): return if event == 'call': print(('%s%s:%d(%s)' % (indent, f[len(path):], frame.f_lineno, frame.f_code.co_name))) indent += '| ' elif event == 'return': indent = indent[:-2] sys.setprofile(f) if profile: from cProfile import Profile import atexit prof = Profile() def f(prof, filename): prof.disable() from gpaw.mpi import rank if filename == '-': prof.print_stats('time') else: prof.dump_stats(filename + '.%04d' % rank) atexit.register(f, prof, profile) prof.enable() command = os.environ.get('GPAWSTARTUP') if command is not None: exec(command) def is_parallel_environment(): """Check if we are running in a parallel environment. This function can be redefined in ~/.gpaw/rc.py. Example:: def is_parallel_environment(): import os return 'PBS_NODEFILE' in os.environ """ return False home = os.environ.get('HOME') if home is not None: rc = os.path.join(home, '.gpaw', 'rc.py') if os.path.isfile(rc): # Read file in ~/.gpaw/rc.py exec(open(rc).read())