#include"../common/define.h" #include"Assemble_Base.h" #include"Nedelec3D_Util.h" #include "../Eigen/SparseLU" #include #include #include #include #include #ifdef _WIN32 #include static void EnsureOutputDir(const std::string& dir) { _mkdir(dir.c_str()); } #else #include static void EnsureOutputDir(const std::string& dir) { mkdir(dir.c_str(), 0755); } #endif /* 2D_EigenMode */ void OpticsFEM_2D_EigenMode::Assemble() { //?????????? _mIsReal = _mMatLib->IsReal(); if (_mIsReal) { if (_mPhy->GetNbrPML() > 0) _mIsReal = false; } if (_mIsReal) { for (int i = 0; i < _mPhy->GetNbrPBC(); i++) { if (_mPhy->GetPBCPhi(i).imag()!= 0.0) { _mIsReal = false; break; } } } //????????? ???????? _mDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(); //???????? this->Assemble_WaveEquation(); if (_mIsReal) { _mA_real = Eigen::SparseMatrix(_mDof, _mDof); _mB_real = Eigen::SparseMatrix(_mDof, _mDof); _mA_real.setFromTriplets(_mTripleA_real.begin(), _mTripleA_real.end()); _mB_real.setFromTriplets(_mTripleB_real.begin(), _mTripleB_real.end()); } else { _mA_complex = Eigen::SparseMatrix, Eigen::RowMajor>(_mDof, _mDof); _mB_complex = Eigen::SparseMatrix, Eigen::RowMajor>(_mDof, _mDof); _mA_complex.setFromTriplets(_mTripleA_complex.begin(), _mTripleA_complex.end()); _mB_complex.setFromTriplets(_mTripleB_complex.begin(), _mTripleB_complex.end()); } //???????????????????????? if ((_mPhy->GetNbrPEC() + _mPhy->GetNbrPBCGroups() > 0)) { this->Assemble_PEC_PBC(); if (_mIsReal) { _mA_real = (_mP_real.transpose() * _mA_real) * _mP_real; _mB_real = (_mP_real.transpose() * _mB_real) * _mP_real; } else { _mA_complex = (_mP_complex.adjoint() * _mA_complex) * _mP_complex; _mB_complex = (_mP_complex.adjoint() * _mB_complex) * _mP_complex; } } else { if (_mIsReal) { _mP_real = Eigen::SparseMatrix(_mDof, _mDof); _mP_real.setIdentity(); } else { _mP_complex = Eigen::SparseMatrix, Eigen::RowMajor>(_mDof, _mDof); _mP_complex.setIdentity(); } } //????????????? /* double k0 = 2 * Pi / _mSolver->GetLda0(); double theta2 = k0 * k0 * _mSolver->GetSearchValue() * _mSolver->GetSearchValue(); if (_mIsReal) { Eigen::SparseMatrix tempA = _mA_real; _mA_real = _mB_real; _mB_real = (1 / theta2) * tempA + _mB_real; } else { Eigen::SparseMatrix, Eigen::RowMajor> tempA = _mA_complex; _mA_complex = _mB_complex; _mB_complex = (1 / theta2) * tempA + _mB_complex; } */ } void OpticsFEM_2D_EigenMode::Run() { double k0 = 2. * Pi / _mSolver->GetLda0(); double search = -k0 * k0 * _mSolver->GetSearchValue() * _mSolver->GetSearchValue(); if (_mIsReal) { _mSolver->GetRealFlag(_mIsReal); _mSolver->SetParam(&_mA_real, &_mB_real, &_mP_real, search); } else { _mSolver->GetRealFlag(_mIsReal); _mSolver->SetParam(&_mA_complex, &_mB_complex, &_mP_complex, search); } _mSolver->Run(&_mX, &_mLambda); } void OpticsFEM_2D_EigenMode::Post(string file) { _mPost->GetMesh(_mMesh); _mPost->GetSolver(_mSolver); _mPost->GetResult(&_mX, &_mLambda); _mPost->GetElectric(); _mPost->OutputData(file); } /* 2D_EigenFreq */ void OpticsFEM_2D_EigenFreq::Assemble() { //?????????? _mIsReal = _mMatLib->IsReal(); if (_mIsReal) { if (_mPhy->GetNbrPML() > 0) _mIsReal = false; } if (_mIsReal) { for (int i = 0; i < _mPhy->GetNbrPBC(); i++) { if (_mPhy->GetPBCPhi(i).imag()!= 0.0) { _mIsReal = false; break; } } } //???????? this->Assemble_WaveEquation(); //????????? if (_mIsReal) { int tempDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(); _mA_real = Eigen::SparseMatrix(tempDof, tempDof); _mB_real = Eigen::SparseMatrix(tempDof, tempDof); _mA_real.setFromTriplets(_mTripleA_real.begin(), _mTripleA_real.end()); _mB_real.setFromTriplets(_mTripleB_real.begin(), _mTripleB_real.end()); } else { int tempDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(); _mA_complex = Eigen::SparseMatrix, Eigen::RowMajor>(tempDof, tempDof); _mB_complex = Eigen::SparseMatrix, Eigen::RowMajor>(tempDof, tempDof); _mA_complex.setFromTriplets(_mTripleA_complex.begin(), _mTripleA_complex.end()); _mB_complex.setFromTriplets(_mTripleB_complex.begin(), _mTripleB_complex.end()); } //???????????????????????? _mElectricType = _mSolver->GetElectricType(); if ((_mPhy->GetNbrPEC() + _mPhy->GetNbrPBCGroups() > 0)) { this->Assemble_PEC_PBC(); } else { //??T???????? 0-Et 1-Ez 2-E if (_mIsReal) { std::vector> tempTriple; if (_mElectricType == 0) { _mDof = _mMesh->GetNbrEdge(); _mP_real = Eigen::SparseMatrix(_mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(), _mDof); for (int i = 0; i < _mDof; i++) { tempTriple.push_back(Eigen::Triplet(_mMesh->GetNbrVertex() + i, i, 1.)); } _mP_real.setFromTriplets(tempTriple.begin(), tempTriple.end()); } else if (_mElectricType == 1) { _mDof = _mMesh->GetNbrVertex(); _mP_real = Eigen::SparseMatrix(_mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(), _mDof); for (int i = 0; i < _mDof; i++) { tempTriple.push_back(Eigen::Triplet(i, i, 1.)); } _mP_real.setFromTriplets(tempTriple.begin(), tempTriple.end()); } else { _mDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(); _mP_real = Eigen::SparseMatrix(_mDof, _mDof); _mP_real.setIdentity(); } } else { std::vector>> tempTriple; if (_mElectricType == 0) { _mDof = _mMesh->GetNbrEdge(); _mP_complex = Eigen::SparseMatrix, Eigen::RowMajor>(_mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(), _mDof); for (int i = 0; i < _mDof; i++) { /*tempTriple.push_back(Eigen::Triplet>(_mMesh->GetNbrVertex() + i, _mMesh->GetNbrVertex() + i, 1.));*/ tempTriple.push_back(Eigen::Triplet>(_mMesh->GetNbrVertex() + i, i, 1.)); } _mP_complex.setFromTriplets(tempTriple.begin(), tempTriple.end()); } else if (_mElectricType == 1) { _mDof = _mMesh->GetNbrVertex(); _mP_complex = Eigen::SparseMatrix, Eigen::RowMajor>(_mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(), _mDof); for (int i = 0; i < _mDof; i++) { tempTriple.push_back(Eigen::Triplet>(i, i, 1.)); } _mP_complex.setFromTriplets(tempTriple.begin(), tempTriple.end()); } else { _mDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(); _mP_complex = Eigen::SparseMatrix, Eigen::RowMajor>(_mDof, _mDof); _mP_complex.setIdentity(); } } } if (_mIsReal) { _mA_real = (_mP_real.transpose() * _mA_real) * _mP_real; _mB_real = (_mP_real.transpose() * _mB_real) * _mP_real; } else { _mA_complex = (_mP_complex.adjoint() * _mA_complex) * _mP_complex; _mB_complex = (_mP_complex.adjoint() * _mB_complex) * _mP_complex; } } void OpticsFEM_2D_EigenFreq::Run() { double k0 = 2. * Pi / (c_const / _mSolver->GetSearchValue()); double search = k0 * k0; if (_mIsReal) { _mSolver->GetRealFlag(_mIsReal); _mSolver->SetParam(&_mA_real, &_mB_real, &_mP_real, search); } else { _mSolver->GetRealFlag(_mIsReal); _mSolver->SetParam(&_mA_complex, &_mB_complex, &_mP_complex, search); } _mSolver->Run(&_mX, &_mLambda); } void OpticsFEM_2D_EigenFreq::Post(string file) { _mPost->GetMesh(_mMesh); _mPost->GetSolver(_mSolver); _mPost->GetResult(&_mX, &_mLambda); _mPost->GetElectric(); _mPost->OutputData(file); } /* 2D_Scatter */ void OpticsFEM_2D_Scatter::Assemble() { _mIsReal = _mMatLib->IsReal(); if (_mIsReal) { if (_mPhy->GetNbrPML() > 0) _mIsReal = false; } if (_mIsReal) { if (_mPhy->GetNbrSBC() > 0) _mIsReal = false; } if (_mIsReal) { /*for (int i = 0; i < _mPhy->GetNbrElE(); i++) { Eigen::Vector3cd E0; _mPhy->GetE0(i, E0); for (int j = 0; j < 3; j++) { if (E0(j).imag() != 0) { _mIsReal = false; } } }*/ } if (_mIsReal) { for (int i = 0; i < _mPhy->GetNbrPBC(); i++) { if (_mPhy->GetPBCPhi(i).imag()!= 0.0) { _mIsReal = false; break; } } } if (_mIsReal) { if (_mPhy->GetBeamState() != 0) _mIsReal = false; } //??????????? this->Assemble_WaveEquation(); if (_mIsReal) { int tempDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(); _mB_real = Eigen::VectorXd::Zero(tempDof); } else { int tempDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(); _mB_complex = Eigen::VectorXcd::Zero(tempDof); } //SBC if (_mPhy->GetNbrSBC() > 0) this->Assemble_SBC(); //BELE if (_mPhy->GetNbrBELE()) this->Assemble_BELE(); if (_mIsReal) { int tempDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(); _mA_real = Eigen::SparseMatrix(tempDof, tempDof); _mA_real.setFromTriplets(_mTripleA_real.begin(), _mTripleA_real.end()); } else { int tempDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(); _mA_complex = Eigen::SparseMatrix, Eigen::RowMajor>(tempDof, tempDof); _mA_complex.setFromTriplets(_mTripleA_complex.begin(), _mTripleA_complex.end()); } //MAG if (_mPhy->GetNbrMAG()) this->Assemble_MAG(); //SCD if (_mPhy->GetNbrSCD()) this->Assemble_SCD(); //MPD if (_mPhy->GetNbrMPD()) this->Assemble_MPD(); //EPD if (_mPhy->GetNbrEPD()) this->Assemble_EPD(); //PEC+ELE this->Assemble_PEC_ELE(); //PBC if (_mPhy->GetNbrPBCGroups() > 0) { this->Assemble_PBC(); } else { if (_mIsReal) { std::vector> tempTriple; if (_mSolver->GetElectricType() == 0) { _mDof = _mMesh->GetNbrEdge(); _mP_real = Eigen::SparseMatrix(_mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(), _mDof); for (int i = 0; i < _mDof; i++) { tempTriple.push_back(Eigen::Triplet(_mMesh->GetNbrVertex() + i, i, 1.)); } _mP_real.setFromTriplets(tempTriple.begin(), tempTriple.end()); } else if (_mSolver->GetElectricType() == 1) { _mDof = _mMesh->GetNbrVertex(); _mP_real = Eigen::SparseMatrix(_mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(), _mDof); for (int i = 0; i < _mDof; i++) { tempTriple.push_back(Eigen::Triplet(i, i, 1.)); } _mP_real.setFromTriplets(tempTriple.begin(), tempTriple.end()); } else { _mDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(); _mP_real = Eigen::SparseMatrix(_mDof, _mDof); _mP_real.setIdentity(); } } else { std::vector>> tempTriple; if (_mSolver->GetElectricType() == 0) { _mDof = _mMesh->GetNbrEdge(); _mP_complex = Eigen::SparseMatrix, Eigen::RowMajor>(_mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(), _mDof); for (int i = 0; i < _mDof; i++) { tempTriple.push_back(Eigen::Triplet>(_mMesh->GetNbrVertex() + i, i, 1.)); } _mP_complex.setFromTriplets(tempTriple.begin(), tempTriple.end()); } else if (_mSolver->GetElectricType() == 1) { _mDof = _mMesh->GetNbrVertex(); _mP_complex = Eigen::SparseMatrix, Eigen::RowMajor>(_mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(), _mDof); for (int i = 0; i < _mDof; i++) { tempTriple.push_back(Eigen::Triplet>(i, i, 1.)); } _mP_complex.setFromTriplets(tempTriple.begin(), tempTriple.end()); } else { _mDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(); _mP_complex = Eigen::SparseMatrix, Eigen::RowMajor>(_mDof, _mDof); _mP_complex.setIdentity(); } } } if (_mIsReal) { _mA_real = (_mP_real.transpose() * _mA_real) * _mP_real; _mB_real = _mP_real.transpose() * _mB_real; } else { _mA_complex = (_mP_complex.adjoint() * _mA_complex) * _mP_complex; _mB_complex = _mP_complex.adjoint() * _mB_complex; } } void OpticsFEM_2D_Scatter::Run() { if (_mIsReal) { _mSolver->GetRealFlag(_mIsReal); _mSolver->SetParam(&_mA_real, &_mB_real, &_mP_real); } else { _mSolver->GetRealFlag(_mIsReal); _mSolver->SetParam(&_mA_complex, &_mB_complex, &_mP_complex); } _mSolver->Run(&_mX); } void OpticsFEM_2D_Scatter::Post(string file) { _mPost->GetMesh(_mMesh); _mPost->GetSolver(_mSolver); _mPost->GetPhy(_mPhy); _mPost->GetResult(&_mX); _mPost->GetElectric(); _mPost->OutputData(file); } /* 3D_EigenFreq - volume assembly_equ → sparse A (curl-curl) and B (eps mass) */ void OpticsFEM_3D_EigenFreq::Assemble() { const int elementOrder = _mPhy->GetElementOrder(); _mDof = Nedelec3D::globalDofCount(_mMesh, elementOrder); _mTripleA_real.clear(); _mTripleB_real.clear(); _mTripleA_complex.clear(); _mTripleB_complex.clear(); _mIsReal = _mMatLib->IsReal(); if (_mIsReal) { for (int i = 0; i < _mPhy->GetNbrPBC(); i++) { if (_mPhy->GetPBCPhi(i).imag()!= 0.0) { _mIsReal = false; break; } } } this->Assemble_WaveEquation(); if (_mIsReal) { _mA_real.resize(_mDof, _mDof); _mB_real.resize(_mDof, _mDof); _mA_real.setFromTriplets(_mTripleA_real.begin(), _mTripleA_real.end()); _mB_real.setFromTriplets(_mTripleB_real.begin(), _mTripleB_real.end()); } else { _mA_complex.resize(_mDof, _mDof); _mB_complex.resize(_mDof, _mDof); _mA_complex.setFromTriplets(_mTripleA_complex.begin(), _mTripleA_complex.end()); _mB_complex.setFromTriplets(_mTripleB_complex.begin(), _mTripleB_complex.end()); } if ((_mPhy->GetNbrPEC() + _mPhy->GetNbrPBCGroups() > 0)) { this->Assemble_PEC_PBC(); } else { if (_mIsReal) { _mP_real.resize(_mDof, _mDof); _mP_real.setIdentity(); } else { _mP_complex.resize(_mDof, _mDof); _mP_complex.setIdentity(); } } if (_mIsReal) { _mA_real = (_mP_real.transpose() * _mA_real) * _mP_real; _mB_real = (_mP_real.transpose() * _mB_real) * _mP_real; } else { _mA_complex = (_mP_complex.adjoint() * _mA_complex) * _mP_complex; _mB_complex = (_mP_complex.adjoint() * _mB_complex) * _mP_complex; } std::cout << "[OpticsFEM_3D_EigenFreq] Assemble done: DOF=" << _mDof << " nnz(A)=" << (_mIsReal ? _mA_real.nonZeros() : _mA_complex.nonZeros()) << " nnz(B)=" << (_mIsReal ? _mB_real.nonZeros() : _mB_complex.nonZeros()) << std::endl; } /* 3D_Scatter - 3D first-order Nedelec scattering (assembly_equ + assembly_out + assembly_inc) */ void OpticsFEM_3D_Scatter::Assemble() { _mFreeDofIndices.clear(); _mPortExtraDof = 0; _mIsReal = _mMatLib->IsReal(); if (_mIsReal) { if (_mPhy->GetNbrPML() > 0) _mIsReal = false; } if (_mIsReal) { if (_mPhy->GetNbrSBC() > 0) _mIsReal = false; } if (_mIsReal) { for (int i = 0; i < _mPhy->GetNbrPBC(); i++) { if (_mPhy->GetPBCPhi(i).imag() != 0.0) { _mIsReal = false; break; } } } if (_mIsReal && _mPhy->GetNbrElE() > 0) _mIsReal = false; if (_mIsReal && (_mPhy->GetNbrBELE() > 0 || _mPhy->GetNbrMAG() > 0 || _mPhy->GetNbrSCD() > 0 || _mPhy->GetNbrMPD() > 0 || _mPhy->GetNbrEPD() > 0)) _mIsReal = false; if (_mIsReal && _mPhy->HasNumericPort()) _mIsReal = false; const int elementOrder = _mPhy->GetElementOrder(); if (elementOrder == 2) { if (_mPhy->HasNumericPort()) { std::cerr << "[OpticsFEM] ElementOrder=2: Port not supported yet; skipped." << std::endl; } } _mDof = Nedelec3D::globalDofCount(_mMesh, elementOrder); this->Assemble_WaveEquation(); if (_mIsReal) _mB_real = Eigen::VectorXd::Zero(_mDof); else _mB_complex = Eigen::VectorXcd::Zero(_mDof); if (_mPhy->GetNbrSBC() > 0) this->Assemble_SBC(); if (_mPhy->GetNbrBELE() > 0) this->Assemble_BELE(); if (_mIsReal) { _mA_real = Eigen::SparseMatrix(_mDof, _mDof); _mA_real.setFromTriplets(_mTripleA_real.begin(), _mTripleA_real.end()); _mP_real = Eigen::SparseMatrix(_mDof, _mDof); _mP_real.setIdentity(); } else { _mA_complex = Eigen::SparseMatrix, Eigen::RowMajor>(_mDof, _mDof); _mA_complex.setFromTriplets(_mTripleA_complex.begin(), _mTripleA_complex.end()); _mP_complex = Eigen::SparseMatrix, Eigen::RowMajor>(_mDof, _mDof); _mP_complex.setIdentity(); } if (_mExportAsmDir.size() > 0) this->Test_OutputMatrix(_mExportAsmDir); if (elementOrder != 2 && _mPhy->HasNumericPort()) this->Assemble_Port(); if (_mPhy->GetNbrMAG() > 0) this->Assemble_MAG(); if (_mPhy->GetNbrSCD() > 0) this->Assemble_SCD(); if (_mPhy->GetNbrMPD() > 0) this->Assemble_MPD(); if (_mPhy->GetNbrEPD() > 0) this->Assemble_EPD(); if (_mPhy->GetNbrPEC() > 0 || _mPhy->GetNbrElE() > 0) this->Assemble_PEC_ELE(); if (_mPhy->GetNbrPBCGroups() > 0) this->Assemble_PBC(); if (_mIsReal) { _mA_real = (_mP_real.transpose() * _mA_real) * _mP_real; _mB_real = _mP_real.transpose() * _mB_real; } else { // After port PEC elimination A/B are already reduced; skip P projection. if (_mFreeDofIndices.empty()) { _mA_complex = (_mP_complex.adjoint() * _mA_complex) * _mP_complex; _mB_complex = _mP_complex.adjoint() * _mB_complex; } } } void OpticsFEM_3D_Scatter::Run() { if (_mIsReal) { _mSolver->GetRealFlag(_mIsReal); _mSolver->SetParam(&_mA_real, &_mB_real, &_mP_real); } else { _mSolver->GetRealFlag(_mIsReal); _mSolver->SetParam(&_mA_complex, &_mB_complex, &_mP_complex); } // PEC/ELE: after Dirichlet BC, external complexsolver CSR export fails; use SparseLU here only. const bool useBuiltInLu = (_mPhy->GetNbrPEC() > 0 || _mPhy->GetNbrElE() > 0 || _mPhy->HasNumericPort()); if (!_mIsReal && useBuiltInLu) { _mA_complex.makeCompressed(); Eigen::VectorXcd xReduced; if (_mPhy->HasNumericPort()) { std::cout << "[OpticsFEM_3D_Scatter] Reduced system" << " size=" << _mA_complex.rows() << " nnz=" << _mA_complex.nonZeros() << std::endl; if (_mFreeDofIndices.size() >= 2) { const size_t n = _mFreeDofIndices.size(); std::cout << "[OpticsFEM_3D_Scatter] Port free DOFs:" << " e1_idx=" << _mFreeDofIndices[n - 2] << " e2_idx=" << _mFreeDofIndices[n - 1] << std::endl; } } bool solved = false; { // MATLAB FemMatrixAssembly uses equilibrate(A) before '\'. // Ruiz infinity-norm scaling + iterative refinement stabilizes short-cavity ports. const int nA = static_cast(_mA_complex.rows()); Eigen::VectorXd Rsc = Eigen::VectorXd::Ones(nA); Eigen::VectorXd Csc = Eigen::VectorXd::Ones(nA); Eigen::SparseMatrix> Aeq = _mA_complex; for (int itEq = 0; itEq < 5; ++itEq) { Eigen::VectorXd rowInf = Eigen::VectorXd::Zero(nA); for (int k = 0; k < Aeq.outerSize(); ++k) for (Eigen::SparseMatrix>::InnerIterator it(Aeq, k); it; ++it) rowInf(it.row()) = std::max(rowInf(it.row()), std::abs(it.value())); for (int i = 0; i < nA; ++i) { const double s = (rowInf(i) > 0.0) ? (1.0 / std::sqrt(rowInf(i))) : 1.0; Rsc(i) *= s; } std::vector>> trips; trips.reserve(static_cast(Aeq.nonZeros())); for (int k = 0; k < Aeq.outerSize(); ++k) for (Eigen::SparseMatrix>::InnerIterator it(Aeq, k); it; ++it) trips.emplace_back(it.row(), it.col(), it.value() * (rowInf(it.row()) > 0.0 ? (1.0 / std::sqrt(rowInf(it.row()))) : 1.0)); Aeq.resize(nA, nA); Aeq.setFromTriplets(trips.begin(), trips.end()); Eigen::VectorXd colInf = Eigen::VectorXd::Zero(nA); for (int k = 0; k < Aeq.outerSize(); ++k) for (Eigen::SparseMatrix>::InnerIterator it(Aeq, k); it; ++it) colInf(it.col()) = std::max(colInf(it.col()), std::abs(it.value())); for (int i = 0; i < nA; ++i) { const double s = (colInf(i) > 0.0) ? (1.0 / std::sqrt(colInf(i))) : 1.0; Csc(i) *= s; } trips.clear(); for (int k = 0; k < Aeq.outerSize(); ++k) for (Eigen::SparseMatrix>::InnerIterator it(Aeq, k); it; ++it) trips.emplace_back(it.row(), it.col(), it.value() * (colInf(it.col()) > 0.0 ? (1.0 / std::sqrt(colInf(it.col()))) : 1.0)); Aeq.resize(nA, nA); Aeq.setFromTriplets(trips.begin(), trips.end()); } const Eigen::VectorXcd beq = Rsc.asDiagonal() * _mB_complex; Eigen::SparseLU>> lu; lu.compute(Aeq); if (lu.info() == Eigen::Success) { xReduced = Csc.asDiagonal() * lu.solve(beq); // Iterative refinement on the original (unscaled) system. for (int ir = 0; ir < 3; ++ir) { const Eigen::VectorXcd r = _mB_complex - _mA_complex * xReduced; Eigen::VectorXcd dr = Csc.asDiagonal() * lu.solve(Rsc.asDiagonal() * r); xReduced += dr; if (r.norm() < 1e-12 * (_mB_complex.norm() + 1e-30)) break; } solved = true; } } if (solved) { if (_mPhy->HasNumericPort()) { if (!_mFreeDofIndices.empty()) { _mX = Eigen::VectorXcd::Zero(_mDof + _mPortExtraDof); for (size_t i = 0; i < _mFreeDofIndices.size(); i++) _mX(_mFreeDofIndices[i]) = xReduced(static_cast(i)); } else _mX = xReduced; } else { _mX = Eigen::VectorXcd::Zero(_mP_complex.rows()); _mX = _mP_complex * xReduced; } const Eigen::VectorXcd r = _mA_complex * xReduced - _mB_complex; std::cout << "[OpticsFEM_3D_Scatter] SparseLU (PEC/ELE/Port)" << " |x|=" << _mX.norm() << " |r|=" << r.norm() << " |b|=" << _mB_complex.norm() << std::endl; } else { std::cout << "[OpticsFEM_3D_Scatter] SparseLU factorization failed" << std::endl; } return; } _mSolver->Run(&_mX); if (!_mIsReal && _mB_complex.size() > 0) { const double bNorm = _mB_complex.norm(); const double xNorm = _mX.norm(); if (bNorm > 0.0 && (!std::isfinite(_mX(0).real()) || xNorm < 1e-12 * bNorm)) { Eigen::SparseLU>> lu; lu.compute(_mA_complex); if (lu.info() == Eigen::Success) _mX = lu.solve(_mB_complex); } } } void OpticsFEM_3D_Scatter::Post(string file) { _mPost->GetMesh(_mMesh); _mPost->GetPhy(_mPhy); _mPost->GetResult(&_mX); _mPost->GetElectric(); if (_mPortExtraDof > 0 && _mX.size() >= _mDof + _mPortExtraDof) { std::cout << "[OpticsFEM_3D_Scatter] Port amplitudes:"; for (int i = 0; i < _mPortExtraDof; i++) std::cout << " e" << (i + 1) << "=" << _mX(_mDof + i); std::cout << std::endl; std::ofstream sOut(file + "/S_params.txt"); if (sOut.is_open()) { sOut << std::setprecision(12); const double pcoef = std::abs(_mPhy->GetNumericPort(0).powerCoef); for (int i = 0; i < _mPortExtraDof; i++) { const std::complex e = _mX(_mDof + i); sOut << "e" << (i + 1) << " " << e.real() << " " << e.imag(); if (i == 0 && pcoef > 0.0) sOut << " S11=" << (e.real() / pcoef) << " " << (e.imag() / pcoef); else if (i == 1 && pcoef > 0.0) sOut << " S21=" << (e.real() / pcoef) << " " << (e.imag() / pcoef); sOut << std::endl; } } } this->Test_OutputMatrix(file); _mPost->OutputData(file); std::cout << "[OpticsFEM] post to " << file << std::endl; } void OpticsFEM_3D_Scatter::Test_OutputMatrix(const std::string& outDir) { EnsureOutputDir(outDir); const std::string prefix = outDir + "/"; std::ofstream outAi(prefix + "Ai.txt"), outAj(prefix + "Aj.txt"), outAv(prefix + "Av.txt"); std::ofstream outBv_real(prefix + "Bv_real.txt"), outBv_imag(prefix + "Bv_imag.txt"); std::ofstream outX_real(prefix + "X_real.txt"), outX_imag(prefix + "X_imag.txt"); outAv << std::setprecision(12); if (_mIsReal) { for (int col = 0; col < _mA_real.outerSize(); col++) { for (Eigen::SparseMatrix::InnerIterator it(_mA_real, col); it; ++it) { outAi << it.row() << std::endl; outAj << it.col() << std::endl; outAv << it.value() << std::endl; } } for (int i = 0; i < _mB_real.size(); i++) outBv_real << _mB_real(i) << std::endl; for (int i = 0; i < _mX.size(); i++) outX_real << _mX(i).real() << std::endl; } else { // Export reduced system after PBC/PEC projection (matches MATLAB main_export OutFile). for (int col = 0; col < _mA_complex.outerSize(); col++) { for (Eigen::SparseMatrix, Eigen::RowMajor>::InnerIterator it(_mA_complex, col); it; ++it) { outAi << it.row() << std::endl; outAj << it.col() << std::endl; outAv << "(" << it.value().real() << "," << it.value().imag() << ")" << std::endl; } } for (int i = 0; i < _mB_complex.size(); i++) { outBv_real << _mB_complex(i).real() << std::endl; outBv_imag << _mB_complex(i).imag() << std::endl; } for (int i = 0; i < _mX.size(); i++) { outX_real << _mX(i).real() << std::endl; outX_imag << _mX(i).imag() << std::endl; } } } void OpticsFEM_3D_EigenFreq::Test_OutputMatrix(const std::string& outDir) { EnsureOutputDir(outDir); const std::string prefix = outDir + "/"; if (_mIsReal) { std::ofstream outAi(prefix + "Ai.txt"), outAj(prefix + "Aj.txt"), outAv(prefix + "Av.txt"); std::ofstream outBi(prefix + "Bi.txt"), outBj(prefix + "Bj.txt"), outBv(prefix + "Bv.txt"); for (const auto& t : _mTripleA_real) { outAi << t.row() << '\n'; outAj << t.col() << '\n'; outAv << t.value() << '\n'; } for (const auto& t : _mTripleB_real) { outBi << t.row() << '\n'; outBj << t.col() << '\n'; outBv << t.value() << '\n'; } std::cout << "[OpticsFEM_3D_EigenFreq] exported A/B COO to " << outDir << std::endl; } else { std::ofstream outAi(prefix + "Ai.txt"), outAj(prefix + "Aj.txt"); std::ofstream outAv_real(prefix + "Av_real.txt"), outAv_imag(prefix + "Av_imag.txt"); std::ofstream outBi(prefix + "Bi.txt"), outBj(prefix + "Bj.txt"); std::ofstream outBv_real(prefix + "Bv_real.txt"), outBv_imag(prefix + "Bv_imag.txt"); for (const auto& t : _mTripleA_complex) { outAi << t.row() << '\n'; outAj << t.col() << '\n'; outAv_real << t.value().real() << '\n'; outAv_imag << t.value().imag() << '\n'; } for (const auto& t : _mTripleB_complex) { outBi << t.row() << '\n'; outBj << t.col() << '\n'; outBv_real << t.value().real() << '\n'; outBv_imag << t.value().imag() << '\n'; } std::cout << "[OpticsFEM_3D_EigenFreq] exported A/B COO to " << outDir << std::endl; } } void OpticsFEM_3D_EigenFreq::Run() { double k0 = 2. * Pi / (c_const / _mSolver->GetSearchValue()); double search = k0 * k0; if (_mIsReal) { _mSolver->GetRealFlag(_mIsReal); _mSolver->SetParam(&_mA_real, &_mB_real, &_mP_real, search); } else { _mSolver->GetRealFlag(_mIsReal); _mSolver->SetParam(&_mA_complex, &_mB_complex, &_mP_complex, search); } _mSolver->Run(&_mX, &_mLambda); } void OpticsFEM_3D_EigenFreq::Post(string file) { _mPost->GetMesh(_mMesh); _mPost->GetSolver(_mSolver); _mPost->GetResult(&_mX, &_mLambda); _mPost->GetElectric(); _mPost->OutputData(file); std::cout << "[OpticsFEM_3D_EigenFreq] post to " << file << std::endl; } /* 3D_Scatter2 prism */ void OpticsFEM_3D_Scatter2::Assemble() { _mIsReal = _mMatLib->IsReal(); if (_mIsReal) { if (_mPhy->GetNbrPML() > 0) _mIsReal = false; } if (_mIsReal) { if (_mPhy->GetNbrSBC() > 0) _mIsReal = false; } if (_mIsReal) { /*for (int i = 0; i < _mPhy->GetNbrElE(); i++) { Eigen::Vector3cd E0; _mPhy->GetE0(i, E0); for (int j = 0; j < 3; j++) { if (E0(j).imag() != 0) { _mIsReal = false; } } }*/ } this->Assemble_WaveEquation(); //SBC //this->Assemble_SBC(); //Port (n+m)*(n+m) //this->Assemble_PortBC(); if (_mIsReal) _mA_real.setFromTriplets(_mTripleA_real.begin(), _mTripleA_real.end()); else _mA_complex.setFromTriplets(_mTripleA_complex.begin(), _mTripleA_complex.end()); //PEC+ELE //this->Assemble_PEC_ELE(); }