|
k-dot-p 0.1
|
00001 /* 00002 *An 8-band Hamiltonian on a Cartesian grid. 00003 00004 Copyright (C) 2010 Joseph Pingenot 00005 00006 This program is free software: you can redistribute it and/or modify 00007 it under the terms of the GNU Affero General Public License as published by 00008 the Free Software Foundation, either version 3 of the License, or 00009 (at your option) any later version. 00010 00011 This program is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU Affero General Public License for more details. 00015 00016 You should have received a copy of the GNU Affero General Public License 00017 along with this program. If not, see <http://www.gnu.org/licenses/>. 00018 00019 */ 00020 00021 #include <string.h> 00022 #include <liblapackwrap/lapackwrap_real_double.h> 00023 #include <liblapackwrap/lapackwrap_complex_double.h> 00024 #include <liblapackwrap/blaswrap_complex_double.h> 00025 #include <liblapackwrap/blaswrap_real_double.h> 00026 #include <libkdotp/hamiltonian_cartesian_8band.h++> 00027 #include <libmodelxx/grid.h++> 00028 #include <libkdotp/physical_constants.h++> 00029 #include <libmodelxx/cartesian_grid.h++> 00030 #include <libkdotp/physical_constants.h++> 00031 #include <libmodelxx/material.h++> 00032 00033 using namespace kdp::constants; 00034 00035 #define N_BANDS 8 00036 00037 namespace kdotp { 00038 namespace libkdotp { 00039 namespace hamiltonian { 00040 00041 typedef libmodelxx::grid::cartesian_grid<libmodelxx::structure::material*,1,1> matgrid; 00042 typedef libmodelxx::grid::cartesian_grid<double,1,1> potgrid; 00043 00044 /**\note This matrix contains all of the *constants* of the 8-band 00045 *k-dot-p matrix. Any non-constants across the nanostructure (e.g. 00046 *the coupling constants P, gamma_i, m', etc.) are dependent upon 00047 *position and, therefore, not included (they're not constant across 00048 *the entire structure (nor can they be determined at compile time) 00049 */ 00050 const static struct llw_complex_double consts_8band[] = { 00051 {-hbar*hbar/2.0, 0}, 00052 {0, 0}, 00053 {-1/__builtin_sqrt(2), 0}, 00054 {__builtin_sqrt(2/3), 0}, 00055 {1/__builtin_sqrt(6), 0}, 00056 {0, 0}, 00057 {-1/__builtin_sqrt(3), 0}, 00058 {-1/__builtin_sqrt(3), 0}, 00059 00060 {0, 0}, 00061 {-hbar*hbar/2.0, 0}, 00062 {0, 0,}, 00063 {-1/__builtin_sqrt(2), 0}, 00064 {__builtin_sqrt(2/3), 0}, 00065 {1/__builtin_sqrt(2), 0}, 00066 {-1/__builtin_sqrt(3), 0}, 00067 {1/__builtin_sqrt(3), 0}, 00068 00069 {-1/__builtin_sqrt(2), 0}, 00070 {0, 0}, 00071 /**\notehbar^2/2 for both k_|| and k_z*/ 00072 {-hbar*hbar/(2*m0), 0}, 00073 {2*__builtin_sqrt(3)*hbar*hbar/(2*m0), 0}, 00074 {__builtin_sqrt(3)*hbar*hbar/(2*m0), 2*__builtin_sqrt(3)*hbar*hbar/(2*m0)}, 00075 {0, 0}, 00076 {-__builtin_sqrt(6)*hbar*hbar/(2*m0), 0}, 00077 {-__builtin_sqrt(6)*hbar*hbar/(2*m0), 2*__builtin_sqrt(6)*hbar*hbar/(2*m0)}, 00078 00079 {__builtin_sqrt(2/3), 0}, 00080 {-__builtin_sqrt(6), 0}, 00081 {2*__builtin_sqrt(3)*hbar*hbar/(2*m0), 0}, 00082 {-hbar*hbar/(2*m0), 0}, 00083 {0, 0}, 00084 {__builtin_sqrt(3)*hbar*hbar/(2*m0), 2*__builtin_sqrt(3)*hbar*hbar/(2*m0)}, 00085 {-__builtin_sqrt(2)*hbar*hbar/(2*m0), 0}, 00086 {-3*__builtin_sqrt(2)*hbar*hbar/(2*m0), 0}, 00087 00088 {1/__builtin_sqrt(6), 0}, 00089 {__builtin_sqrt(2/3), 0}, 00090 {__builtin_sqrt(3)*hbar*hbar/(2*m0), -2*__builtin_sqrt(3)*hbar*hbar/(2*m0)}, 00091 {0, 0}, 00092 {-hbar*hbar/(2*m0), 0}, 00093 {-2*__builtin_sqrt(3)*hbar*hbar/(2*m0), 0}, 00094 {3*__builtin_sqrt(2)*hbar*hbar/(2*m0), 0}, 00095 {__builtin_sqrt(2)*hbar*hbar/(2*m0), 0}, 00096 00097 {0, 0}, 00098 {1/__builtin_sqrt(2), 0}, 00099 {0, 0}, 00100 {__builtin_sqrt(3)*hbar*hbar/(2*m0), 2*__builtin_sqrt(3)*hbar*hbar/(2*m0)}, 00101 {-2*__builtin_sqrt(3)*hbar*hbar/(2*m0), 0}, 00102 {__builtin_sqrt(6)*hbar*hbar/(2*m0), -2*__builtin_sqrt(6)*hbar*hbar/(2*m0)}, 00103 {-__builtin_sqrt(6)*hbar*hbar/(2*m0), 0}, 00104 00105 {-1/__builtin_sqrt(3), 0}, 00106 {-1/__builtin_sqrt(3), 0}, 00107 {-__builtin_sqrt(6)*hbar*hbar/(2*m0), 0}, 00108 {-__builtin_sqrt(2)*hbar*hbar/(2*m0), 0}, 00109 {3*__builtin_sqrt(2)*hbar*hbar/(2*m0), 0}, 00110 {__builtin_sqrt(6)*hbar*hbar/(2*m0), 2*__builtin_sqrt(6)*hbar*hbar/(2*m0)}, 00111 {-hbar*hbar/(2*m0), 0}, 00112 {0, 0}, 00113 00114 {-1/__builtin_sqrt(3), 0}, 00115 {1/__builtin_sqrt(3), 0}, 00116 {-__builtin_sqrt(6)*hbar*hbar/(2*m0), 2*__builtin_sqrt(6)*hbar*hbar/(2*m0)}, 00117 {3*__builtin_sqrt(2)*hbar*hbar/(2*m0), 0}, 00118 {__builtin_sqrt(2)*hbar*hbar/(2*m0), 0}, 00119 {-__builtin_sqrt(6)*hbar*hbar/(2*m0), 0}, 00120 {0, 0}, 00121 {-hbar*hbar/(2*m0), 0} 00122 }; 00123 00124 /**Simple helper function to get the appropriate constant out of consts_8band[] 00125 *\note entries are stored in column-major order. 00126 *\note rows, cols are in the order of page 215 in Winkler's spin-orbit book 00127 */ 00128 static inline short get_consts_index(short unsigned row, short unsigned col) { 00129 return row*8 + col; 00130 } 00131 00132 /**does a quick check to make sure the constants matrix is truly Hermitean 00133 *\param eye pointer to a short unsigned int to store the row index of the invalid constant. 00134 *\return -j if a real portion was not identical across a transpose 00135 * +j if a complex portion was not negated across a transpose 00136 * 0 if identical 00137 *\note this is a debugging/safety aid, but costs basically no time. 00138 */ 00139 static int check_constants_hermiticity(unsigned short *eye) { 00140 for(unsigned short i=0; i<8; i++) { 00141 for(unsigned short j=0; j<8; j++) { 00142 /* 00143 *This is buggy and this file currently unused, so it's been commented out so that things will build. 00144 if(consts_8band[get_consts_index(i, j)].re 00145 != consts_8band[get_consts_index(i, j)].re) { 00146 *eye = i; 00147 return -j; 00148 } 00149 if(consts_8band[get_consts_index(i, j)].im 00150 != -consts_8band[get_consts_index(i, j)].im) { 00151 *eye = i; 00152 return j; 00153 } 00154 */ 00155 } 00156 } 00157 return 0; 00158 } 00159 00160 static GError* store_reduced_material_parameters(struct parameters_8band_nostrain *params, matgrid *mg, potgrid *pg) { 00161 int e; 00162 char *s; 00163 const char* paramstring[] = {"E_g_Gamma", "E_v", "Delta", "m_e_Gamma", "gamma1", "gamma2", "gamma3", "Ep"}; 00164 double temp_params[8]; 00165 for(long unsigned i=0; i<mg->L[0]; i++) { 00166 for(short unsigned p=0; p<8; p++) { 00167 temp_params[i] = mg->data[i]->get_property(paramstring[p], &e); 00168 if(e != 0) { 00169 return g_error_new(HAMILTONIAN_CARTESIAN_8BAND_GERROR_DOMAIN, 10+e, "Got error %d getting property (%s) at site %lu (material %s).\n", e, paramstring[p], i, s=mg->data[i]->get_name()); 00170 } 00171 } 00172 params[i].Ec = temp_params[0]+temp_params[1]; 00173 params[i].Ev = temp_params[1]; 00174 params[i].Eso = temp_params[1]-temp_params[2]; 00175 params[i].P = sqrt(hbar*hbar/(2*m0)*temp_params[7]); 00176 /*For the reduced param terms, see Winkler's Spin-orbit book page 216*/ 00177 params[i].oo_mstar = 1.0/temp_params[4] - temp_params[7]/(3*m0)*(2/(temp_params[0]+temp_params[1]) + 1/(temp_params[0]+temp_params[1]+temp_params[2])); 00178 params[i].gamma1 = temp_params[4] - temp_params[7]/(3*(temp_params[0] + temp_params[1])); 00179 params[i].gamma2 = temp_params[5] - temp_params[7]/(6*(temp_params[0] + temp_params[1])); 00180 params[i].gamma3 = temp_params[6] - temp_params[7]/(6*(temp_params[0] + temp_params[1])); 00181 } 00182 return NULL; 00183 } 00184 00185 00186 cartesian_8band::cartesian_8band(struct libmodelxx::structure::generic_structure *gs, boundary_condition bc_, bool second_neighbor_) : upper_diagonal(NULL), diagonal(NULL), matrix(NULL), Q(NULL), bc(bc_), second_neighbor(second_neighbor_), params(NULL) { 00187 n_neighbors=second_neighbor_?2:1; 00188 /*Check to make sure our consts matrix is Hermitean*/ 00189 { 00190 int col; 00191 short unsigned row; 00192 if((col=check_constants_hermiticity(&row)) != 0) { 00193 fprintf(stderr, "Hermiticty check of 8-band constants FAILED at row=%hu col=%d.\n", row, col); 00194 }else{ 00195 fprintf(stderr, "Hermiticty check of 8-band constants PASSED.\n"); 00196 } 00197 } 00198 matgrid *mg = (matgrid*)(gs->material_grid); 00199 potgrid *pg = (potgrid*)(gs->potential_grid); 00200 L = mg->L[0]; 00201 /*Load the reduced material parameters into the array.*/ 00202 params = (struct parameters_8band_nostrain*)malloc(L*sizeof(struct parameters_8band_nostrain)); 00203 if(params == NULL) return; 00204 GError *e = NULL; 00205 if((e = store_reduced_material_parameters(params, mg, pg)) != NULL) { 00206 fprintf(stderr, "hamiltonian_cartesian_8band: ERROR calculating reduced band parameters: %s\n", e->message); 00207 g_error_free(e); 00208 free(params); 00209 params =NULL; 00210 return; 00211 } 00212 if(bc == HARDWALL) { 00213 matrix = new llw_complex_double[(n_neighbors+1)*L*N_BANDS]; 00214 for(long unsigned i = 0; i<(n_neighbors+1)*L*N_BANDS; i++) { 00215 matrix[i].re = 0; 00216 matrix[i].im = 0; 00217 } 00218 }else{ 00219 matrix = new llw_complex_double[L*L*N_BANDS*N_BANDS]; 00220 for(long unsigned int i=0; i<(L*L*N_BANDS*N_BANDS); i++) { 00221 matrix[i].re = 0; 00222 matrix[i].im = 0; 00223 } 00224 } 00225 int e2=0; 00226 //double dconsts = -1/(nm_to_bohr(mg->a[0])*nm_to_bohr(mg->a[0])); 00227 /*Set up the constants for the diagonal, superdiagonal, and second superdiagonal for first nearest neighbor*/ 00228 00229 double ooms=0, ooms_prev=0, ooms_next=0, Eg=0, Ev=0, ooms_prev2=0, ooms_next2=0; 00230 /*Initialize the current ooms.*/ 00231 ooms = 1.0/mg->data[0]->get_property("m_e_Gamma", &e2); 00232 if(e2 != 0) { 00233 fprintf(stderr, "hamiltonians::cartesian_8band: ERROR getting m_e_Gamma (err=%d).\n", e2); 00234 e2=0; 00235 } 00236 ooms_next = 1.0/mg->data[1]->get_property("m_e_Gamma", &e2); 00237 if(e2 != 0) { 00238 fprintf(stderr, "hamiltonians::cartesian_8band: ERROR getting m_e_Gamma (err=%d).\n", e2); 00239 e2=0; 00240 } 00241 for(unsigned int i=0; i<L; i++, ooms_prev2 = ooms_prev, ooms_prev=ooms, ooms=ooms_next, ooms_next = ooms_next2) { 00242 //Eg = ev_to_hartree(mg->data[i]->get_property("E_g_Gamma", &e2)); 00243 Eg = mg->data[i]->get_property("E_g_Gamma", &e2); 00244 if(e2 != 0) { 00245 fprintf(stderr, "hamiltonians::cartesian_8band: ERROR getting E_g_Gamma (err=%d).\n", e2); 00246 e2=0; 00247 } 00248 //Ev = ev_to_hartree(mg->data[i]->get_property("E_v", &e2)); 00249 Ev = mg->data[i]->get_property("E_v", &e2); 00250 if(e2 != 0) { 00251 fprintf(stderr, "hamiltonians::cartesian_8band: ERROR getting E_v (err=%d).\n", e2); 00252 e2=0; 00253 } 00254 if(i < L-2) { 00255 ooms_next2 = 1.0/mg->data[i+2]->get_property("m_e_Gamma", &e2); 00256 if(e2 != 0) { 00257 fprintf(stderr, "hamiltonians::cartesian_8band: ERROR getting m_e_Gamma (err=%d).\n", e2); 00258 e2=0; 00259 } 00260 } 00261 char *s; 00262 fprintf(stderr, "%05u(%s): ooms_prev2=%g ooms_prev=%g ooms=%g ooms_next=%g ooms_next2=%g Ev+Eg=%g\n", i, s=mg->data[i]->get_name(), ooms_prev2, ooms_prev, ooms, ooms_next, ooms_next2, Ev+Eg); 00263 g_free(s); 00264 //////////////////////////////////////////////////////////////// 00265 // NOTHING BELOW THIS LINE HAS BEEN FULLY IMPLEMENTED FOR 8BAND; 00266 // THIS IS ALL PLACEHOLDER/FORM CODE WHICH HAS BEEN MADE TO 00267 // COMPILE. 00268 //////////////////////////////////////////////////////////////// 00269 if(bc == HARDWALL) { 00270 }else{ 00271 } 00272 } 00273 } 00274 00275 cartesian_8band::~cartesian_8band(){ 00276 if(matrix != NULL) delete[] matrix; 00277 if(diagonal != NULL) delete[] diagonal; 00278 if(upper_diagonal != NULL) delete[] upper_diagonal; 00279 if(Q != NULL) delete[] Q; 00280 if(matrix != NULL) delete[] matrix; 00281 } 00282 00283 double* cartesian_8band::get_eigenvectors(char VoI, double eVmin, double eVmax, int imin, int imax, double **evals, int *n_eigs, GError **err) { 00284 int info; 00285 if ((bc == PERIODIC) && (diagonal == NULL) && (upper_diagonal == NULL) && (Q == NULL)) { 00286 /*If we're not hardwall, we first have to reduce to tridiagonal.*/ 00287 /*We're a symmetric matrix, but not tridiag. 00288 *Call DSYTRD to get the tri-diag matrix*/ 00289 /*Call DORGTR to get the matrix Q to convert the eigenfunctions back to the position basis.*/ 00290 } else if (second_neighbor && (diagonal == NULL) && (upper_diagonal == NULL) && (Q == NULL)) { 00291 /*We're a banded matrix.*/ 00292 /*Call DSBTRD to get the tri-diagonal matrix and Q*/ 00293 info = llw_complex_double_sbtrd_a('V', 'U', L, n_neighbors, matrix, n_neighbors+1, &diagonal, &upper_diagonal, &Q); 00294 if(info != 0) { 00295 *err = g_error_new(HAMILTONIAN_CARTESIAN_8BAND_GERROR_DOMAIN, 1, "Got error from llw_complex_double_sbtrd_a: %d\n", info); 00296 if(diagonal != NULL) { 00297 free(diagonal); 00298 diagonal = NULL; 00299 } 00300 if(upper_diagonal != NULL) { 00301 free(upper_diagonal); 00302 upper_diagonal = NULL; 00303 } 00304 if(Q != NULL) { 00305 free(Q); 00306 Q = NULL; 00307 } 00308 return NULL; 00309 } 00310 } 00311 double *eigvecs = NULL; 00312 int n_eigvecs = -1; 00313 int* isuppz = NULL; 00314 //info = llw_complex_double_stegr_a('V', VoI, L, diagonal, upper_diagonal, eVmin, eVmax, imin, imax, n_eigs, evals, &eigvecs, &n_eigvecs, &isuppz); 00315 if((n_eigvecs <= *n_eigs) || (info != 0)) { 00316 if(n_eigvecs <= *n_eigs) { 00317 *err = g_error_new(HAMILTONIAN_CARTESIAN_8BAND_GERROR_DOMAIN, 6, "in return from llw_complex_double_stegr_a: failed to get same number or more eigenvec storage than there were eigenvals (%d and %d, respectively)", n_eigvecs, *n_eigs); 00318 }else{ 00319 if(info < 0) { 00320 *err = g_error_new(HAMILTONIAN_CARTESIAN_8BAND_GERROR_DOMAIN, 1, "Bad argument to LAPACK call DSTEGR: %d\n", -info); 00321 }else if(info < 10) { 00322 *err = g_error_new(HAMILTONIAN_CARTESIAN_8BAND_GERROR_DOMAIN, 2, "Error in BLAS call DLARRE called by LAPACK call DSGEGR: %d\n", info); 00323 }else if(info < 20) { 00324 *err = g_error_new(HAMILTONIAN_CARTESIAN_8BAND_GERROR_DOMAIN, 3, "Error in BLAS call DLARRV called by LAPACK call DSGEGR: %d\n", info/2); 00325 }else if(info == 100) { 00326 *err = g_error_new(HAMILTONIAN_CARTESIAN_8BAND_GERROR_DOMAIN, 5, "Error in liblapackwrap llw_complex_double_stegr_a: malloc failed (%d)\n", info/100); 00327 }else{ 00328 *err = g_error_new(HAMILTONIAN_CARTESIAN_8BAND_GERROR_DOMAIN, 4, "Got error (info=%d) from DSTEGR, but don't know what it means.\n", info); 00329 } 00330 } 00331 free(*evals); 00332 free(eigvecs); 00333 *evals=NULL; 00334 eigvecs=NULL; 00335 }else{ 00336 free(isuppz); 00337 if(Q != NULL) { 00338 double* final_eigvecs = NULL; 00339 double one = 1.0; 00340 //info = llw_complex_double_gemm_a('N', 'N', L, n_eigvecs, L, &one, Q, L, eigvecs, L, &final_eigvecs); 00341 if(info != 0) { 00342 *err = g_error_new(HAMILTONIAN_CARTESIAN_8BAND_GERROR_DOMAIN, 4, "Got error (info=%d) from llw_complex_double_gemmm_a\n", info); 00343 if(final_eigvecs != NULL) free(final_eigvecs); 00344 return eigvecs; 00345 } 00346 free(eigvecs); 00347 return final_eigvecs; 00348 } 00349 } 00350 return eigvecs; 00351 } 00352 00353 00354 } 00355 } 00356 }