util::matrix_t MatrixFactory::build( double E ) const { // Copy the static elements util::matrix_t result( static_matrix ); // Generate the dynamic elements int size = result.size1() / 2; ublas::range first_half( 0, size ); ublas::range second_half( size, 2*size ); typedef ublas::matrix_range< util::matrix_t > submatrix_t; submatrix_t A ( result, first_half, first_half ); submatrix_t A_star( result, second_half, second_half ); BOOST_FOREACH( const Term &t, dynamic_terms ) { A += t( ph_states, E, ENUM_A ); A_star -= t( ph_states, E, ENUM_A_STAR ); }
/*! \fn inline void symmetryBlocking(Eigen::MatrixXd & matrix, int cavitySize, int ntsirr, int nr_irrep) * \param[out] matrix the matrix to be block-diagonalized * \param[in] cavitySize the size of the cavity (size of the matrix) * \param[in] ntsirr the size of the irreducible portion of the cavity (size of the blocks) * \param[in] nr_irrep the number of irreducible representations (number of blocks) */ inline void symmetryBlocking(Eigen::MatrixXd & matrix, size_t cavitySize, int ntsirr, int nr_irrep) { // This function implements the simmetry-blocking of the PCM // matrix due to point group symmetry as reported in: // L. Frediani, R. Cammi, C. S. Pomelli, J. Tomasi and K. Ruud, J. Comput.Chem. 25, 375 (2003) // u is the character table for the group (t in the paper) Eigen::MatrixXd u = Eigen::MatrixXd::Zero(nr_irrep, nr_irrep); for (int i = 0; i < nr_irrep; ++i) { for (int j = 0; j < nr_irrep; ++j) { u(i, j) = parity(i&j); } } // Naming of indices: // a, b, c, d run over the total size of the cavity (N) // i, j, k, l run over the number of irreps (n) // p, q, r, s run over the irreducible size of the cavity (N/n) // Instead of forming U (T in the paper) and then perform the dense // multiplication, we multiply block-by-block using just the u matrix. // matrix = U * matrix * Ut; U * Ut = Ut * U = id // First half-transformation, i.e. first_half = matrix * Ut Eigen::MatrixXd first_half = Eigen::MatrixXd::Zero(cavitySize, cavitySize); for (int i = 0; i < nr_irrep; ++i) { int ioff = i * ntsirr; for (int k = 0; k < nr_irrep; ++k) { int koff = k * ntsirr; for (int j = 0; j < nr_irrep; ++j) { int joff = j * ntsirr; double ujk = u(j, k) / nr_irrep; for (int p = 0; p < ntsirr; ++p) { int a = ioff + p; for (int q = 0; q < ntsirr; ++q) { int b = joff + q; int c = koff + q; first_half(a, c) += matrix(a, b) * ujk; } } } } } // Second half-transformation, i.e. matrix = U * first_half matrix.setZero(cavitySize, cavitySize); for (int i = 0; i < nr_irrep; ++i) { int ioff = i * ntsirr; for (int k = 0; k < nr_irrep; ++k) { int koff = k * ntsirr; for (int j = 0; j < nr_irrep; ++j) { int joff = j * ntsirr; double uij = u(i, j); for (int p = 0; p < ntsirr; ++p) { int a = ioff + p; int b = joff + p; for (int q = 0; q < ntsirr; ++q) { int c = koff + q; matrix(a, c) += uij * first_half(b, c); } } } } } // Traverse the matrix and discard numerical zeros for (size_t a = 0; a < cavitySize; ++a) { for (size_t b = 0; b < cavitySize; ++b) { if (numericalZero(matrix(a, b))) { matrix(a, b) = 0.0; } } } }