|
41 | 41 | * \date 2015
|
42 | 42 | */
|
43 | 43 |
|
| 44 | +/*! \brief Builds the **anisotropic** IEFPCM matrix |
| 45 | + * \param[in] cav the discretized cavity |
| 46 | + * \param[in] gf_i Green's function inside the cavity |
| 47 | + * \param[in] gf_o Green's function outside the cavity |
| 48 | + * \return the \f$ \mathbf{K} = \mathbf{T}^{-1}\mathbf{R}\mathbf{A} \f$ matrix |
| 49 | + * |
| 50 | + * This function calculates the PCM matrix. We use the following definitions: |
| 51 | + * \f[ |
| 52 | + * \begin{align} |
| 53 | + * \mathbf{T} &= |
| 54 | + * \left(2\pi\mathbf{I} - \mathbf{D}_\mathrm{e}\mathbf{A}\right)\mathbf{S}_\mathrm{i} |
| 55 | + * +\mathbf{S}_\mathrm{e}\left(2\pi\mathbf{I} + |
| 56 | + * \mathbf{A}\mathbf{D}_\mathrm{i}^\dagger\right) \\ |
| 57 | + * \mathbf{R} &= |
| 58 | + * \left(2\pi\mathbf{A}^{-1} - \mathbf{D}_\mathrm{e}\right) - |
| 59 | + * \mathbf{S}_\mathrm{e}\mathbf{S}^{-1}_\mathrm{i}\left(2\pi\mathbf{A}^{-1}-\mathbf{D}_\mathrm{i}\right) |
| 60 | + * \end{align} |
| 61 | + * \f] |
| 62 | + * The matrix is not symmetrized and is not symmetry packed. |
| 63 | + */ |
| 64 | +inline Eigen::MatrixXd anisotropicIEFMatrix(const Cavity & cav, const IGreensFunction & gf_i, const IGreensFunction & gf_o) |
| 65 | +{ |
| 66 | + // The total size of the cavity |
| 67 | + PCMSolverIndex cavitySize = cav.size(); |
| 68 | + // The number of irreps in the group |
| 69 | + int nrBlocks = cav.pointGroup().nrIrrep(); |
| 70 | + // The size of the irreducible portion of the cavity |
| 71 | + int dimBlock = cav.irreducible_size(); |
| 72 | + |
| 73 | + // Compute SI, DI and SE, DE on the whole cavity, regardless of symmetry |
| 74 | + TIMER_ON("Computing SI"); |
| 75 | + Eigen::MatrixXd SI = gf_i.singleLayer(cav.elements()); |
| 76 | + TIMER_OFF("Computing SI"); |
| 77 | + TIMER_ON("Computing DI"); |
| 78 | + Eigen::MatrixXd DI = gf_i.doubleLayer(cav.elements()); |
| 79 | + TIMER_OFF("Computing DI"); |
| 80 | + TIMER_ON("Computing SE"); |
| 81 | + Eigen::MatrixXd SE = gf_o.singleLayer(cav.elements()); |
| 82 | + TIMER_OFF("Computing SE"); |
| 83 | + TIMER_ON("Computing DE"); |
| 84 | + Eigen::MatrixXd DE = gf_o.doubleLayer(cav.elements()); |
| 85 | + TIMER_OFF("Computing DE"); |
| 86 | + |
| 87 | + // Perform symmetry blocking |
| 88 | + // If the group is C1 avoid symmetry blocking, we will just pack the fullPCMMatrix |
| 89 | + // into "block diagonal" when all other manipulations are done. |
| 90 | + if (cav.pointGroup().nrGenerators() != 0) { |
| 91 | + TIMER_ON("Symmetry blocking"); |
| 92 | + symmetryBlocking(DI, cavitySize, dimBlock, nrBlocks); |
| 93 | + symmetryBlocking(SI, cavitySize, dimBlock, nrBlocks); |
| 94 | + symmetryBlocking(DE, cavitySize, dimBlock, nrBlocks); |
| 95 | + symmetryBlocking(SE, cavitySize, dimBlock, nrBlocks); |
| 96 | + TIMER_OFF("Symmetry blocking"); |
| 97 | + } |
| 98 | + |
| 99 | + Eigen::MatrixXd a = cav.elementArea().asDiagonal(); |
| 100 | + Eigen::MatrixXd Id = Eigen::MatrixXd::Identity(cavitySize, cavitySize); |
| 101 | + |
| 102 | + TIMER_ON("Assemble T matrix"); |
| 103 | + Eigen::MatrixXd T = ((2 * M_PI * Id - DE * a) * SI + SE * (2 * M_PI * Id + a * DI.adjoint().eval())); |
| 104 | + TIMER_OFF("Assemble T matrix"); |
| 105 | + |
| 106 | + TIMER_ON("Assemble R matrix"); |
| 107 | + Eigen::MatrixXd R = ((2 * M_PI * Id - DE * a) - SE * SI.ldlt().solve((2 * M_PI * Id - DI * a))); |
| 108 | + TIMER_OFF("Assemble R matrix"); |
| 109 | + |
| 110 | + TIMER_ON("Assemble T^-1R matrix"); |
| 111 | + Eigen::MatrixXd fullPCMMatrix = T.partialPivLu().solve(R); |
| 112 | + TIMER_OFF("Assemble T^-1R matrix"); |
| 113 | + |
| 114 | + return fullPCMMatrix; |
| 115 | +} |
| 116 | + |
| 117 | +/*! \brief Builds the **isotropic** IEFPCM matrix |
| 118 | + * \param[in] cav the discretized cavity |
| 119 | + * \param[in] gf_i Green's function inside the cavity |
| 120 | + * \param[in] epsilon permittivity outside the cavity |
| 121 | + * \return the \f$ \mathbf{K} = \mathbf{T}^{-1}\mathbf{R}\mathbf{A} \f$ matrix |
| 122 | + * |
| 123 | + * This function calculates the PCM matrix. We use the following definitions: |
| 124 | + * \f[ |
| 125 | + * \begin{align} |
| 126 | + * \mathbf{T} &= |
| 127 | + * \left(2\pi\frac{\varepsilon+1}{\varepsilon-1}\mathbf{I} - \mathbf{D}_\mathrm{i}\mathbf{A}\right)\mathbf{S}_\mathrm{i} \\ |
| 128 | + * \mathbf{R} &= |
| 129 | + * \left(2\pi\mathbf{A}^{-1} - \mathbf{D}_\mathrm{i}\right) |
| 130 | + * \end{align} |
| 131 | + * \f] |
| 132 | + * The matrix is not symmetrized and is not symmetry packed. |
| 133 | + */ |
| 134 | +inline Eigen::MatrixXd isotropicIEFMatrix(const Cavity & cav, const IGreensFunction & gf_i, double epsilon) |
| 135 | +{ |
| 136 | + // The total size of the cavity |
| 137 | + PCMSolverIndex cavitySize = cav.size(); |
| 138 | + // The number of irreps in the group |
| 139 | + int nrBlocks = cav.pointGroup().nrIrrep(); |
| 140 | + // The size of the irreducible portion of the cavity |
| 141 | + int dimBlock = cav.irreducible_size(); |
| 142 | + |
| 143 | + // Compute SI and DI on the whole cavity, regardless of symmetry |
| 144 | + TIMER_ON("Computing SI"); |
| 145 | + Eigen::MatrixXd SI = gf_i.singleLayer(cav.elements()); |
| 146 | + TIMER_OFF("Computing SI"); |
| 147 | + TIMER_ON("Computing DI"); |
| 148 | + Eigen::MatrixXd DI = gf_i.doubleLayer(cav.elements()); |
| 149 | + TIMER_OFF("Computing DI"); |
| 150 | + |
| 151 | + // Perform symmetry blocking |
| 152 | + // If the group is C1 avoid symmetry blocking, we will just pack the fullPCMMatrix |
| 153 | + // into "block diagonal" when all other manipulations are done. |
| 154 | + if (cav.pointGroup().nrGenerators() != 0) { |
| 155 | + TIMER_ON("Symmetry blocking"); |
| 156 | + symmetryBlocking(DI, cavitySize, dimBlock, nrBlocks); |
| 157 | + symmetryBlocking(SI, cavitySize, dimBlock, nrBlocks); |
| 158 | + TIMER_OFF("Symmetry blocking"); |
| 159 | + } |
| 160 | + |
| 161 | + Eigen::MatrixXd a = cav.elementArea().asDiagonal(); |
| 162 | + Eigen::MatrixXd Id = Eigen::MatrixXd::Identity(cavitySize, cavitySize); |
| 163 | + |
| 164 | + // Tq = -Rv -> q = -(T^-1 * R)v = -Kv |
| 165 | + // T = (2 * M_PI * fact * aInv - DI) * a * SI; R = (2 * M_PI * aInv - DI) |
| 166 | + // fullPCMMatrix_ = K = T^-1 * R * a |
| 167 | + // 1. Form T |
| 168 | + double fact = (epsilon + 1.0)/(epsilon - 1.0); |
| 169 | + TIMER_ON("Assemble T matrix"); |
| 170 | + Eigen::MatrixXd T = (2 * M_PI * fact * Id - DI * a) * SI; |
| 171 | + TIMER_OFF("Assemble T matrix"); |
| 172 | + |
| 173 | + TIMER_ON("Assemble R matrix"); |
| 174 | + Eigen::MatrixXd R = (2 * M_PI * Id - DI * a); |
| 175 | + TIMER_OFF("Assemble R matrix"); |
| 176 | + |
| 177 | + TIMER_ON("Assemble T^-1R matrix"); |
| 178 | + Eigen::MatrixXd fullPCMMatrix = T.partialPivLu().solve(R); |
| 179 | + TIMER_OFF("Assemble T^-1R matrix"); |
| 180 | + |
| 181 | + return fullPCMMatrix; |
| 182 | +} |
| 183 | + |
44 | 184 | /*! \brief Builds the **anisotropic** \f$ \mathbf{T}_\varepsilon \f$ matrix
|
45 | 185 | * \param[in] cav the discretized cavity
|
46 | 186 | * \param[in] gf_i Green's function inside the cavity
|
@@ -172,8 +312,7 @@ inline Eigen::MatrixXd anisotropicRinfinity(const Cavity & cav, const IGreensFun
|
172 | 312 | Eigen::MatrixXd Id = Eigen::MatrixXd::Identity(cavitySize, cavitySize);
|
173 | 313 |
|
174 | 314 | // Form R
|
175 |
| - Eigen::PartialPivLU<Eigen::MatrixXd> SI_LU(SI); |
176 |
| - return ((2 * M_PI * Id - DE * a) - SE * SI_LU.inverse() * (2 * M_PI * Id - DI * a)); |
| 315 | + return ((2 * M_PI * Id - DE * a) - SE * SI.ldlt().solve((2 * M_PI * Id - DI * a))); |
177 | 316 | }
|
178 | 317 |
|
179 | 318 | /*! \brief Builds the **isotropic** \f$ \mathbf{R}_\infty \f$ matrix
|
|
0 commit comments