/** * Diagonalize the block diagonal matrix. Needs lapack. Differs from MomHamiltonian::ExactDiagonalizeFull that * is diagonalize block per block and keeps the momentum associated with each eigenvalue. * @param calc_eigenvectors set to true to calculate the eigenvectors. The hamiltonian * matrix is then overwritten by the vectors. * @return a vector of pairs. The first member of the pair is the momentum, the second is * the eigenvalue. The vector is sorted to the eigenvalues. */ std::vector< std::pair<int,double> > MomHamiltonian::ExactMomDiagonalizeFull(bool calc_eigenvectors) { std::vector<double> eigs(dim); std::vector< std::pair<int, double> > energy; int offset = 0; for(int B=0; B<L; B++) { int dim = mombase[B].size(); Diagonalize(dim, blockmat[B].get(), &eigs[offset], calc_eigenvectors); for(int i=0; i<dim; i++) energy.push_back(std::make_pair(B,eigs[offset+i])); offset += dim; } std::sort(energy.begin(), energy.end(), [](const std::pair<int,double> & a, const std::pair<int,double> & b) -> bool { return a.second < b.second; }); return energy; }
/** * Exactly calculates the eigenvalues of the matrix. * Needs lapack. * @param calc_eigenvectors set to true to calculate the eigenvectors. The hamiltonian * matrix is then overwritten by the vectors. * @return the vector of the sorted eigenvalues */ std::vector<double> MomHamiltonian::ExactDiagonalizeFull(bool calc_eigenvectors) { std::vector<double> eigenvalues(dim); int offset = 0; for(int B=0; B<L; B++) { int dim = mombase[B].size(); Diagonalize(dim, blockmat[B].get(), &eigenvalues[offset], calc_eigenvectors); offset += dim; } std::sort(eigenvalues.begin(), eigenvalues.end()); return eigenvalues; }
/** * diag = u^* m v^+ * * @param m mass matrix * @param u mixing matrix * @param v mixing matrix * @param eigenvalues eigenvalues (sorted) */ void Diagonalize(const softsusy::DoubleMatrix& m, softsusy::ComplexMatrix& u, softsusy::ComplexMatrix& v, softsusy::DoubleVector& eigenvalues) { #ifdef ENABLE_DEBUG const int c = m.displayCols(); if (m.displayRows() != c || eigenvalues.displayEnd() != c || v.displayCols() != c || v.displayRows() !=c || c > 10) { ostringstream ii; ii << "Error: Trying to diagonalise matrix \n" << m; throw ii.str(); } #endif softsusy::DoubleMatrix realU(u.real()), realV(v.real()); Diagonalize(m, realU, realV, eigenvalues); const softsusy::ComplexMatrix trans(phase_rotation(eigenvalues)); u = trans * realU; v = trans * realV; eigenvalues = eigenvalues.apply(fabs); }
Matrix3 Diagonalized(Mat3Param matrix) { Matrix3 newMatrix = matrix; Diagonalize(&newMatrix); return newMatrix; }
/** * This methods calculates the eigenvalues for a range of U values. The interval is [Ubegin, Uend] * with a stepsize of step. The resulting data is written to a file in the HDF5 file format. * @param Ubegin the startpoint for U * @param Uend the endpoint for U. We demand Ubegin < Uend * @param step the stepsize to use for U * @param filename the name of the file write to written the eigenvalues to */ void MomHamiltonian::GenerateData(double Ubegin, double Uend, double step, std::string filename) { double Ucur = Ubegin; if( !baseUp.size() || !baseDown.size() ) BuildBase(); std::vector<double> eigenvalues(dim); hid_t file_id, group_id, dataset_id, dataspace_id, attribute_id; herr_t status; file_id = H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); HDF5_STATUS_CHECK(file_id); group_id = H5Gcreate(file_id, "run", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); HDF5_STATUS_CHECK(group_id); dataspace_id = H5Screate(H5S_SCALAR); attribute_id = H5Acreate (group_id, "L", H5T_STD_I32LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT); status = H5Awrite (attribute_id, H5T_NATIVE_INT, &L ); HDF5_STATUS_CHECK(status); status = H5Aclose(attribute_id); HDF5_STATUS_CHECK(status); attribute_id = H5Acreate (group_id, "Nu", H5T_STD_I32LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT); status = H5Awrite (attribute_id, H5T_NATIVE_INT, &Nu ); HDF5_STATUS_CHECK(status); status = H5Aclose(attribute_id); HDF5_STATUS_CHECK(status); attribute_id = H5Acreate (group_id, "Nd", H5T_STD_I32LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT); status = H5Awrite (attribute_id, H5T_NATIVE_INT, &Nd ); HDF5_STATUS_CHECK(status); status = H5Aclose(attribute_id); HDF5_STATUS_CHECK(status); attribute_id = H5Acreate (group_id, "J", H5T_IEEE_F64LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT); status = H5Awrite (attribute_id, H5T_NATIVE_DOUBLE, &J ); HDF5_STATUS_CHECK(status); status = H5Aclose(attribute_id); HDF5_STATUS_CHECK(status); attribute_id = H5Acreate (group_id, "Ubegin", H5T_IEEE_F64LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT); status = H5Awrite (attribute_id, H5T_NATIVE_DOUBLE, &Ubegin ); HDF5_STATUS_CHECK(status); status = H5Aclose(attribute_id); HDF5_STATUS_CHECK(status); attribute_id = H5Acreate (group_id, "Uend", H5T_IEEE_F64LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT); status = H5Awrite (attribute_id, H5T_NATIVE_DOUBLE, &Uend ); HDF5_STATUS_CHECK(status); status = H5Aclose(attribute_id); HDF5_STATUS_CHECK(status); attribute_id = H5Acreate (group_id, "Ustep", H5T_IEEE_F64LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT); status = H5Awrite (attribute_id, H5T_NATIVE_DOUBLE, &step ); HDF5_STATUS_CHECK(status); status = H5Aclose(attribute_id); HDF5_STATUS_CHECK(status); status = H5Sclose(dataspace_id); HDF5_STATUS_CHECK(status); status = H5Gclose(group_id); HDF5_STATUS_CHECK(status); status = H5Fclose(file_id); HDF5_STATUS_CHECK(status); std::vector<double> diagonalelements(dim); std::vector< std::unique_ptr<double []> > offdiag; offdiag.resize(L); // make sure that we don't rebuild the whole hamiltonian every time. // store the hopping and interaction part seperate so we can just // add them in every step #pragma omp parallel for for(int B=0; B<L; B++) { int cur_dim = mombase[B].size(); int offset = 0; for(int tmp=0; tmp<B; tmp++) offset += mombase[tmp].size(); offdiag[B].reset(new double [cur_dim*cur_dim]); for(int i=0; i<cur_dim; i++) { int a = mombase[B][i].first; int b = mombase[B][i].second; diagonalelements[offset+i] = hopping(baseUp[a]) + hopping(baseDown[b]); for(int j=i; j<cur_dim; j++) { int c = mombase[B][j].first; int d = mombase[B][j].second; offdiag[B][j+cur_dim*i] = 1.0/L*interaction(a,b,c,d); offdiag[B][i+cur_dim*j] = offdiag[B][j+cur_dim*i]; } } } while(Ucur <= Uend) { std::cout << "U = " << Ucur << std::endl; setU(Ucur); // make hamiltonian #pragma omp parallel for for(int B=0; B<L; B++) { int cur_dim = mombase[B].size(); int offset = 0; for(int tmp=0; tmp<B; tmp++) offset += mombase[tmp].size(); std::memcpy(blockmat[B].get(),offdiag[B].get(),cur_dim*cur_dim*sizeof(double)); int tmp = cur_dim*cur_dim; int inc = 1; dscal_(&tmp,&Ucur,blockmat[B].get(),&inc); for(int i=0; i<cur_dim; i++) blockmat[B][i+cur_dim*i] += diagonalelements[offset+i]; } #pragma omp parallel for for(int B=0; B<L; B++) { int dim = mombase[B].size(); int offset = 0; for(int tmp=0; tmp<B; tmp++) offset += mombase[tmp].size(); Diagonalize(dim, blockmat[B].get(), &eigenvalues[offset], false); } hid_t U_id; std::stringstream name; name << std::setprecision(5) << std::fixed << "/run/" << Ucur; file_id = H5Fopen(filename.c_str(), H5F_ACC_RDWR, H5P_DEFAULT); HDF5_STATUS_CHECK(file_id); U_id = H5Gcreate(file_id, name.str().c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); HDF5_STATUS_CHECK(U_id); for(int B=0; B<L; B++) { int dim = mombase[B].size(); int offset = 0; for(int tmp=0; tmp<B; tmp++) offset += mombase[tmp].size(); hsize_t dimarr = dim; dataspace_id = H5Screate_simple(1, &dimarr, NULL); std::stringstream cur_block; cur_block << B; dataset_id = H5Dcreate(U_id, cur_block.str().c_str(), H5T_IEEE_F64LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); status = H5Dwrite(dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &eigenvalues[offset] ); HDF5_STATUS_CHECK(status); status = H5Sclose(dataspace_id); HDF5_STATUS_CHECK(status); status = H5Dclose(dataset_id); HDF5_STATUS_CHECK(status); } status = H5Gclose(U_id); HDF5_STATUS_CHECK(status); status = H5Fclose(file_id); HDF5_STATUS_CHECK(status); Ucur += step; } }