/*! \brief Builds the CPCM matrix * \param[in] cav the discretized cavity * \param[in] gf_i Green's function inside the cavity * \param[in] epsilon permittivity outside the cavity * \param[in] correction CPCM correction factor * \return the \f$ \mathbf{K} = f(\varepsilon)\mathbf{S}^{-1} \f$ matrix * * This function calculates the PCM matrix. * The matrix is not symmetrized and is not symmetry packed. */ inline Eigen::MatrixXd CPCMMatrix(const Cavity & cav, const IGreensFunction & gf_i, double epsilon, double correction) { // The total size of the cavity size_t cavitySize = cav.size(); // The number of irreps in the group int nrBlocks = cav.pointGroup().nrIrrep(); // The size of the irreducible portion of the cavity int dimBlock = cav.irreducible_size(); // Compute SI and DI on the whole cavity, regardless of symmetry TIMER_ON("Computing SI"); Eigen::MatrixXd SI = gf_i.singleLayer(cav.elements()); TIMER_OFF("Computing SI"); // Perform symmetry blocking // If the group is C1 avoid symmetry blocking, we will just pack the fullPCMMatrix // into "block diagonal" when all other manipulations are done. if (cav.pointGroup().nrGenerators() != 0) { TIMER_ON("Symmetry blocking"); symmetryBlocking(SI, cavitySize, dimBlock, nrBlocks); TIMER_OFF("Symmetry blocking"); } double fact = (epsilon - 1.0)/(epsilon + correction); // Invert SI using LU decomposition with full pivoting // This is a rank-revealing LU decomposition, this allows us // to test if SI is invertible before attempting to invert it. Eigen::FullPivLU<Eigen::MatrixXd> SI_LU(SI); if (!(SI_LU.isInvertible())) PCMSOLVER_ERROR("SI matrix is not invertible!", BOOST_CURRENT_FUNCTION); return fact * SI_LU.inverse(); }
/*! \brief Builds the **anisotropic** IEFPCM matrix * \param[in] cav the discretized cavity * \param[in] gf_i Green's function inside the cavity * \param[in] gf_o Green's function outside the cavity * \return the \f$ \mathbf{K} = \mathbf{T}^{-1}\mathbf{R}\mathbf{A} \f$ matrix * * This function calculates the PCM matrix. We use the following definitions: * \f[ * \begin{align} * \mathbf{T} &= * \left(2\pi\mathbf{I} - \mathbf{D}_\mathrm{e}\mathbf{A}\right)\mathbf{S}_\mathrm{i} * +\mathbf{S}_\mathrm{e}\left(2\pi\mathbf{I} + * \mathbf{A}\mathbf{D}_\mathrm{i}^\dagger\right) \\ * \mathbf{R} &= * \left(2\pi\mathbf{A}^{-1} - \mathbf{D}_\mathrm{e}\right) - * \mathbf{S}_\mathrm{e}\mathbf{S}^{-1}_\mathrm{i}\left(2\pi\mathbf{A}^{-1}-\mathbf{D}_\mathrm{i}\right) * \end{align} * \f] * The matrix is not symmetrized and is not symmetry packed. */ inline Eigen::MatrixXd anisotropicIEFMatrix(const Cavity & cav, const IGreensFunction & gf_i, const IGreensFunction & gf_o) { // The total size of the cavity size_t cavitySize = cav.size(); // The number of irreps in the group int nrBlocks = cav.pointGroup().nrIrrep(); // The size of the irreducible portion of the cavity int dimBlock = cav.irreducible_size(); // Compute SI, DI and SE, DE on the whole cavity, regardless of symmetry TIMER_ON("Computing SI"); Eigen::MatrixXd SI = gf_i.singleLayer(cav.elements()); TIMER_OFF("Computing SI"); TIMER_ON("Computing DI"); Eigen::MatrixXd DI = gf_i.doubleLayer(cav.elements()); TIMER_OFF("Computing DI"); TIMER_ON("Computing SE"); Eigen::MatrixXd SE = gf_o.singleLayer(cav.elements()); TIMER_OFF("Computing SE"); TIMER_ON("Computing DE"); Eigen::MatrixXd DE = gf_o.doubleLayer(cav.elements()); TIMER_OFF("Computing DE"); // Perform symmetry blocking // If the group is C1 avoid symmetry blocking, we will just pack the fullPCMMatrix // into "block diagonal" when all other manipulations are done. if (cav.pointGroup().nrGenerators() != 0) { TIMER_ON("Symmetry blocking"); symmetryBlocking(DI, cavitySize, dimBlock, nrBlocks); symmetryBlocking(SI, cavitySize, dimBlock, nrBlocks); symmetryBlocking(DE, cavitySize, dimBlock, nrBlocks); symmetryBlocking(SE, cavitySize, dimBlock, nrBlocks); TIMER_OFF("Symmetry blocking"); } Eigen::MatrixXd a = cav.elementArea().asDiagonal(); Eigen::MatrixXd Id = Eigen::MatrixXd::Identity(cavitySize, cavitySize); // 1. Form T TIMER_ON("Assemble T matrix"); Eigen::MatrixXd fullPCMMatrix = ((2 * M_PI * Id - DE * a) * SI + SE * (2 * M_PI * Id + a * DI.adjoint().eval())); TIMER_OFF("Assemble T matrix"); // 2. Invert T using LU decomposition with full pivoting // This is a rank-revealing LU decomposition, this allows us // to test if T is invertible before attempting to invert it. TIMER_ON("Invert T matrix"); Eigen::FullPivLU<Eigen::MatrixXd> T_LU(fullPCMMatrix); if (!(T_LU.isInvertible())) PCMSOLVER_ERROR("T matrix is not invertible!", BOOST_CURRENT_FUNCTION); fullPCMMatrix = T_LU.inverse(); TIMER_OFF("Invert T matrix"); Eigen::FullPivLU<Eigen::MatrixXd> SI_LU(SI); if (!(SI_LU.isInvertible())) PCMSOLVER_ERROR("SI matrix is not invertible!", BOOST_CURRENT_FUNCTION); TIMER_ON("Assemble T^-1R matrix"); fullPCMMatrix *= ((2 * M_PI * Id - DE * a) - SE * SI_LU.inverse() * (2 * M_PI * Id - DI * a)); TIMER_OFF("Assemble T^-1R matrix"); return fullPCMMatrix; }
/******** Timer_SetPeriod ************************************************** // Set the interrupt period for Timer // Input: // timer - one of the Timer_T value ( Timer1A, Timer1B... ) // period - n of the 20ns time slices // Output: none // ------------------------------------------------------------------------*/ void Timer_SetPeriod ( Timer_T timer, unsigned long period ) { if ( TIMER_ON(timer/2) ) { // only can set period for timer that has been initialized TimerLoadSet ( Timer_Base[timer], get_half_timer(timer), period); } }
/******** Timer_GetTime **************************************************** // Get the current value in timer // Input: timer is one of the Timer_T value ( Timer1A, Timer1B... ) // Output: n of the 20ns time slices. // Return 0xFFFFFFFF if the timer is not initialized // ------------------------------------------------------------------------*/ unsigned long Timer_GetTime ( Timer_T timer ) { if ( TIMER_ON(timer/2) ) { return TimerValueGet( Timer_Base[timer], get_half_timer(timer) ); } else { return 0xFFFFFFFF; } }
/*! \brief Builds the **isotropic** IEFPCM matrix * \param[in] cav the discretized cavity * \param[in] gf_i Green's function inside the cavity * \param[in] epsilon permittivity outside the cavity * \return the \f$ \mathbf{K} = \mathbf{T}^{-1}\mathbf{R}\mathbf{A} \f$ matrix * * This function calculates the PCM matrix. We use the following definitions: * \f[ * \begin{align} * \mathbf{T} &= * \left(2\pi\frac{\varepsilon+1}{\varepsilon-1}\mathbf{I} - \mathbf{D}_\mathrm{i}\mathbf{A}\right)\mathbf{S}_\mathrm{i} \\ * \mathbf{R} &= * \left(2\pi\mathbf{A}^{-1} - \mathbf{D}_\mathrm{i}\right) * \end{align} * \f] * The matrix is not symmetrized and is not symmetry packed. */ inline Eigen::MatrixXd isotropicIEFMatrix(const Cavity & cav, const IGreensFunction & gf_i, double epsilon) { // The total size of the cavity size_t cavitySize = cav.size(); // The number of irreps in the group int nrBlocks = cav.pointGroup().nrIrrep(); // The size of the irreducible portion of the cavity int dimBlock = cav.irreducible_size(); // Compute SI and DI on the whole cavity, regardless of symmetry TIMER_ON("Computing SI"); Eigen::MatrixXd SI = gf_i.singleLayer(cav.elements()); TIMER_OFF("Computing SI"); TIMER_ON("Computing DI"); Eigen::MatrixXd DI = gf_i.doubleLayer(cav.elements()); TIMER_OFF("Computing DI"); // Perform symmetry blocking // If the group is C1 avoid symmetry blocking, we will just pack the fullPCMMatrix // into "block diagonal" when all other manipulations are done. if (cav.pointGroup().nrGenerators() != 0) { TIMER_ON("Symmetry blocking"); symmetryBlocking(DI, cavitySize, dimBlock, nrBlocks); symmetryBlocking(SI, cavitySize, dimBlock, nrBlocks); TIMER_OFF("Symmetry blocking"); } Eigen::MatrixXd a = cav.elementArea().asDiagonal(); Eigen::MatrixXd Id = Eigen::MatrixXd::Identity(cavitySize, cavitySize); // Tq = -Rv -> q = -(T^-1 * R)v = -Kv // T = (2 * M_PI * fact * aInv - DI) * a * SI; R = (2 * M_PI * aInv - DI) // fullPCMMatrix_ = K = T^-1 * R * a // 1. Form T double fact = (epsilon + 1.0)/(epsilon - 1.0); TIMER_ON("Assemble T matrix"); Eigen::MatrixXd fullPCMMatrix = (2 * M_PI * fact * Id - DI * a) * SI; TIMER_OFF("Assemble T matrix"); // 2. Invert T using LU decomposition with full pivoting // This is a rank-revealing LU decomposition, this allows us // to test if T is invertible before attempting to invert it. TIMER_ON("Invert T matrix"); Eigen::FullPivLU<Eigen::MatrixXd> T_LU(fullPCMMatrix); if (!(T_LU.isInvertible())) PCMSOLVER_ERROR("T matrix is not invertible!", BOOST_CURRENT_FUNCTION); fullPCMMatrix = T_LU.inverse(); TIMER_OFF("Invert T matrix"); // 3. Multiply T^-1 and R TIMER_ON("Assemble T^-1R matrix"); fullPCMMatrix *= (2 * M_PI * Id - DI * a); TIMER_OFF("Assemble T^-1R matrix"); return fullPCMMatrix; }
void CPCMSolver::buildSystemMatrix_impl(const ICavity & cavity, const IGreensFunction & gf_i, const IGreensFunction & gf_o, const IBoundaryIntegralOperator & op) { if (!isotropic_) PCMSOLVER_ERROR("C-PCM is defined only for isotropic environments!"); TIMER_ON("Computing S"); double epsilon = gf_o.permittivity(); S_ = op.computeS(cavity, gf_i); S_ /= (epsilon - 1.0) / (epsilon + correction_); // Get in Hermitian form if (hermitivitize_) utils::hermitivitize(S_); TIMER_OFF("Computing S"); // Symmetry-pack // The number of irreps in the group int nrBlocks = cavity.pointGroup().nrIrrep(); // The size of the irreducible portion of the cavity int dimBlock = cavity.irreducible_size(); utils::symmetryPacking(blockS_, S_, dimBlock, nrBlocks); built_ = true; }
/******** Timer_Init ******************************************************* // Initialize timer as either CCP, PWM or regular timer // Input: // timer - one of the Timer_T value ( Timer1A, Timer1B... ) // config - indicates the operational mode of the timer // xParameter - additional configure value, depends the mode of timer // tBool - if true then enable timer right away // Output: none // ------------------------------------------------------------------------*/ void Timer_Init ( Timer_T timer, Timer_Config config, unsigned long xParameter, tBoolean enable ) { unsigned long timer_base, timer_config; // only turn on system control for the same timer once if ( !(TIMER_ON(timer/2)) ) { SysCtlPeripheralEnable ( Timer_Periph[timer] ); TIMER_POWER_ON ( timer/2 ); } // disable timer before configure TimerDisable ( Timer_Base[timer], get_half_timer(timer) ); // determine what user want this timer to do switch ( config ) { case Timer_CCP: { if ( timer >= NUM_CCP ) { // return if the timer does not associate with a CCP pin return; } // initialize CCP pin GPIO_Init ( CCP_Port[timer], CCP_Pin[timer], 0, 0, CCP ); // initialize Timer if ( timer % 2 ) { // timer B, 16bit capture TimerConfigure ( Timer_Base[timer], TIMER_CFG_16_BIT_PAIR | TIMER_CFG_B_ONE_SHOT | TIMER_CFG_B_CAP_TIME ); TimerControlEvent ( Timer_Base[timer], TIMER_B, xParameter); Timer_IntFlag[timer] = TIMER_CAPB_EVENT; } else { // timer A, 16bit capture TimerConfigure ( Timer_Base[timer], TIMER_CFG_16_BIT_PAIR | TIMER_CFG_A_ONE_SHOT | TIMER_CFG_A_CAP_TIME ); TimerControlEvent ( Timer_Base[timer], TIMER_A, xParameter); Timer_IntFlag[timer] = TIMER_CAPA_EVENT; } break; } case Timer_PWM: { break; } case Timer_Periodic: { break; } case Timer_OneTime: { break; } default: { break; } } if ( enable ) { TimerEnable ( Timer_Base[timer], get_half_timer(timer) ); } }