//------------------------------------------------------------------------------------------------------- // The MIT License (MIT) // // Copyright (c) 2021 Yoshiya Usui // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. //------------------------------------------------------------------------------------------------------- #include "Forward3DNonConformingHexaElement0thOrder.h" #include "MeshDataNonConformingHexaElement.h" #include "ResistivityBlock.h" #include "CommonParameters.h" #include "OutputFiles.h" #include "ObservedData.h" #include #include #include #include const double Forward3DNonConformingHexaElement0thOrder::m_eps = 1.0e-12; Forward3DNonConformingHexaElement0thOrder::Forward3DNonConformingHexaElement0thOrder(): Forward3D(), m_slaveDofToMasterDofAndFactors(NULL), m_hasMadeMapSlaveDofToMasterDofAndFactors(false), m_IDsAfterDegenerated2AfterConstrained(NULL), m_numOfEquationDegeneratedAndConstrained(0), m_solutionVectorDegeneratedAndConstrained(NULL), m_vectorMPCConstants(NULL) { //--------------------------------------------------------------------------- //--- Calculate integral points and weights of two point Gauss quadrature --- //--------------------------------------------------------------------------- int ip(0); for( int i = 0; i < m_numGauss; ++i ){ for( int j = 0; j < m_numGauss; ++j ){ for( int k = 0; k < m_numGauss; ++k ){ m_integralPointXi[ip] = CommonParameters::abscissas2Point[i]; m_integralPointEta[ip] = CommonParameters::abscissas2Point[j]; m_integralPointZeta[ip] = CommonParameters::abscissas2Point[k]; m_weights[ip] = CommonParameters::weights2Point[i] * CommonParameters::weights2Point[j] * CommonParameters::weights2Point[k]; ++ip; } } } // Array of reference coord xi values for each node m_xiAtNode[0] = -1.0; m_xiAtNode[1] = 1.0; m_xiAtNode[2] = 1.0; m_xiAtNode[3] = -1.0; m_xiAtNode[4] = -1.0; m_xiAtNode[5] = 1.0; m_xiAtNode[6] = 1.0; m_xiAtNode[7] = -1.0; // Array of reference coord eta values for each node m_etaAtNode[0] = -1.0; m_etaAtNode[1] = -1.0; m_etaAtNode[2] = 1.0; m_etaAtNode[3] = 1.0; m_etaAtNode[4] = -1.0; m_etaAtNode[5] = -1.0; m_etaAtNode[6] = 1.0; m_etaAtNode[7] = 1.0; // Array of reference coord zeta values for each node m_zetaAtNode[0] = -1.0; m_zetaAtNode[1] = -1.0; m_zetaAtNode[2] = -1.0; m_zetaAtNode[3] = -1.0; m_zetaAtNode[4] = 1.0; m_zetaAtNode[5] = 1.0; m_zetaAtNode[6] = 1.0; m_zetaAtNode[7] = 1.0; // Array of reference coord xi values for each edge m_xiAtEdge[0] = -9999.999; m_xiAtEdge[1] = -9999.999; m_xiAtEdge[2] = -9999.999; m_xiAtEdge[3] = -9999.999; m_xiAtEdge[4] = -1.0; m_xiAtEdge[5] = -1.0; m_xiAtEdge[6] = 1.0; m_xiAtEdge[7] = 1.0; m_xiAtEdge[8] = -1.0; m_xiAtEdge[9] = 1.0; m_xiAtEdge[10] = -1.0; m_xiAtEdge[11] = 1.0; // Array of reference coord eta values for each edge m_etaAtEdge[0] = -1.0; m_etaAtEdge[1] = 1.0; m_etaAtEdge[2] = -1.0; m_etaAtEdge[3] = 1.0; m_etaAtEdge[4] = -9999.999; m_etaAtEdge[5] = -9999.999; m_etaAtEdge[6] = -9999.999; m_etaAtEdge[7] = -9999.999; m_etaAtEdge[8] = -1.0; m_etaAtEdge[9] = -1.0; m_etaAtEdge[10] = 1.0; m_etaAtEdge[11] = 1.0; // Array of reference coord zeta values for each edge m_zetaAtEdge[0] = -1.0; m_zetaAtEdge[1] = -1.0; m_zetaAtEdge[2] = 1.0; m_zetaAtEdge[3] = 1.0; m_zetaAtEdge[4] = -1.0; m_zetaAtEdge[5] = 1.0; m_zetaAtEdge[6] = -1.0; m_zetaAtEdge[7] = 1.0; m_zetaAtEdge[8] = -9999.999; m_zetaAtEdge[9] = -9999.999; m_zetaAtEdge[10] = -9999.999; m_zetaAtEdge[11] = -9999.999; m_Fwd2DQuadrilateralElement[MeshData::ZXMinus] = new Forward2DNonConformingQuadrilateralElement0thOrderEdgeBased( MeshData::ZXMinus, CommonParameters::EX_POLARIZATION ); m_Fwd2DQuadrilateralElement[MeshData::ZXPlus ] = new Forward2DNonConformingQuadrilateralElement0thOrderEdgeBased( MeshData::ZXPlus, CommonParameters::EX_POLARIZATION ); m_Fwd2DQuadrilateralElement[MeshData::YZMinus] = new Forward2DNonConformingQuadrilateralElement0thOrderEdgeBased( MeshData::YZMinus, CommonParameters::EY_POLARIZATION ); m_Fwd2DQuadrilateralElement[MeshData::YZPlus ] = new Forward2DNonConformingQuadrilateralElement0thOrderEdgeBased( MeshData::YZPlus, CommonParameters::EY_POLARIZATION ); } //Destructer Forward3DNonConformingHexaElement0thOrder::~Forward3DNonConformingHexaElement0thOrder(){ if( m_slaveDofToMasterDofAndFactors != NULL ){ delete [] m_slaveDofToMasterDofAndFactors; m_slaveDofToMasterDofAndFactors = NULL; } if( m_IDsAfterDegenerated2AfterConstrained != NULL ){ delete [] m_IDsAfterDegenerated2AfterConstrained; m_IDsAfterDegenerated2AfterConstrained = NULL; } if( m_solutionVectorDegeneratedAndConstrained != NULL ){ delete [] m_solutionVectorDegeneratedAndConstrained; m_solutionVectorDegeneratedAndConstrained = NULL; } if( m_vectorMPCConstants != NULL ){ delete [] m_vectorMPCConstants; m_vectorMPCConstants = NULL; } } // Run 3D forward calculation void Forward3DNonConformingHexaElement0thOrder::forwardCalculation( const double freq, const int iPol ){ setFrequencyCurrent(freq); setPolarizationCurrent(iPol); setOrderOfFiniteElement( 0 ); if( m_matrix3DAnalysis.getNumRightHandSideVectors() != 1 ){ m_matrix3DAnalysis.reallocateMemoryForRightHandSideVectors(1); } const AnalysisControl* pAnalysisControl = AnalysisControl::getInstance(); if( pAnalysisControl->getBoundaryConditionBottom() != AnalysisControl::BOUNDARY_BOTTOM_PERFECT_CONDUCTOR ){ OutputFiles::m_logFile << "Error : When 0th order 3D edge-based element is used, electric field of the bottom must be zero !" << std::endl; exit(1); } OutputFiles::m_logFile << "# Start 3D forward calculation with the 0th order 3D edge-based element." << pAnalysisControl->outputElapsedTime() << std::endl; //----------------------------------------------------------------------------- //--- Set Number of equations and array converting local IDs to global ones --- //----------------------------------------------------------------------------- if( !m_hasSetIDsLocal2Global ){ calcArrayConvertLocalID2Global(); } if( !m_hasIDsGlobal2AfterDegenerated[iPol] ){ calcArrayConvertIDsGlobal2AfterDegenerated(); } if( !m_hasMadeMapSlaveDofToMasterDofAndFactors ){ makeMapSlaveDofToMasterDofAndFactors(); } OutputFiles::m_logFile << "# Number of equation = " << m_numOfEquation << ", Number of equation after degeneration = " << m_numOfEquationDegenerated << ", Number of equation after constraint = " << m_numOfEquationDegeneratedAndConstrained << std::endl; // Calculate array converting global edge IDs non-zero electric field values specified to the edges calcArrayConvertIDGlobal2NonZeroValues(); //----------------------------------------------------------------------- //--- Set matrix structure and analyze the structure by matrix solver --- //----------------------------------------------------------------------- if( !m_hasSetIDsLocal2Global ){ OutputFiles::m_logFile << "Error : m_hasSetIDsLocal2Global is NULL !!" << std::endl; exit(1); } if( !m_hasIDsGlobal2AfterDegenerated[iPol] ){ OutputFiles::m_logFile << "Error : m_hasIDsGlobal2AfterDegenerated[iPol] is NULL !!" << std::endl; exit(1); } if( !m_hasMatrixStructureSetAndAnalyzed ){ // If matrix structure has not been set yet, set matrix structure. OutputFiles::m_logFile << "# Set matrix structure. " << pAnalysisControl->outputElapsedTime() << std::endl; initializeSparseSolver(); m_matrix3DAnalysis.setDegreeOfEquation( m_numOfEquationDegeneratedAndConstrained ); setNonZeroStrucuture( m_matrix3DAnalysis ); //--- Convert the matrix from the triplet format to the CRS format if( m_matrix3DAnalysis.hasConvertedToCRSFormat() == false ){ m_matrix3DAnalysis.convertToCRSFormat(); } //--- Anaysis phase of matrix solver OutputFiles::m_logFile << "# Anaysis phase of matrix solver for 3D forward calculation." << " Polarization : " << iPol << ". " << pAnalysisControl->outputElapsedTime() << std::endl; m_matrix3DAnalysis.analysisPhaseMatrixSolver(); //---- Output memory required to caluculate the 2D analysis m_matrix3DAnalysis.writeMemoryRequiredByMatrixSolver(); m_hasMatrixStructureSetAndAnalyzed = true; } //------------------------------------------------------- //--- Set values of matrix and right hand side vector --- //------------------------------------------------------- OutputFiles::m_logFile << "# Set values of matrix and right hand side vector. " << pAnalysisControl->outputElapsedTime() << std::endl; m_matrix3DAnalysis.zeroClearNonZeroValues();// Zero clear matrix values m_matrix3DAnalysis.zeroClearRightHandSideVector();// Zero clear right hand side vector // Calculate MPC constants calcMPCConstants(); // Set non-zero values of matrix and right-hande side vector for forward calculation setNonZeroValues( m_matrix3DAnalysis ); //----------------------------------------------------- //--- Numrical factorization phase of matrix solver --- //----------------------------------------------------- OutputFiles::m_logFile << "# Numerical factorization phase of matrix solver for 3D forward calculation." << " Polarization : " << iPol << "." << pAnalysisControl->outputElapsedTime() << std::endl; m_matrix3DAnalysis.factorizationPhaseMatrixSolver();//Numrical factorization phase of matrix solver //------------------------------------ //--- Solve phase of matrix solver --- //------------------------------------ //std::complex* solutionConstrained = new std::complex[m_numOfEquationDegeneratedAndConstrained]; if( m_solutionVectorDegeneratedAndConstrained != NULL ){ delete [] m_solutionVectorDegeneratedAndConstrained; m_solutionVectorDegeneratedAndConstrained = NULL; } m_solutionVectorDegeneratedAndConstrained = new std::complex[m_numOfEquationDegeneratedAndConstrained]; OutputFiles::m_logFile << "# Solve phase of matrix solver for 3D forward calculation." << " Polarization : " << iPol << "." << pAnalysisControl->outputElapsedTime() << std::endl; m_matrix3DAnalysis.solvePhaseMatrixSolver( m_solutionVectorDegeneratedAndConstrained );//Solve phase of matrix solver #ifdef _DEBUG_WRITE for( int i = 0; i < m_numOfEquationDegeneratedAndConstrained; ++i ){ std::cout << "i m_solutionVectorDegeneratedAndConstrained : " << i << " " << m_solutionVectorDegeneratedAndConstrained[i] << std::endl; } #endif if( m_solution != NULL ){ delete [] m_solution; m_solution = NULL; } m_solution = new std::complex[ m_numOfEquation ]; bool* alreadyFound = new bool[ m_numOfEquation ]; for( int i = 0; i < m_numOfEquation; ++i ){ alreadyFound[i] = false; } const int nElem = m_MeshDataNonConformingHexaElement.getNumElemTotal(); for( int iElem = 0; iElem < nElem; ++iElem ){ for( int iEdge = 0; iEdge < 12; ++iEdge ){ const int iNum = m_IDsLocal2Global[iElem][iEdge]; if( !alreadyFound[iNum] ){ const int iNumDegenerated = m_IDsGlobal2AfterDegenerated[iPol][iNum]; if( iNumDegenerated == Forward3DNonConformingHexaElement0thOrder::DIRICHLET_BOUNDARY_ZERO_VALUE ){ m_solution[iNum] = std::complex( 0.0, 0.0 ); }else if( iNumDegenerated == Forward3DNonConformingHexaElement0thOrder::DIRICHLET_BOUNDARY_NONZERO_VALUE ){ m_solution[iNum] = m_globalID2NonZeroValues[iNum]; }else{ m_solution[iNum] = m_vectorMPCConstants[iNumDegenerated]; const std::vector< std::pair >& masterDofAndFactor = m_slaveDofToMasterDofAndFactors[iNumDegenerated]; for( std::vector< std::pair >::const_iterator itr = masterDofAndFactor.begin(); itr != masterDofAndFactor.end(); ++itr ){ const int dof = m_IDsAfterDegenerated2AfterConstrained[itr->first]; const std::complex factor = std::complex(itr->second, 0.0); m_solution[iNum] += m_solutionVectorDegeneratedAndConstrained[dof] * factor; } } alreadyFound[iNum] = true; } }// iEdge }// iElem //delete[] solutionConstrained; delete[] alreadyFound; #ifdef _DEBUG_WRITE for( int i = 0; i < m_numOfEquation; ++i ){ std::cout << "i m_solution : " << i << " " << m_solution[i] << std::endl; } #endif // Output EM field vectors if( pAnalysisControl->writeBinaryFormat() ){// BINARY outputResultToBinary( (ObservedData::getInstance())->getFreqIDs( freq ), iPol ); } else{// ASCII outputResultToVTK(); } } // Calculate X component of electric field std::complex Forward3DNonConformingHexaElement0thOrder::calcValueElectricFieldXDirection( const int iElem, const double xLocal, const double yLocal, const double zLocal ) const{ assert( m_solution != NULL ); assert( m_IDsLocal2Global != NULL ); Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( iElem, xLocal, yLocal, zLocal, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); std::complex val(0.0, 0.0); for( int i = 0; i < 12; ++i ){ const double length = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( iElem, i ); val += m_solution[ m_IDsLocal2Global[iElem][i] ] * std::complex( getShapeFuncX( xLocal, yLocal, zLocal, i, invJacobMat ) * length, 0.0 ); } return val; } // Calculate Y component of electric field std::complex Forward3DNonConformingHexaElement0thOrder::calcValueElectricFieldYDirection( const int iElem, const double xLocal, const double yLocal, const double zLocal ) const{ assert( m_solution != NULL ); assert( m_IDsLocal2Global != NULL ); Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( iElem, xLocal, yLocal, zLocal, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); std::complex val(0.0, 0.0); for( int i = 0; i < 12; ++i ){ const double length = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( iElem, i ); val += m_solution[ m_IDsLocal2Global[iElem][i] ] * std::complex( getShapeFuncY( xLocal, yLocal, zLocal, i, invJacobMat ) * length, 0.0 ); } return val; } // Calculate Z component of electric field std::complex Forward3DNonConformingHexaElement0thOrder::calcValueElectricFieldZDirection( const int iElem, const double xLocal, const double yLocal, const double zLocal ) const{ assert( m_solution != NULL ); assert( m_IDsLocal2Global != NULL ); Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( iElem, xLocal, yLocal, zLocal, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); std::complex val(0.0, 0.0); for( int i = 0; i < 12; ++i ){ const double length = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( iElem, i ); val += m_solution[ m_IDsLocal2Global[iElem][i] ] * std::complex( getShapeFuncZ( xLocal, yLocal, zLocal, i, invJacobMat ) * length, 0.0 ); } return val; } // Calculate Z component of rotated electric field std::complex Forward3DNonConformingHexaElement0thOrder::calcValueRotatedElectricFieldZDirection( const int iElem, const double xLocal, const double yLocal, const double zLocal ) const{ assert( m_solution != NULL ); assert( m_IDsLocal2Global != NULL ); Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( iElem, xLocal, yLocal, zLocal, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); std::complex val(0.0, 0.0); for( int i = 0; i < 12; ++i ){ const double length = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( iElem, i ); val += m_solution[ m_IDsLocal2Global[iElem][i] ] * std::complex( getShapeFuncRotatedZ( xLocal, yLocal, zLocal, i, invJacobMat ) * length, 0.0 ); } return val; } // Calculate X component of electric field only from the edges on the Earth's surface std::complex Forward3DNonConformingHexaElement0thOrder::calcValueRotatedElectricFieldNormal( const int iElem, const double xLocal, const double yLocal ) const{ assert( m_solution != NULL ); assert( m_IDsLocal2Global != NULL ); std::complex val(0.0, 0.0); Forward3D::Matrix2x2 jacobMat; const double detJacob = calc2DJacobianMatrixForEarthSurface( iElem, xLocal, yLocal, jacobMat ); Forward3D::Matrix2x2 invJacobMat; const double invDet = 1.0 / detJacob; invJacobMat.mat11 = jacobMat.mat22 * invDet; invJacobMat.mat12 = - jacobMat.mat12 * invDet; invJacobMat.mat21 = - jacobMat.mat21 * invDet; invJacobMat.mat22 = jacobMat.mat11 * invDet; const int iFace = 4; for( int i = 0; i < 4; ++i ){ const int iEdge = m_MeshDataNonConformingHexaElement.getEdgeIDLocalFromFaceIDLocal( iFace, i ); const double length = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( iElem, iEdge ); val += m_solution[ m_IDsLocal2Global[iElem][iEdge] ] * std::complex( get2DShapeFuncRotatedForEarthSurface(0.0, 0.0, i, invJacobMat) * length, 0.0 ); } return val; } // Calculate X component of electric field only from the edges on the Earth's surface std::complex Forward3DNonConformingHexaElement0thOrder::calcValueElectricFieldXDirectionFromEdgesOnEarthSurface( const int iElem, const int iFace, const double uCoord, const double vCoord ) const{ OutputFiles::m_logFile << "Error : " << __FUNCTION__ << " is not implemented" << std::endl; exit(1); } // Calculate Y component of electric field only from the edges on the Earth's surface std::complex Forward3DNonConformingHexaElement0thOrder::calcValueElectricFieldYDirectionFromEdgesOnEarthSurface( const int iElem, const int iFace, const double uCoord, const double vCoord ) const{ OutputFiles::m_logFile << "Error : " << __FUNCTION__ << " is not implemented" << std::endl; exit(1); } // Calculate tangential electric field directed to X from all edges of owner element std::complex Forward3DNonConformingHexaElement0thOrder::calcValueElectricFieldTangentialXFromAllEdges( const int iElem, const int iFace, const double xLocal, const double yLocal, const double zLocal ) const{ assert( m_solution != NULL ); assert( m_IDsLocal2Global != NULL ); Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( iElem, xLocal, yLocal, zLocal, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); std::complex val(0.0, 0.0); for( int i = 0; i < 12; ++i ){ const double length = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( iElem, i ); val += m_solution[ m_IDsLocal2Global[iElem][i] ] * std::complex( getShapeFuncX( xLocal, yLocal, zLocal, i, invJacobMat ) * length, 0.0 ); } const double dzdx = JacobMat.mat13 / JacobMat.mat11; const double factor = sqrt( 1.0 + dzdx * dzdx ); return val * std::complex(factor, 0.0); } // Calculate tangential electric field directed to Y from all edges of owner element std::complex Forward3DNonConformingHexaElement0thOrder::calcValueElectricFieldTangentialYFromAllEdges( const int iElem, const int iFace, const double xLocal, const double yLocal, const double zLocal ) const{ assert( m_solution != NULL ); assert( m_IDsLocal2Global != NULL ); Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( iElem, xLocal, yLocal, zLocal, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); std::complex val(0.0, 0.0); for( int i = 0; i < 12; ++i ){ const double length = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( iElem, i ); val += m_solution[ m_IDsLocal2Global[iElem][i] ] * std::complex( getShapeFuncY( xLocal, yLocal, zLocal, i, invJacobMat ) * length, 0.0 ); } const double dzdy = JacobMat.mat23 / JacobMat.mat22; const double factor = sqrt( 1.0 + dzdy * dzdy ); return val * std::complex(factor, 0.0); } // Calculate tangential electric field directed to X std::complex Forward3DNonConformingHexaElement0thOrder::calcValueElectricFieldTangentialX( const int iElem, const int iFace, const double uCoord, const double vCoord ) const{ OutputFiles::m_logFile << "Error : " << __FUNCTION__ << " is not implemented" << std::endl; exit(1); } // Calculate tangential electric field directed to Y std::complex Forward3DNonConformingHexaElement0thOrder::calcValueElectricFieldTangentialY( const int iElem, const int iFace, const double uCoord, const double vCoord ) const{ OutputFiles::m_logFile << "Error : " << __FUNCTION__ << " is not implemented" << std::endl; exit(1); } // Calculate X component of magnetic field std::complex Forward3DNonConformingHexaElement0thOrder::calcValueMagneticFieldXDirection( const int iElem, const double xLocal, const double yLocal, const double zLocal ) const{ assert( m_solution != NULL ); assert( m_IDsLocal2Global != NULL ); Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( iElem, xLocal, yLocal, zLocal, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); std::complex val(0.0, 0.0); for( int i = 0; i < 12; ++i ){ const double length = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( iElem, i ); val += m_solution[ m_IDsLocal2Global[iElem][i] ] * std::complex( getShapeFuncRotatedX( xLocal, yLocal, zLocal, i, invJacobMat ) * length, 0.0 ); } const double omega = 2.0 * CommonParameters::PI * getFrequencyCurrent();//Angular frequency val /= std::complex(0.0, omega * CommonParameters::mu); return val; } // Calculate Y component of magnetic field std::complex Forward3DNonConformingHexaElement0thOrder::calcValueMagneticFieldYDirection( const int iElem, const double xLocal, const double yLocal, const double zLocal ) const{ assert( m_solution != NULL ); assert( m_IDsLocal2Global != NULL ); Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( iElem, xLocal, yLocal, zLocal, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); std::complex val(0.0, 0.0); for( int i = 0; i < 12; ++i ){ const double length = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( iElem, i ); val += m_solution[ m_IDsLocal2Global[iElem][i] ] * std::complex( getShapeFuncRotatedY( xLocal, yLocal, zLocal, i, invJacobMat ) * length, 0.0 ); } const double omega = 2.0 * CommonParameters::PI * getFrequencyCurrent();//Angular frequency val /= std::complex(0.0, omega * CommonParameters::mu); return val; } // Calculate Z component of magnetic field std::complex Forward3DNonConformingHexaElement0thOrder::calcValueMagneticFieldZDirection( const int iElem, const double xLocal, const double yLocal, const double zLocal ) const{ const double omega = 2.0 * CommonParameters::PI * getFrequencyCurrent();//Angular frequency return calcValueRotatedElectricFieldZDirection( iElem, xLocal, yLocal, zLocal ) / std::complex(0.0, omega * CommonParameters::mu); } // Calculate interpolator vector of X component of electric field void Forward3DNonConformingHexaElement0thOrder::calcInterpolatorVectorOfElectricFieldXDirection( const int iElem, const double xLocal, const double yLocal, const double zLocal, const int irhs, const std::complex& factor ){ assert( m_solution != NULL ); assert( m_IDsLocal2Global != NULL ); Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( iElem, xLocal, yLocal, zLocal, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); const int iPol = getPolarizationCurrent(); for( int i = 0; i < 12; ++i ){ const int irow = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[iElem][i] ]; if( irow < 0 ){ continue; } const double length = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( iElem, i ); const std::complex val = std::complex( getShapeFuncX( xLocal, yLocal, zLocal, i, invJacobMat ) * length, 0.0 ) * factor; addValuesToRhsVectorsByConsideringMPC( irow, irhs, val ); } } // Calculate interpolator vector of Y component of electric field void Forward3DNonConformingHexaElement0thOrder::calcInterpolatorVectorOfElectricFieldYDirection( const int iElem, const double xLocal, const double yLocal, const double zLocal, const int irhs, const std::complex& factor ){ assert( m_solution != NULL ); assert( m_IDsLocal2Global != NULL ); Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( iElem, xLocal, yLocal, zLocal, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); const int iPol = getPolarizationCurrent(); for( int i = 0; i < 12; ++i ){ const int irow = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[iElem][i] ]; if( irow < 0 ){ continue; } const double length = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( iElem, i ); const std::complex val = std::complex( getShapeFuncY( xLocal, yLocal, zLocal, i, invJacobMat ) * length, 0.0 ) * factor; addValuesToRhsVectorsByConsideringMPC( irow, irhs, val ); } } // Calculate interpolator vector of Z component of electric field void Forward3DNonConformingHexaElement0thOrder::calcInterpolatorVectorOfElectricFieldZDirection( const int iElem, const double xLocal, const double yLocal, const double zLocal, const int irhs, const std::complex& factor ){ assert( m_solution != NULL ); assert( m_IDsLocal2Global != NULL ); Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( iElem, xLocal, yLocal, zLocal, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); const int iPol = getPolarizationCurrent(); for( int i = 0; i < 12; ++i ){ const int irow = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[iElem][i] ]; if( irow < 0 ){ continue; } const double length = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( iElem, i ); const std::complex val = std::complex( getShapeFuncZ( xLocal, yLocal, zLocal, i, invJacobMat ) * length, 0.0 ) * factor; addValuesToRhsVectorsByConsideringMPC( irow, irhs, val ); } } // Calculate interpolator vector of Z component of rotated electric field void Forward3DNonConformingHexaElement0thOrder::calcInterpolatorVectorOfRotatedElectricFieldZDirection( const int iElem, const double xLocal, const double yLocal, const double zLocal, const int irhs, const std::complex& factor ){ assert( m_solution != NULL ); assert( m_IDsLocal2Global != NULL ); Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( iElem, xLocal, yLocal, zLocal, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); const int iPol = getPolarizationCurrent(); for( int i = 0; i < 12; ++i ){ const int irow = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[iElem][i] ]; if( irow < 0 ){ continue; } const double length = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( iElem, i ); const std::complex val = std::complex( getShapeFuncRotatedZ( xLocal, yLocal, zLocal, i, invJacobMat ) * length, 0.0 ) * factor; addValuesToRhsVectorsByConsideringMPC( irow, irhs, val ); } } // Calculate interpolator vector of X component of electric field only from the edges on the Earth's surface void Forward3DNonConformingHexaElement0thOrder::calcInterpolatorVectorOfRotatedElectricFieldNormal( const int iElem, const double xLocal, const double yLocal, const int irhs, const std::complex& factor ){ assert( m_solution != NULL ); assert( m_IDsLocal2Global != NULL ); Forward3D::Matrix2x2 jacobMat; const double detJacob = calc2DJacobianMatrixForEarthSurface( iElem, xLocal, yLocal, jacobMat ); Forward3D::Matrix2x2 invJacobMat; const double invDet = 1.0 / detJacob; invJacobMat.mat11 = jacobMat.mat22 * invDet; invJacobMat.mat12 = - jacobMat.mat12 * invDet; invJacobMat.mat21 = - jacobMat.mat21 * invDet; invJacobMat.mat22 = jacobMat.mat11 * invDet; const int iPol = getPolarizationCurrent(); const int iFace = 4; for( int i = 0; i < 4; ++i ){ const int iEdge = m_MeshDataNonConformingHexaElement.getEdgeIDLocalFromFaceIDLocal( iFace, i ); const int irow = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[iElem][iEdge] ]; if( irow < 0 ){ continue; } const double length = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( iElem, iEdge ); //val += m_solution[ m_IDsLocal2Global[iElem][iEdge] ] * std::complex( get2DShapeFuncRotatedForEarthSurface(0.0, 0.0, i, invJacobMat) * length, 0.0 ); const std::complex val = std::complex( get2DShapeFuncRotatedForEarthSurface(0.0, 0.0, i, invJacobMat) * length, 0.0 ) * factor; addValuesToRhsVectorsByConsideringMPC( irow, irhs, val ); } } // Calculate interpolator vector of X component of electric field only from the edges on the Earth's surface void Forward3DNonConformingHexaElement0thOrder::calcInterpolatorVectorOfElectricFieldXDirectionFromEdgesOnEarthSurface( const int iElem, const int iFace, const double uCoord, const double vCoord, const int irhs, const std::complex& factor ){ OutputFiles::m_logFile << "Error : " << __FUNCTION__ << " is not implemented" << std::endl; exit(1); } // Calculate interpolator vector of Y component of electric field only from the edges on the Earth's surface void Forward3DNonConformingHexaElement0thOrder::calcInterpolatorVectorOfElectricFieldYDirectionFromEdgesOnEarthSurface( const int iElem, const int iFace, const double uCoord, const double vCoord, const int irhs, const std::complex& factor ){ OutputFiles::m_logFile << "Error : " << __FUNCTION__ << " is not implemented" << std::endl; exit(1); } // Calculate interpolator vector of tangential electric field directed to X from all edges void Forward3DNonConformingHexaElement0thOrder::calcInterpolatorVectorOfElectricFieldTangentialXFromAllEdges( const int iElem, const int iFace, const double xLocal, const double yLocal, const double zLocal, const int irhs, const std::complex& factor ){ assert( m_solution != NULL ); assert( m_IDsLocal2Global != NULL ); Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( iElem, xLocal, yLocal, zLocal, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); const double dzdx = JacobMat.mat13 / JacobMat.mat11; const double dLengdx = sqrt( 1.0 + dzdx * dzdx ); const int iPol = getPolarizationCurrent(); for( int i = 0; i < 12; ++i ){ const int irow = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[iElem][i] ]; if( irow < 0 ){ continue; } const double length = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( iElem, i ); const std::complex val = std::complex( getShapeFuncX( xLocal, yLocal, zLocal, i, invJacobMat ) * length * dLengdx, 0.0 ) * factor; addValuesToRhsVectorsByConsideringMPC( irow, irhs, val ); } } // Calculate interpolator vector of tangential electric field directed to Y from all edges void Forward3DNonConformingHexaElement0thOrder::calcInterpolatorVectorOfElectricFieldTangentialYFromAllEdges( const int iElem, const int iFace, const double xLocal, const double yLocal, const double zLocal, const int irhs, const std::complex& factor ){ assert( m_solution != NULL ); assert( m_IDsLocal2Global != NULL ); Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( iElem, xLocal, yLocal, zLocal, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); const double dzdy = JacobMat.mat23 / JacobMat.mat22; const double dLengdy = sqrt( 1.0 + dzdy * dzdy ); const int iPol = getPolarizationCurrent(); for( int i = 0; i < 12; ++i ){ const int irow = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[iElem][i] ]; if( irow < 0 ){ continue; } const double length = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( iElem, i ); const std::complex val = std::complex( getShapeFuncY( xLocal, yLocal, zLocal, i, invJacobMat ) * length * dLengdy, 0.0 ) * factor; addValuesToRhsVectorsByConsideringMPC( irow, irhs, val ); } } // Calculate interpolator vector of tangential electric field directed to X void Forward3DNonConformingHexaElement0thOrder::calcInterpolatorVectorOfElectricFieldTangentialX( const int iElem, const int iFace, const double uCoord, const double vCoord, const int irhs, const std::complex& factor ){ OutputFiles::m_logFile << "Error : " << __FUNCTION__ << " is not implemented" << std::endl; exit(1); } // Calculate interpolator vector of tangential electric field directed to Y void Forward3DNonConformingHexaElement0thOrder::calcInterpolatorVectorOfElectricFieldTangentialY( const int iElem, const int iFace, const double uCoord, const double vCoord, const int irhs, const std::complex& factor ){ OutputFiles::m_logFile << "Error : " << __FUNCTION__ << " is not implemented" << std::endl; exit(1); } // Calculate interpolator vector of X component of magnetic field void Forward3DNonConformingHexaElement0thOrder::calcInterpolatorVectorOfMagneticFieldXDirection( const int iElem, const double xLocal, const double yLocal, const double zLocal, const int irhs, const std::complex& factor ){ assert( m_solution != NULL ); assert( m_IDsLocal2Global != NULL ); Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( iElem, xLocal, yLocal, zLocal, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); const double omega = 2.0 * CommonParameters::PI * getFrequencyCurrent();//Angular frequency const int iPol = getPolarizationCurrent(); for( int i = 0; i < 12; ++i ){ const int irow = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[iElem][i] ]; if( irow < 0 ){ continue; } const double length = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( iElem, i ); const std::complex val = std::complex( getShapeFuncRotatedX( xLocal, yLocal, zLocal, i, invJacobMat ) * length, 0.0 ) * factor / std::complex(0.0, omega * CommonParameters::mu); addValuesToRhsVectorsByConsideringMPC( irow, irhs, val ); } } // Calculate interpolator vector of Y component of magnetic field void Forward3DNonConformingHexaElement0thOrder::calcInterpolatorVectorOfMagneticFieldYDirection( const int iElem, const double xLocal, const double yLocal, const double zLocal, const int irhs, const std::complex& factor ){ assert( m_solution != NULL ); assert( m_IDsLocal2Global != NULL ); Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( iElem, xLocal, yLocal, zLocal, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); const double omega = 2.0 * CommonParameters::PI * getFrequencyCurrent();//Angular frequency const int iPol = getPolarizationCurrent(); for( int i = 0; i < 12; ++i ){ const int irow = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[iElem][i] ]; if( irow < 0 ){ continue; } const double length = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( iElem, i ); const std::complex val = std::complex( getShapeFuncRotatedY( xLocal, yLocal, zLocal, i, invJacobMat ) * length, 0.0 ) * factor / std::complex(0.0, omega * CommonParameters::mu); addValuesToRhsVectorsByConsideringMPC( irow, irhs, val ); } } // Calculate interpolator vector of Z component of magnetic field void Forward3DNonConformingHexaElement0thOrder::calcInterpolatorVectorOfMagneticFieldZDirection( const int iElem, const double xLocal, const double yLocal, const double zLocal, const int irhs, const std::complex& factor ){ const double omega = 2.0 * CommonParameters::PI * getFrequencyCurrent();//Angular frequency const std::complex factorMod = factor / std::complex(0.0, omega * CommonParameters::mu); calcInterpolatorVectorOfRotatedElectricFieldZDirection( iElem, xLocal, yLocal, zLocal, irhs, factorMod ); } // Calculate interpolator vector of difference of voltage void Forward3DNonConformingHexaElement0thOrder::calcInterpolatorVectorOfVoltageDifference( const int nElem, const int* elememtsIncludingDipole, const CommonParameters::locationXY* localCoordinateValuesStartPoint, const CommonParameters::locationXY* localCoordinateValuesEndPoint, const int irhs ){ assert( m_IDsLocal2Global != NULL ); const int iPol = getPolarizationCurrent(); assert( m_IDsGlobal2AfterDegenerated[iPol] != NULL ); for( int ielem = 0; ielem < nElem; ++ielem ){ const int elemID = elememtsIncludingDipole[ielem]; const CommonParameters::locationXY startCoord = localCoordinateValuesStartPoint[ielem]; const CommonParameters::locationXY endCoord = localCoordinateValuesEndPoint[ielem]; bool rotationDirectionPlus = true; CommonParameters::locationXY sharedPoint = {0.0, 0.0}; const bool integralXCompFirst = doesIntegralXCompFirst( startCoord, endCoord, rotationDirectionPlus, sharedPoint ); const double lengthX = m_MeshDataNonConformingHexaElement.getEdgeLengthX(elemID); const double lengthY = m_MeshDataNonConformingHexaElement.getEdgeLengthY(elemID); Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( elemID, 0.0, 0.0, -1.0, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); const double dzdx = JacobMat.mat13 / JacobMat.mat11; const double factorX = sqrt( 1.0 + dzdx * dzdx ); const double dzdy = JacobMat.mat23 / JacobMat.mat22; const double factorY = sqrt( 1.0 + dzdy * dzdy ); const double xCoordDifferenceOfSegment = (endCoord.X - startCoord.X) * lengthX * 0.5; const double yCoordDifferenceOfSegment = (endCoord.Y - startCoord.Y) * lengthY * 0.5; if( integralXCompFirst ){ //voltageDifference -= std::complex( xCoordDifferenceOfSegment * factorX, 0.0 ) * calcValueElectricFieldTangentialXFromAllEdges( elemID, 4, startCoord.X, startCoord.Y, -1.0 );// Since electric field is constant on edges //voltageDifference -= std::complex( yCoordDifferenceOfSegment * factorY, 0.0 ) * calcValueElectricFieldTangentialYFromAllEdges( elemID, 4, endCoord.X, endCoord.Y, -1.0 );// Since electric field is constant on edges calcInterpolatorVectorOfElectricFieldTangentialXFromAllEdges( elemID, 4, startCoord.X, startCoord.Y, -1.0, irhs, std::complex( - xCoordDifferenceOfSegment * factorX, 0.0 ) ); calcInterpolatorVectorOfElectricFieldTangentialYFromAllEdges( elemID, 4, endCoord.X, endCoord.Y, -1.0, irhs, std::complex( - yCoordDifferenceOfSegment * factorY, 0.0 ) ); }else{ //voltageDifference -= std::complex( yCoordDifferenceOfSegment * factorY, 0.0 ) * calcValueElectricFieldTangentialYFromAllEdges( elemID, 4, startCoord.X, startCoord.Y, -1.0 );// Since electric field is constant on edges //voltageDifference -= std::complex( xCoordDifferenceOfSegment * factorX, 0.0 ) * calcValueElectricFieldTangentialXFromAllEdges( elemID, 4, endCoord.X, endCoord.Y, -1.0 );// Since electric field is constant on edges calcInterpolatorVectorOfElectricFieldTangentialYFromAllEdges( elemID, 4, startCoord.X, startCoord.Y, -1.0, irhs, std::complex( - yCoordDifferenceOfSegment * factorY, 0.0 ) ); calcInterpolatorVectorOfElectricFieldTangentialXFromAllEdges( elemID, 4, endCoord.X, endCoord.Y, -1.0, irhs, std::complex( - xCoordDifferenceOfSegment * factorX, 0.0 ) ); } const double areaFraction = 0.25 * fabs( (endCoord.X - startCoord.X) * (endCoord.Y - startCoord.Y) ); const double area = m_MeshDataNonConformingHexaElement.calcAreaOfFace(elemID, 4); double areaWithSign = 0.5 * area * areaFraction; if( !rotationDirectionPlus ){ areaWithSign *= -1.0; } //voltageDifference += calcValueRotatedElectricFieldNormal(elemID, 0.0, 0.0) * areaWithSign;// Since magnetic field is constant in the area calcInterpolatorVectorOfRotatedElectricFieldNormal( elemID, 0.0, 0.0, irhs, areaWithSign ); } } // Calculate interpolator vector of difference of voltage void Forward3DNonConformingHexaElement0thOrder::calcInterpolatorVectorOfVoltageDifference( const int nElem, const int* elememtsIncludingDipole, const int* const facesIncludingDipole, const CommonParameters::AreaCoords* const areaCoordValStartPoint, const CommonParameters::AreaCoords* const areaCoordValEndPoint, const int irhs ){ OutputFiles::m_logFile << "Error : " << __FUNCTION__ << " is not implemented" << std::endl; exit(1); } // Set non-zero strucuture of matrix for forward calculation void Forward3DNonConformingHexaElement0thOrder::setNonZeroStrucuture( ComplexSparseSquareSymmetricMatrix& matrix ){ const ResistivityBlock* const pResistivityBlock = ResistivityBlock::getInstance(); const int iPol = getPolarizationCurrent(); const int nElem = m_MeshDataNonConformingHexaElement.getNumElemTotal(); for( int iElem = 0; iElem < nElem; ++iElem ){ const int elemID = iElem; for( int iEdge1 = 0; iEdge1 < 12; ++iEdge1 ){ const int row = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[elemID][iEdge1] ]; if( row < 0 ){ continue; } for( int iEdge2 = 0; iEdge2 < 12; ++iEdge2 ){ const int col = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[elemID][iEdge2] ]; if( col < 0 ){ continue; } std::vector< std::pair >& rowMasters= m_slaveDofToMasterDofAndFactors[row]; std::vector< std::pair >& colMasters= m_slaveDofToMasterDofAndFactors[col]; for( std::vector< std::pair >::const_iterator itrRow = rowMasters.begin(); itrRow != rowMasters.end(); ++itrRow ){ const int rowMod = m_IDsAfterDegenerated2AfterConstrained[itrRow->first]; for( std::vector< std::pair >::const_iterator itrCol = colMasters.begin(); itrCol != colMasters.end(); ++itrCol ){ const int colMod = m_IDsAfterDegenerated2AfterConstrained[itrCol->first]; if( colMod >= rowMod ){// Store only upper triangle part matrix.setStructureByTripletFormat( rowMod, colMod ); } } } }// iEdge2 }// iEdge1 } } // Set non-zero values of matrix and right-hande side vector for forward calculation void Forward3DNonConformingHexaElement0thOrder::setNonZeroValues( ComplexSparseSquareSymmetricMatrix& matrix ){ #ifdef _DEBUG_WRITE ComplexSparseSquareSymmetricMatrix matrixTemp(m_numOfEquationDegenerated); #endif const ResistivityBlock* const pResistivityBlock = ResistivityBlock::getInstance(); const int iPol = getPolarizationCurrent(); const double freq = getFrequencyCurrent(); const double ln10 = 2.30258509299405; const double omega = 2.0 * CommonParameters::PI * freq;//Angular frequency const int nElem = m_MeshDataNonConformingHexaElement.getNumElemTotal(); for( int iElem = 0; iElem < nElem; ++iElem ){ const int elemID = iElem; //--- Calculate omega * mu * sigma const double sigma = pResistivityBlock->getConductivityValuesFromElemID(elemID); const double factor1 = 1.0; const std::complex factor2 = std::complex( 0.0, omega * CommonParameters::mu * sigma );// exp(-i*omega*t) form double length[12]; for( int i = 0; i < 12; ++i ){ length[i] = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( elemID, i ); } for( int iEdge1 = 0; iEdge1 < 12; ++iEdge1 ){ const int row = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[elemID][iEdge1] ]; if( row < 0 ){ continue; } for( int iEdge2 = 0; iEdge2 < 12; ++iEdge2 ){ const int col = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[elemID][iEdge2] ]; if( col <= Forward3DNonConformingHexaElement0thOrder::DIRICHLET_BOUNDARY_ZERO_VALUE ){ continue; } double integral1 = 0.0; double integral2 = 0.0; for( int ip = 0; ip < m_numIntegralPoints; ++ip ){ const double xi = m_integralPointXi[ip]; const double eta = m_integralPointEta[ip]; const double zeta = m_integralPointZeta[ip]; Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( elemID, xi, eta, zeta, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); integral1 += ( getShapeFuncRotatedX( xi, eta, zeta, iEdge1, invJacobMat ) * getShapeFuncRotatedX( xi, eta, zeta, iEdge2, invJacobMat ) + getShapeFuncRotatedY( xi, eta, zeta, iEdge1, invJacobMat ) * getShapeFuncRotatedY( xi, eta, zeta, iEdge2, invJacobMat ) + getShapeFuncRotatedZ( xi, eta, zeta, iEdge1, invJacobMat ) * getShapeFuncRotatedZ( xi, eta, zeta, iEdge2, invJacobMat ) ) * detJacob * m_weights[ip]; integral2 += ( getShapeFuncX( xi, eta, zeta, iEdge1, invJacobMat ) * getShapeFuncX( xi, eta, zeta, iEdge2, invJacobMat ) + getShapeFuncY( xi, eta, zeta, iEdge1, invJacobMat ) * getShapeFuncY( xi, eta, zeta, iEdge2, invJacobMat ) + getShapeFuncZ( xi, eta, zeta, iEdge1, invJacobMat ) * getShapeFuncZ( xi, eta, zeta, iEdge2, invJacobMat ) ) * detJacob * m_weights[ip]; } integral1 *= length[iEdge1] * length[iEdge2]; integral2 *= length[iEdge1] * length[iEdge2]; const std::complex val = std::complex( integral1 * factor1 , 0.0 ) - std::complex( integral2, 0.0 ) * factor2;// exp(-i*omega*t) form //#ifdef _DEBUG_WRITE // if( col == Forward3DNonConformingHexaElement0thOrder::DIRICHLET_BOUNDARY_NONZERO_VALUE ){ // matrixTemp.addRightHandSideVector( row, -val * m_globalID2NonZeroValues[ m_IDsLocal2Global[elemID][iEdge2] ] );// Add to right hand side vector // }else if( col >= row ){// Store only upper triangle part // matrixTemp.setStructureAndAddValueByTripletFormat( row, col, val );// Add to matrix // } //#endif const std::vector< std::pair >& rowMasters= m_slaveDofToMasterDofAndFactors[row]; for( std::vector< std::pair >::const_iterator itrRow = rowMasters.begin(); itrRow != rowMasters.end(); ++itrRow ){ const int rowMod = m_IDsAfterDegenerated2AfterConstrained[itrRow->first]; const std::complex valMod = val * std::complex(itrRow->second, 0.0); if( col == Forward3DNonConformingHexaElement0thOrder::DIRICHLET_BOUNDARY_NONZERO_VALUE ){ // Add to right hand side vector matrix.addRightHandSideVector( rowMod, -valMod * m_globalID2NonZeroValues[ m_IDsLocal2Global[elemID][iEdge2] ] ); }else{ // Add to right hand side vector corresponding to MPC constants matrix.addRightHandSideVector( rowMod, valMod * m_vectorMPCConstants[col] ); const std::vector< std::pair >& colMasters= m_slaveDofToMasterDofAndFactors[col]; for( std::vector< std::pair >::const_iterator itrCol = colMasters.begin(); itrCol != colMasters.end(); ++itrCol ){ const int colMod = m_IDsAfterDegenerated2AfterConstrained[itrCol->first]; const std::complex valModMod = valMod * std::complex(itrCol->second, 0.0); if( colMod >= rowMod ){// Store only upper triangle part const int loc = matrix.checkAndGetLocationNonZeroValue( rowMod, colMod ); matrix.addNonZeroValuesWithoutSearchingLocation( loc, valModMod );// Add to matrix } } } } }// iEdge2 }// iEdge1 } #ifdef _DEBUG_WRITE std::cout << "matrix" << std::endl; matrix.debugWriteMatrix(); matrix.debugWriteRightHandSide(); #endif //#ifdef _DEBUG_WRITE // matrixTemp.transformationByConstraintMatrix( m_numOfEquationDegeneratedAndConstrained, m_transposedConstraintMatrix ); // matrixTemp.convertToCRSFormat(); // std::cout << "matrixTemp" << std::endl; // matrixTemp.debugWriteMatrix(); // matrixTemp.debugWriteRightHandSide(); //#endif } // Calculate vector x of the reciprocity algorithm of Rodi (1976) void Forward3DNonConformingHexaElement0thOrder::calVectorXOfReciprocityAlgorithm( const std::complex* const vecIn, const int blkID, std::complex* const vecOut, std::vector& nonZeroRows ){ const ResistivityBlock* const pResistivityBlock = ResistivityBlock::getInstance(); if( pResistivityBlock->isFixedResistivityValue(blkID) ){ return; } const int iPol = getPolarizationCurrent(); const double freq = getFrequencyCurrent(); const double ln10 = 2.30258509299405; const double omega = 2.0 * CommonParameters::PI * freq;//Angular frequency const std::vector< std::pair >& mdl2Elem = pResistivityBlock->getBlockID2Elements(blkID); const int nElem = static_cast( mdl2Elem.size() ); for( int iElem = 0; iElem < nElem; ++iElem ){ // [Attention] : You must use elemID instead of iElem from this line const int elemID = mdl2Elem[iElem].first; //----- debug >>>>> #ifdef _DEBUG_WRITE std::cout << "blkID iElem elemID = " << blkID << " " << iElem << " " << elemID << std::endl; #endif //----- debug <<<<< //--- Calculate omega * mu * sigma const double sigma = pResistivityBlock->getConductivityValuesFromElemID(elemID); const double factor1 = 0.0; const std::complex factor2 = std::complex(0.0, - omega * CommonParameters::mu * sigma * ln10 * mdl2Elem[iElem].second);// exp(-i*omega*t) form double length[12]; for( int i = 0; i < 12; ++i ){ length[i] = m_MeshDataNonConformingHexaElement.calcEdgeLengthFromElementAndEdge( elemID, i ); } for( int iEdge1 = 0; iEdge1 < 12; ++iEdge1 ){ const int row = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[elemID][iEdge1] ]; if( row < 0 ){ continue; } for( int iEdge2 = 0; iEdge2 < 12; ++iEdge2 ){ const int col = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[elemID][iEdge2] ]; if( col <= Forward3DNonConformingHexaElement0thOrder::DIRICHLET_BOUNDARY_ZERO_VALUE ){ continue; } double integral1 = 0.0; double integral2 = 0.0; for( int ip = 0; ip < m_numIntegralPoints; ++ip ){ const double xi = m_integralPointXi[ip]; const double eta = m_integralPointEta[ip]; const double zeta = m_integralPointZeta[ip]; Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( elemID, xi, eta, zeta, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); integral1 += ( getShapeFuncRotatedX( xi, eta, zeta, iEdge1, invJacobMat ) * getShapeFuncRotatedX( xi, eta, zeta, iEdge2, invJacobMat ) + getShapeFuncRotatedY( xi, eta, zeta, iEdge1, invJacobMat ) * getShapeFuncRotatedY( xi, eta, zeta, iEdge2, invJacobMat ) + getShapeFuncRotatedZ( xi, eta, zeta, iEdge1, invJacobMat ) * getShapeFuncRotatedZ( xi, eta, zeta, iEdge2, invJacobMat ) ) * detJacob * m_weights[ip]; integral2 += ( getShapeFuncX( xi, eta, zeta, iEdge1, invJacobMat ) * getShapeFuncX( xi, eta, zeta, iEdge2, invJacobMat ) + getShapeFuncY( xi, eta, zeta, iEdge1, invJacobMat ) * getShapeFuncY( xi, eta, zeta, iEdge2, invJacobMat ) + getShapeFuncZ( xi, eta, zeta, iEdge1, invJacobMat ) * getShapeFuncZ( xi, eta, zeta, iEdge2, invJacobMat ) ) * detJacob * m_weights[ip]; } integral1 *= length[iEdge1] * length[iEdge2]; integral2 *= length[iEdge1] * length[iEdge2]; const std::complex val = std::complex( integral1 * factor1 , 0.0 ) - std::complex( integral2, 0.0 ) * factor2;// exp(-i*omega*t) form //#ifdef _DEBUG_WRITE // if( col == Forward3DNonConformingHexaElement0thOrder::DIRICHLET_BOUNDARY_NONZERO_VALUE ){ // matrixTemp.addRightHandSideVector( row, -val * m_globalID2NonZeroValues[ m_IDsLocal2Global[elemID][iEdge2] ] );// Add to right hand side vector // }else if( col >= row ){// Store only upper triangle part // matrixTemp.setStructureAndAddValueByTripletFormat( row, col, val );// Add to matrix // } //#endif const std::vector< std::pair >& rowMasters= m_slaveDofToMasterDofAndFactors[row]; for( std::vector< std::pair >::const_iterator itrRow = rowMasters.begin(); itrRow != rowMasters.end(); ++itrRow ){ const int rowMod = m_IDsAfterDegenerated2AfterConstrained[itrRow->first]; const std::complex valMod = val * std::complex(itrRow->second, 0.0); if( col == Forward3DNonConformingHexaElement0thOrder::DIRICHLET_BOUNDARY_NONZERO_VALUE ){ nonZeroRows.push_back(rowMod); // Add to right hand side vector vecOut[rowMod] -= valMod * m_globalID2NonZeroValues[ m_IDsLocal2Global[elemID][iEdge2] ]; }else{ nonZeroRows.push_back(rowMod); // Add to right hand side vector corresponding to MPC constants vecOut[rowMod] += valMod * m_vectorMPCConstants[col]; const std::vector< std::pair >& colMasters= m_slaveDofToMasterDofAndFactors[col]; for( std::vector< std::pair >::const_iterator itrCol = colMasters.begin(); itrCol != colMasters.end(); ++itrCol ){ const int colMod = m_IDsAfterDegenerated2AfterConstrained[itrCol->first]; const std::complex valModMod = valMod * std::complex(itrCol->second, 0.0); vecOut[rowMod] -= valModMod * vecIn[colMod]; } } } }// iEdge2 }// iEdge1 } std::sort(nonZeroRows.begin(), nonZeroRows.end()); nonZeroRows.erase( std::unique( nonZeroRows.begin(), nonZeroRows.end() ), nonZeroRows.end() ); } // Copy solution vector degenerated void Forward3DNonConformingHexaElement0thOrder::copySolutionVectorDegenerated( const int iPol, std::complex* solutionVector ) const{ for( int i = 0; i < m_numOfEquationDegeneratedAndConstrained; ++i ){ solutionVector[i] = m_solutionVectorDegeneratedAndConstrained[i]; } } // Call function inputMeshData of the class MeshData void Forward3DNonConformingHexaElement0thOrder::callInputMeshData(){ m_MeshDataNonConformingHexaElement.inputMeshData(); } // Get pointer to the class MeshData const MeshData* Forward3DNonConformingHexaElement0thOrder::getPointerToMeshData() const{ return static_cast( &m_MeshDataNonConformingHexaElement ) ; } // Get pointer to the class MeshDataNonConformingHexaElement const MeshDataNonConformingHexaElement* Forward3DNonConformingHexaElement0thOrder::getPointerToMeshDataNonConformingHexaElement() const{ return &m_MeshDataNonConformingHexaElement; } // Calculate difference of voltage for brick element std::complex Forward3DNonConformingHexaElement0thOrder::calcVoltageDifference( const int nElem, const int* elememtsIncludingDipole, const CommonParameters::locationXY* localCoordinateValuesStartPoint, const CommonParameters::locationXY* localCoordinateValuesEndPoint ) const{ std::complex voltageDifference = std::complex(0.0, 0.0); for( int ielem = 0; ielem < nElem; ++ielem ){ const int elemID = elememtsIncludingDipole[ielem]; const CommonParameters::locationXY startCoord = localCoordinateValuesStartPoint[ielem]; const CommonParameters::locationXY endCoord = localCoordinateValuesEndPoint[ielem]; bool rotationDirectionPlus = true; CommonParameters::locationXY sharedPoint = {0.0, 0.0}; const bool integralXCompFirst = doesIntegralXCompFirst( startCoord, endCoord, rotationDirectionPlus, sharedPoint ); const double lengthX = m_MeshDataNonConformingHexaElement.getEdgeLengthX(elemID); const double lengthY = m_MeshDataNonConformingHexaElement.getEdgeLengthY(elemID); Forward3D::Matrix3x3 JacobMat; const double detJacob = calcJacobianMatrix( elemID, 0.0, 0.0, -1.0, JacobMat ); Forward3D::Matrix3x3 invJacobMat; calcInverseOfJacobianMatrix( JacobMat, detJacob, invJacobMat ); const double dzdx = JacobMat.mat13 / JacobMat.mat11; const double factorX = sqrt( 1.0 + dzdx * dzdx ); const double dzdy = JacobMat.mat23 / JacobMat.mat22; const double factorY = sqrt( 1.0 + dzdy * dzdy ); const double xCoordDifferenceOfSegment = (endCoord.X - startCoord.X) * lengthX * 0.5; const double yCoordDifferenceOfSegment = (endCoord.Y - startCoord.Y) * lengthY * 0.5; if( integralXCompFirst ){ voltageDifference -= std::complex( xCoordDifferenceOfSegment * factorX, 0.0 ) * calcValueElectricFieldTangentialXFromAllEdges( elemID, 4, startCoord.X, startCoord.Y, -1.0 );// Since electric field is constant on edges voltageDifference -= std::complex( yCoordDifferenceOfSegment * factorY, 0.0 ) * calcValueElectricFieldTangentialYFromAllEdges( elemID, 4, endCoord.X, endCoord.Y, -1.0 );// Since electric field is constant on edges }else{ voltageDifference -= std::complex( yCoordDifferenceOfSegment * factorY, 0.0 ) * calcValueElectricFieldTangentialYFromAllEdges( elemID, 4, startCoord.X, startCoord.Y, -1.0 );// Since electric field is constant on edges voltageDifference -= std::complex( xCoordDifferenceOfSegment * factorX, 0.0 ) * calcValueElectricFieldTangentialXFromAllEdges( elemID, 4, endCoord.X, endCoord.Y, -1.0 );// Since electric field is constant on edges } #ifdef _DEBUG_WRITE std::cout << "voltageDifference : " << voltageDifference << std::endl; #endif const double areaFraction = 0.25 * fabs( (endCoord.X - startCoord.X) * (endCoord.Y - startCoord.Y) ); const double area = m_MeshDataNonConformingHexaElement.calcAreaOfFace(elemID, 4); double areaWithSign = 0.5 * area * areaFraction; if( !rotationDirectionPlus ){ areaWithSign *= -1.0; } #ifdef _DEBUG_WRITE const std::complex tmp1 = calcValueRotatedElectricFieldNormal(elemID, 0.0, 0.0); const std::complex tmp2 = calcValueRotatedElectricFieldZDirection(elemID, 0.0, 0.0, -1.0); #endif voltageDifference += calcValueRotatedElectricFieldNormal(elemID, 0.0, 0.0) * areaWithSign;// Since magnetic field is constant in the area #ifdef _DEBUG_WRITE std::cout << "areaWithSign calcValueRotatedElectricFieldZDirection : " << areaWithSign << " " << tmp1 << std::endl; std::cout << "voltageDifference total : " << voltageDifference << std::endl; #endif } return voltageDifference; } // Calculate difference of voltage for tetra element std::complex Forward3DNonConformingHexaElement0thOrder::calcVoltageDifference( const int nElem, const int* const elememtsIncludingDipole, const int* const facesIncludingDipole, const CommonParameters::AreaCoords* const areaCoordValStartPoint, const CommonParameters::AreaCoords* const areaCoordValEndPoint ) const{ OutputFiles::m_logFile << "Error : " << __FUNCTION__ << " is not implemented" << std::endl; exit(1); } // Get total number of equations finally solved int Forward3DNonConformingHexaElement0thOrder::getNumOfEquationFinallySolved() const{ return m_numOfEquationDegeneratedAndConstrained; } // Calculate array converting local IDs to global ones void Forward3DNonConformingHexaElement0thOrder::calcArrayConvertLocalID2Global(){ typedef std::pair< int, int > NodeIDPair; typedef std::pair< int, int > ElemAndEdgeID; typedef std::pair< NodeIDPair, ElemAndEdgeID > InputedDataType; std::vector< InputedDataType > workVector; const int nElem = m_MeshDataNonConformingHexaElement.getNumElemTotal(); for( int iElem = 0; iElem < nElem; ++iElem ){ for( int iEdge = 0; iEdge < 12; ++iEdge ){ const int nodeID0 = m_MeshDataNonConformingHexaElement.getNodeIDGlobalFromElementAndEdge( iElem, iEdge, 0 ); const int nodeID1 = m_MeshDataNonConformingHexaElement.getNodeIDGlobalFromElementAndEdge( iElem, iEdge, 1 ); const NodeIDPair nodePairCur = nodeID1 > nodeID0 ? std::make_pair( nodeID0, nodeID1 ) : std::make_pair( nodeID1, nodeID0 ); const ElemAndEdgeID elemAndEdgeIDCur = std::make_pair( iElem, iEdge ); workVector.push_back( InputedDataType( std::pair< NodeIDPair, ElemAndEdgeID >(nodePairCur, elemAndEdgeIDCur) ) ); } } std::sort( workVector.begin(), workVector.end() ); // Allocate memory to m_IDsLocal2Global --- if( m_IDsLocal2Global != NULL ){ const int nElem = sizeof( m_IDsLocal2Global ) / sizeof( m_IDsLocal2Global[0] ); for( int iElem = 0; iElem < nElem; ++iElem ){ delete [] m_IDsLocal2Global[iElem]; } delete [] m_IDsLocal2Global; m_IDsLocal2Global = NULL; } m_IDsLocal2Global = new int*[nElem]; for( int iElem = 0; iElem < nElem; ++iElem ){ m_IDsLocal2Global[iElem] = new int[12]; } //----------------------------------------- std::pair nodePairPre; int edgeIDGlobal(-1); std::vector::const_iterator itrEnd = workVector.end(); for( std::vector::const_iterator itr = workVector.begin(); itr != itrEnd; ++itr ){ const int elemIDGlobal = (*itr).second.first; const int edgeIDLocal = (*itr).second.second; const int nodePairCur0 = m_MeshDataNonConformingHexaElement.getNodeIDGlobalFromElementAndEdge( elemIDGlobal, edgeIDLocal, 0 ); const int nodePairCur1 = m_MeshDataNonConformingHexaElement.getNodeIDGlobalFromElementAndEdge( elemIDGlobal, edgeIDLocal, 1 ); if( ( nodePairCur0 == nodePairPre.first && nodePairCur1 == nodePairPre.second ) || ( nodePairCur0 == nodePairPre.second && nodePairCur1 == nodePairPre.first ) ){// Same edge with privious one }else{// New edge ++edgeIDGlobal; nodePairPre.first = nodePairCur0; nodePairPre.second = nodePairCur1; } m_IDsLocal2Global[elemIDGlobal][edgeIDLocal] = edgeIDGlobal; #ifdef _DEBUG_WRITE std::cout << "nodePairCur0 nodePairCur1 m_IDsLocal2Global[elemIDGlobal][edgeIDLocal] : " << nodePairCur0 << " " << nodePairCur1 << " -> " << m_IDsLocal2Global[elemIDGlobal][edgeIDLocal] << std::endl; #endif } m_numOfEquation = edgeIDGlobal + 1; m_hasSetIDsLocal2Global = true; } // Calculate array converting global IDs to the ones after degeneration void Forward3DNonConformingHexaElement0thOrder::calcArrayConvertIDsGlobal2AfterDegenerated(){ if( !m_hasSetIDsLocal2Global ){ OutputFiles::m_logFile << "Error : Array converting local edge IDs to global ones has not been set yet." << std::endl; exit(1); } const int iPol = getPolarizationCurrent(); if( m_IDsGlobal2AfterDegenerated[iPol] != NULL ){ delete [] m_IDsGlobal2AfterDegenerated[iPol]; m_IDsGlobal2AfterDegenerated[iPol] = NULL; } m_IDsGlobal2AfterDegenerated[iPol] = new int[m_numOfEquation]; for( int i = 0; i < m_numOfEquation; ++i ){ m_IDsGlobal2AfterDegenerated[iPol][i] = 0; } int planesWithNonzeroValues[3] = { -1, -1, -1 }; int planesWithZeroValues[3] = { -1, -1, -1 }; if( iPol == CommonParameters::EX_POLARIZATION ){// Ex Polarization planesWithNonzeroValues[0] = MeshData::ZXMinus; planesWithNonzeroValues[1] = MeshData::ZXPlus; planesWithNonzeroValues[2] = MeshData::XYMinus; planesWithZeroValues[0] = MeshData::YZMinus; planesWithZeroValues[1] = MeshData::YZPlus; planesWithZeroValues[2] = MeshData::XYPlus; }else{// Ey Polarization planesWithNonzeroValues[0] = MeshData::YZMinus; planesWithNonzeroValues[1] = MeshData::YZPlus; planesWithNonzeroValues[2] = MeshData::XYMinus; planesWithZeroValues[0] = MeshData::ZXMinus; planesWithZeroValues[1] = MeshData::ZXPlus; planesWithZeroValues[2] = MeshData::XYPlus; } // Planes on which dirichlet boundary condition with non-zero values is specified for( int iPlane = 0; iPlane < 3; ++iPlane ){ const int planeID = planesWithNonzeroValues[iPlane]; const int nElemOnPlane = m_MeshDataNonConformingHexaElement.getNumElemOnBoundaryPlanes( planeID ); //#ifdef _DEBUG_WRITE // std::cout << "planeID " << planeID << std::endl; //#endif for( int iElem = 0; iElem < nElemOnPlane; ++iElem ){ const int elemIDGlobal = m_MeshDataNonConformingHexaElement.getElemBoundaryPlanes( planeID, iElem ); const int faceIDLocal = m_MeshDataNonConformingHexaElement.getFaceIDLocalFromElementBoundaryPlanes( planeID, iElem ); for( int iEdge = 0; iEdge < 4; ++iEdge ){ const int edgeIDLocal = m_MeshDataNonConformingHexaElement.getEdgeIDLocalFromFaceIDLocal( faceIDLocal, iEdge ); //#ifdef _DEBUG_WRITE // std::cout << "elemIDGlobal edgeIDLocal m_IDsLocal2Global[elemIDGlobal][edgeIDLocal] : " << elemIDGlobal << " " << edgeIDLocal << " " << m_IDsLocal2Global[elemIDGlobal][edgeIDLocal] << std::endl; //#endif m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[elemIDGlobal][edgeIDLocal] ] = Forward3DNonConformingHexaElement0thOrder::DIRICHLET_BOUNDARY_NONZERO_VALUE; } } } // Planes on which dirichlet boundary condition with zero values is specified for( int iPlane = 0; iPlane < 3; ++iPlane ){ const int planeID = planesWithZeroValues[iPlane]; const int nElemOnPlane = m_MeshDataNonConformingHexaElement.getNumElemOnBoundaryPlanes( planeID ); for( int iElem = 0; iElem < nElemOnPlane; ++iElem ){ const int elemIDGlobal = m_MeshDataNonConformingHexaElement.getElemBoundaryPlanes( planeID, iElem ); const int faceIDLocal = m_MeshDataNonConformingHexaElement.getFaceIDLocalFromElementBoundaryPlanes( planeID, iElem ); for( int iEdge = 0; iEdge < 4; ++iEdge ){ const int edgeIDLocal = m_MeshDataNonConformingHexaElement.getEdgeIDLocalFromFaceIDLocal( faceIDLocal, iEdge ); m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[elemIDGlobal][edgeIDLocal] ] = Forward3DNonConformingHexaElement0thOrder::DIRICHLET_BOUNDARY_ZERO_VALUE; } } } int icount(-1); for( int i = 0; i < m_numOfEquation; ++i ){ if( m_IDsGlobal2AfterDegenerated[iPol][i] < 0 ){ continue; } m_IDsGlobal2AfterDegenerated[iPol][i] = ++icount; } m_numOfEquationDegenerated = icount + 1; m_hasIDsGlobal2AfterDegenerated[iPol] = true; #ifdef _DEBUG_WRITE for( int i = 0; i < m_numOfEquation; ++i ){ std::cout << "i m_IDsGlobal2AfterDegenerated[iPol][i] : " << i << " " << m_IDsGlobal2AfterDegenerated[iPol][i] << std::endl; } const int nElem = m_MeshDataNonConformingHexaElement.getNumElemTotal(); for( int iElem = 0; iElem < nElem; ++iElem ){ for( int iEdge = 0; iEdge < 12; ++iEdge ){ std::cout << "iElem iEdge m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[iElem][iEdge] ] : " << iElem << " " << iEdge << " " << m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[iElem][iEdge] ] << std::endl; } } #endif } // Calculate array converting global edge IDs non-zero electric field values specified to the edges void Forward3DNonConformingHexaElement0thOrder::calcArrayConvertIDGlobal2NonZeroValues(){ if( m_hasSetIDsLocal2Global == false ){ OutputFiles::m_logFile << "Error : Array converting local edge IDs to global ones has not been set yet." << std::endl; exit(1); } const int iPol = getPolarizationCurrent(); if( m_hasIDsGlobal2AfterDegenerated[iPol] == false ){ OutputFiles::m_logFile << "Error : Array converting global IDs to the ones after degeneration has not been set yet." << std::endl; exit(1); } //---------------------------------------------------------------------------- //--- Calculating EM field of the boundary planes with 2D forward analysis --- //---------------------------------------------------------------------------- const double freq = getFrequencyCurrent(); OutputFiles::m_logFile << "# Calculating EM field of the boundary planes with 2D forward analysis." << std::endl; if( iPol == CommonParameters::EX_POLARIZATION ){// Ex polarization OutputFiles::m_logFile << "#-----------------------------[ Boundary Plane " << MeshData::ZXMinus << " ]-----------------------------" << std::endl; m_Fwd2DQuadrilateralElement[MeshData::ZXMinus]->calcEMFieldsOfBoundaryPlanes( freq, &m_MeshDataNonConformingHexaElement ); OutputFiles::m_logFile << "#-----------------------------[ Boundary Plane " << MeshData::ZXPlus << " ]-----------------------------" << std::endl; m_Fwd2DQuadrilateralElement[MeshData::ZXPlus]->calcEMFieldsOfBoundaryPlanes( freq, &m_MeshDataNonConformingHexaElement ); }else{// Ey polarization OutputFiles::m_logFile << "#-----------------------------[ Boundary Plane " << MeshData::YZMinus << " ]-----------------------------" << std::endl; m_Fwd2DQuadrilateralElement[MeshData::YZMinus]->calcEMFieldsOfBoundaryPlanes( freq, &m_MeshDataNonConformingHexaElement ); OutputFiles::m_logFile << "#-----------------------------[ Boundary Plane " << MeshData::YZPlus << " ]-----------------------------" << std::endl; m_Fwd2DQuadrilateralElement[MeshData::YZPlus]->calcEMFieldsOfBoundaryPlanes( freq, &m_MeshDataNonConformingHexaElement ); } OutputFiles::m_logFile << "#------------------------------------------------------------------------------" << std::endl; //---------------------------------------------------------------------------- // Initialize array converting global edge IDs non-zero electric field values specified to the edges m_globalID2NonZeroValues.clear(); int sidePlanes[2] = { -1, -1 }; if( iPol == CommonParameters::EX_POLARIZATION ){// Ex Polarization sidePlanes[0] = MeshData::ZXMinus; sidePlanes[1] = MeshData::ZXPlus; }else{// Ey Polarization sidePlanes[0] = MeshData::YZMinus; sidePlanes[1] = MeshData::YZPlus; } // Side planes on which dirichlet boundary condition with non-zero values is specified for( int iPlane = 0; iPlane < 2; ++iPlane ){ const int planeID = sidePlanes[iPlane]; const int nElemOnPlane = m_MeshDataNonConformingHexaElement.getNumElemOnBoundaryPlanes( planeID ); for( int iElem = 0; iElem < nElemOnPlane; ++iElem ){ const int elemIDGlobal = m_MeshDataNonConformingHexaElement.getElemBoundaryPlanes( planeID, iElem ); const int faceIDLocal = m_MeshDataNonConformingHexaElement.getFaceIDLocalFromElementBoundaryPlanes( planeID, iElem ); for( int iEdge = 0; iEdge < 4; ++iEdge ){ const std::complex val = m_Fwd2DQuadrilateralElement[planeID]->getSolutionFromLocalID( iElem, iEdge ); const int edgeIDLocal = m_MeshDataNonConformingHexaElement.getEdgeIDLocalFromFaceIDLocal( faceIDLocal, iEdge ); m_globalID2NonZeroValues.insert( std::map >::value_type( m_IDsLocal2Global[elemIDGlobal][edgeIDLocal], val ) ); } } } // Top planes on which dirichlet boundary condition with non-zero values ( source field ) is specified { const double sourceValueElectric = CommonParameters::sourceValueElectric; const int nElemOnPlane = m_MeshDataNonConformingHexaElement.getNumElemOnBoundaryPlanes( MeshData::XYMinus ); for( int iElem = 0; iElem < nElemOnPlane; ++iElem ){ const int elemIDGlobal = m_MeshDataNonConformingHexaElement.getElemBoundaryPlanes( MeshData::XYMinus, iElem ); const int faceIDLocal = m_MeshDataNonConformingHexaElement.getFaceIDLocalFromElementBoundaryPlanes( MeshData::XYMinus, iElem ); for( int iEdge = 0; iEdge < 4; ++iEdge ){ const int edgeIDLocal = m_MeshDataNonConformingHexaElement.getEdgeIDLocalFromFaceIDLocal( faceIDLocal, iEdge ); const int nodeID0 = m_MeshDataNonConformingHexaElement.getNodeIDGlobalFromElementAndEdge( elemIDGlobal, edgeIDLocal, 0 ); const int nodeID1 = m_MeshDataNonConformingHexaElement.getNodeIDGlobalFromElementAndEdge( elemIDGlobal, edgeIDLocal, 1 ); double val = ( iPol == CommonParameters::EX_POLARIZATION ) ? m_MeshDataNonConformingHexaElement.caldDiffXOfTwoNodes( nodeID0, nodeID1 ) : m_MeshDataNonConformingHexaElement.caldDiffYOfTwoNodes( nodeID0, nodeID1 ); val /= m_MeshDataNonConformingHexaElement.calcDistanceOfTwoNodes( nodeID0, nodeID1 ); m_globalID2NonZeroValues.insert( std::map >::value_type( m_IDsLocal2Global[elemIDGlobal][edgeIDLocal], std::complex(sourceValueElectric*val, 0.0) ) ); } } } #ifdef _DEBUG_WRITE for ( std::map >::iterator itr = m_globalID2NonZeroValues.begin(); itr != m_globalID2NonZeroValues.end(); ++itr ){ std::cout << "key value " << itr->first << " " << itr->second << std::endl; } #endif } // Calculate 2D jacobian matrix for the Earth's surface double Forward3DNonConformingHexaElement0thOrder::calc2DJacobianMatrixForEarthSurface( const int elemID, const double xi, const double eta, Forward3D::Matrix2x2& jacobMat ) const{ // Array of reference coord xi values for each node const double xiAtNode[4] = { -1.0, 1.0, 1.0, -1.0 }; // Array of reference coord eta values for each node const double etaAtNode[4] = { -1.0, -1.0, 1.0, 1.0 }; jacobMat.mat11 = 0.0; jacobMat.mat12 = 0.0; jacobMat.mat21 = 0.0; jacobMat.mat22 = 0.0; for( int i = 0; i < 4; ++i ){ const double xiNode = xiAtNode[i]; const double etaNode = etaAtNode[i]; const double tmp1 = 0.25 * xiNode * (1.0 + etaNode * eta); const double tmp2 = 0.25 * etaNode * (1.0 + xiNode * xi); const int node = m_MeshDataNonConformingHexaElement.getNodesOfElements( elemID, i ); const double xCoord = m_MeshDataNonConformingHexaElement.getXCoordinatesOfNodes(node); const double yCoord = m_MeshDataNonConformingHexaElement.getYCoordinatesOfNodes(node); jacobMat.mat11 += tmp1 * xCoord; jacobMat.mat12 += tmp1 * yCoord; jacobMat.mat21 += tmp2 * xCoord; jacobMat.mat22 += tmp2 * yCoord; } return jacobMat.mat11 * jacobMat.mat22 - jacobMat.mat12 * jacobMat.mat21; } // Make map converting master dofs after degeneration and MPC factors from slave dof after degeneration void Forward3DNonConformingHexaElement0thOrder::makeMapSlaveDofToMasterDofAndFactors(){ const int iPol = getPolarizationCurrent();// Constraint matrix does not depend on the type of polarization if( m_IDsAfterDegenerated2AfterConstrained != NULL ){ delete [] m_IDsAfterDegenerated2AfterConstrained; m_IDsAfterDegenerated2AfterConstrained = NULL; } m_IDsAfterDegenerated2AfterConstrained = new int[m_numOfEquationDegenerated]; for( int i = 0; i < m_numOfEquationDegenerated; ++i ){ m_IDsAfterDegenerated2AfterConstrained[i] = 0; } if( m_slaveDofToMasterDofAndFactors != NULL ){ delete [] m_slaveDofToMasterDofAndFactors; m_slaveDofToMasterDofAndFactors = NULL; } m_slaveDofToMasterDofAndFactors = new std::vector< std::pair >[m_numOfEquationDegenerated]; const int nElem = m_MeshDataNonConformingHexaElement.getNumElemTotal(); for( int iElem = 0; iElem < nElem; ++iElem ){ const int elemID = iElem; for( int iFace = 0; iFace < 6; ++iFace ){ if( !m_MeshDataNonConformingHexaElement.faceSlaveElements(elemID, iFace) ){ // This face does not have slave edges continue; } // Dofs of master edges int dofMasterBeforeDegenerated[4] = { -1, -1, -1, -1 }; int dofMaster[4] = { -1, -1, -1, -1 }; for( int iEdge = 0; iEdge < 4; ++iEdge ){ const int edgeIDLocal = m_MeshDataNonConformingHexaElement.getEdgeIDLocalFromFaceIDLocal( iFace, iEdge ); const int dofBeforeDegenerated = m_IDsLocal2Global[elemID][edgeIDLocal]; dofMasterBeforeDegenerated[iEdge] = dofBeforeDegenerated; dofMaster[iEdge] = m_IDsGlobal2AfterDegenerated[iPol][ dofBeforeDegenerated ]; #ifdef _DEBUG_WRITE if( dofMaster[iEdge] < 0 ){ std::cout << "iElem, iEdge, dofMaster :" << iElem << " " << iEdge << " " << dofMaster[iEdge] << std::endl; } #endif } // Face index of neighbor element const int iFaceNeib = m_MeshDataNonConformingHexaElement.getFaceIndexOfNeighborElement(iFace); const int numNeibElements = m_MeshDataNonConformingHexaElement.getNumNeighborElement(elemID, iFace); if( numNeibElements == 2 ){ // Dofs of slave edges int dofSlaves[2][4] = { { -1, -1, -1, -1 }, { -1, -1, -1, -1 } }; for( int iNeib = 0; iNeib < 2; ++iNeib ){ const int elemIDNeib = m_MeshDataNonConformingHexaElement.getIDOfNeighborElement(elemID, iFace, iNeib ); for( int iEdgeNeib = 0; iEdgeNeib < 4; ++iEdgeNeib ){ const int edgeIDLocalNeib = m_MeshDataNonConformingHexaElement.getEdgeIDLocalFromFaceIDLocal( iFaceNeib, iEdgeNeib ); dofSlaves[iNeib][iEdgeNeib] = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[elemIDNeib][edgeIDLocalNeib] ]; } } assert( dofSlaves[0][3] == dofSlaves[1][2] ); if( dofMaster[0] >= 0 ){ // Slave dofs on outer edges of the face addMasterDofAndFactorPair( dofSlaves[0][0], dofMaster[0], 1.0 ); addMasterDofAndFactorPair( dofSlaves[1][0], dofMaster[0], 1.0 ); } if( dofMaster[1] >= 0 ){ // Slave dofs on outer edges of the face addMasterDofAndFactorPair( dofSlaves[0][1], dofMaster[1], 1.0 ); addMasterDofAndFactorPair( dofSlaves[1][1], dofMaster[1], 1.0 ); } if( dofMaster[2] >= 0 ){ // Slave dofs on interior edges of the face addMasterDofAndFactorPair( dofSlaves[0][3], dofMaster[2], 0.5 ); }else{ // In this case, MPC constants are calcunated in calcMPCConstants } if( dofMaster[3] >= 0 ){ // Slave dofs on interior edges of the face addMasterDofAndFactorPair( dofSlaves[0][3], dofMaster[3], 0.5 ); }else{ // In this case, MPC constants are calcunated in calcMPCConstants } // Slave dofs on outer edges of the face m_IDsAfterDegenerated2AfterConstrained[ dofSlaves[0][0] ] = Forward3DNonConformingHexaElement0thOrder::SLAVE_ON_OUTER_EDGES; m_IDsAfterDegenerated2AfterConstrained[ dofSlaves[1][0] ] = Forward3DNonConformingHexaElement0thOrder::SLAVE_ON_OUTER_EDGES; m_IDsAfterDegenerated2AfterConstrained[ dofSlaves[0][1] ] = Forward3DNonConformingHexaElement0thOrder::SLAVE_ON_OUTER_EDGES; m_IDsAfterDegenerated2AfterConstrained[ dofSlaves[1][1] ] = Forward3DNonConformingHexaElement0thOrder::SLAVE_ON_OUTER_EDGES; // Slave dofs on interior edges of the face m_IDsAfterDegenerated2AfterConstrained[ dofSlaves[0][3] ] = Forward3DNonConformingHexaElement0thOrder::SLAVE_ON_INTERIOR_EDGES; }else if( numNeibElements == 4 ){ // Dofs of slave edges int dofSlaves[4][4] = { { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 } }; for( int iNeib = 0; iNeib < 4; ++iNeib ){ const int elemIDNeib = m_MeshDataNonConformingHexaElement.getIDOfNeighborElement(elemID, iFace, iNeib ); for( int iEdgeNeib = 0; iEdgeNeib < 4; ++iEdgeNeib ){ const int edgeIDLocalNeib = m_MeshDataNonConformingHexaElement.getEdgeIDLocalFromFaceIDLocal( iFaceNeib, iEdgeNeib ); dofSlaves[iNeib][iEdgeNeib] = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[elemIDNeib][edgeIDLocalNeib] ]; } } assert( dofSlaves[0][1] == dofSlaves[2][0] ); assert( dofSlaves[1][1] == dofSlaves[3][0] ); assert( dofSlaves[0][3] == dofSlaves[1][2] ); assert( dofSlaves[2][3] == dofSlaves[3][2] ); if( dofMaster[0] >= 0 ){ // Slave dofs on outer edges of the face addMasterDofAndFactorPair( dofSlaves[0][0], dofMaster[0], 1.0 ); addMasterDofAndFactorPair( dofSlaves[1][0], dofMaster[0], 1.0 ); // Slave dofs on interior edges of the face addMasterDofAndFactorPair( dofSlaves[0][1], dofMaster[0], 0.5 ); addMasterDofAndFactorPair( dofSlaves[1][1], dofMaster[0], 0.5 ); }else{ // In this case, MPC constants are calcunated in calcMPCConstants } if( dofMaster[1] >= 0 ){ // Slave dofs on outer edges of the face addMasterDofAndFactorPair( dofSlaves[2][1], dofMaster[1], 1.0 ); addMasterDofAndFactorPair( dofSlaves[3][1], dofMaster[1], 1.0 ); // Slave dofs on interior edges of the face addMasterDofAndFactorPair( dofSlaves[0][1], dofMaster[1], 0.5 ); addMasterDofAndFactorPair( dofSlaves[1][1], dofMaster[1], 0.5 ); }else{ // In this case, MPC constants are calcunated in calcMPCConstants } if( dofMaster[2] >= 0 ){ // Slave dofs on outer edges of the face addMasterDofAndFactorPair( dofSlaves[0][2], dofMaster[2], 1.0 ); addMasterDofAndFactorPair( dofSlaves[2][2], dofMaster[2], 1.0 ); // Slave dofs on interior edges of the face addMasterDofAndFactorPair( dofSlaves[0][3], dofMaster[2], 0.5 ); addMasterDofAndFactorPair( dofSlaves[2][3], dofMaster[2], 0.5 ); }else{ // In this case, MPC constants are calcunated in calcMPCConstants } if( dofMaster[3] >= 0 ){ // Slave dofs on outer edges of the face addMasterDofAndFactorPair( dofSlaves[1][3], dofMaster[3], 1.0 ); addMasterDofAndFactorPair( dofSlaves[3][3], dofMaster[3], 1.0 ); // Slave dofs on interior edges of the face addMasterDofAndFactorPair( dofSlaves[0][3], dofMaster[3], 0.5 ); addMasterDofAndFactorPair( dofSlaves[2][3], dofMaster[3], 0.5 ); }else{ // In this case, MPC constants are calcunated in calcMPCConstants } // Slave dofs on outer edges of the face m_IDsAfterDegenerated2AfterConstrained[ dofSlaves[0][0] ] = Forward3DNonConformingHexaElement0thOrder::SLAVE_ON_OUTER_EDGES; m_IDsAfterDegenerated2AfterConstrained[ dofSlaves[1][0] ] = Forward3DNonConformingHexaElement0thOrder::SLAVE_ON_OUTER_EDGES; m_IDsAfterDegenerated2AfterConstrained[ dofSlaves[2][1] ] = Forward3DNonConformingHexaElement0thOrder::SLAVE_ON_OUTER_EDGES; m_IDsAfterDegenerated2AfterConstrained[ dofSlaves[3][1] ] = Forward3DNonConformingHexaElement0thOrder::SLAVE_ON_OUTER_EDGES; m_IDsAfterDegenerated2AfterConstrained[ dofSlaves[0][2] ] = Forward3DNonConformingHexaElement0thOrder::SLAVE_ON_OUTER_EDGES; m_IDsAfterDegenerated2AfterConstrained[ dofSlaves[2][2] ] = Forward3DNonConformingHexaElement0thOrder::SLAVE_ON_OUTER_EDGES; m_IDsAfterDegenerated2AfterConstrained[ dofSlaves[1][3] ] = Forward3DNonConformingHexaElement0thOrder::SLAVE_ON_OUTER_EDGES; m_IDsAfterDegenerated2AfterConstrained[ dofSlaves[3][3] ] = Forward3DNonConformingHexaElement0thOrder::SLAVE_ON_OUTER_EDGES; // Slave dofs on interior edges of the face m_IDsAfterDegenerated2AfterConstrained[ dofSlaves[0][1] ] = Forward3DNonConformingHexaElement0thOrder::SLAVE_ON_INTERIOR_EDGES; m_IDsAfterDegenerated2AfterConstrained[ dofSlaves[1][1] ] = Forward3DNonConformingHexaElement0thOrder::SLAVE_ON_INTERIOR_EDGES; m_IDsAfterDegenerated2AfterConstrained[ dofSlaves[0][3] ] = Forward3DNonConformingHexaElement0thOrder::SLAVE_ON_INTERIOR_EDGES; m_IDsAfterDegenerated2AfterConstrained[ dofSlaves[2][3] ] = Forward3DNonConformingHexaElement0thOrder::SLAVE_ON_INTERIOR_EDGES; }else{ OutputFiles::m_logFile << "Error : Number of neighbor elements is wrong : " << numNeibElements << std::endl; exit(1); } } } //#ifdef _DEBUG_WRITE // for( int i = 0; i < m_numOfEquationDegenerated; ++i ){ // std::vector< std::pair >& vec = m_slaveDofToMasterDofAndFactors[i]; // const int numMasters = vec.size(); // assert( numMasters == 1 || numMasters == 2 ); // double sumFactor(0.0); // for( std::vector< std::pair >::const_iterator itrVec = vec.begin(); itrVec != vec.end(); ++itrVec ){ // sumFactor += itrVec->second; // } // assert( std::abs(sumFactor - 0.5) < m_eps ); // } //#endif int icount(-1); for( int i = 0; i < m_numOfEquationDegenerated; ++i ){ if( m_IDsAfterDegenerated2AfterConstrained[i] < 0 ){ // Slave dof continue; } // Master dof addMasterDofAndFactorPair( i, i, 1.0 );// Even for master dof, dof and factor are inserted m_IDsAfterDegenerated2AfterConstrained[i] = ++icount; } m_numOfEquationDegeneratedAndConstrained = icount + 1; m_hasMadeMapSlaveDofToMasterDofAndFactors = true; #ifdef _DEBUG_WRITE for( int i = 0; i < m_numOfEquationDegenerated; ++i ){ std::vector< std::pair >& vec = m_slaveDofToMasterDofAndFactors[i]; for( std::vector< std::pair >::const_iterator itrVec = vec.begin(); itrVec != vec.end(); ++itrVec ){ std::cout << "slave master factor : " << i << " " << itrVec->first << " " << itrVec->second << std::endl; } } #endif } // Calculate MPC constants void Forward3DNonConformingHexaElement0thOrder::calcMPCConstants(){ const int iPol = getPolarizationCurrent();// Constraint matrix does not depend on the type of polarization if( m_vectorMPCConstants == NULL ){ m_vectorMPCConstants = new std::complex[m_numOfEquationDegenerated]; } // Zero clear because values are added in the following procedure for( int i = 0; i < m_numOfEquationDegenerated; ++i ){ m_vectorMPCConstants[i] = std::complex(0.0, 0.0); } const int nElem = m_MeshDataNonConformingHexaElement.getNumElemTotal(); for( int iElem = 0; iElem < nElem; ++iElem ){ const int elemID = iElem; for( int iFace = 0; iFace < 6; ++iFace ){ if( !m_MeshDataNonConformingHexaElement.faceSlaveElements(elemID, iFace) ){ // This face does not have slave edges continue; } // Dofs of master edges int dofMasterBeforeDegenerated[4] = { -1, -1, -1, -1 }; int dofMaster[4] = { -1, -1, -1, -1 }; for( int iEdge = 0; iEdge < 4; ++iEdge ){ const int edgeIDLocal = m_MeshDataNonConformingHexaElement.getEdgeIDLocalFromFaceIDLocal( iFace, iEdge ); const int dofBeforeDegenerated = m_IDsLocal2Global[elemID][edgeIDLocal]; dofMasterBeforeDegenerated[iEdge] = dofBeforeDegenerated; dofMaster[iEdge] = m_IDsGlobal2AfterDegenerated[iPol][ dofBeforeDegenerated ]; } // Face index of neighbor element const int iFaceNeib = m_MeshDataNonConformingHexaElement.getFaceIndexOfNeighborElement(iFace); const int numNeibElements = m_MeshDataNonConformingHexaElement.getNumNeighborElement(elemID, iFace); if( numNeibElements == 2 ){ // Dofs of slave edges int dofSlaves[2][4] = { { -1, -1, -1, -1 }, { -1, -1, -1, -1 } }; for( int iNeib = 0; iNeib < 2; ++iNeib ){ const int elemIDNeib = m_MeshDataNonConformingHexaElement.getIDOfNeighborElement(elemID, iFace, iNeib ); for( int iEdgeNeib = 0; iEdgeNeib < 4; ++iEdgeNeib ){ const int edgeIDLocalNeib = m_MeshDataNonConformingHexaElement.getEdgeIDLocalFromFaceIDLocal( iFaceNeib, iEdgeNeib ); dofSlaves[iNeib][iEdgeNeib] = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[elemIDNeib][edgeIDLocalNeib] ]; } } assert( dofSlaves[0][3] == dofSlaves[1][2] ); if( dofMaster[2] < 0 ){ if( dofMaster[2] == Forward3DNonConformingHexaElement0thOrder::DIRICHLET_BOUNDARY_NONZERO_VALUE ){ const std::complex value = std::complex(0.5, 0.0) * m_globalID2NonZeroValues[ dofMasterBeforeDegenerated[2] ]; m_vectorMPCConstants[ dofSlaves[0][3] ] += value; } } if( dofMaster[3] < 0 ){ if( dofMaster[3] == Forward3DNonConformingHexaElement0thOrder::DIRICHLET_BOUNDARY_NONZERO_VALUE ){ const std::complex value = std::complex(0.5, 0.0) * m_globalID2NonZeroValues[ dofMasterBeforeDegenerated[3] ]; m_vectorMPCConstants[ dofSlaves[0][3] ] += value; } } }else if( numNeibElements == 4 ){ // Dofs of slave edges int dofSlaves[4][4] = { { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 } }; for( int iNeib = 0; iNeib < 4; ++iNeib ){ const int elemIDNeib = m_MeshDataNonConformingHexaElement.getIDOfNeighborElement(elemID, iFace, iNeib ); for( int iEdgeNeib = 0; iEdgeNeib < 4; ++iEdgeNeib ){ const int edgeIDLocalNeib = m_MeshDataNonConformingHexaElement.getEdgeIDLocalFromFaceIDLocal( iFaceNeib, iEdgeNeib ); dofSlaves[iNeib][iEdgeNeib] = m_IDsGlobal2AfterDegenerated[iPol][ m_IDsLocal2Global[elemIDNeib][edgeIDLocalNeib] ]; } } assert( dofSlaves[0][1] == dofSlaves[2][0] ); assert( dofSlaves[1][1] == dofSlaves[3][0] ); assert( dofSlaves[0][3] == dofSlaves[1][2] ); assert( dofSlaves[2][3] == dofSlaves[3][2] ); if( dofMaster[0] < 0 ){ if( dofMaster[0] == Forward3DNonConformingHexaElement0thOrder::DIRICHLET_BOUNDARY_NONZERO_VALUE ){ const std::complex value = std::complex(0.5, 0.0) * m_globalID2NonZeroValues[ dofMasterBeforeDegenerated[0] ]; m_vectorMPCConstants[ dofSlaves[0][1] ] += value; m_vectorMPCConstants[ dofSlaves[1][1] ] += value; } } if( dofMaster[1] < 0 ){ if( dofMaster[1] == Forward3DNonConformingHexaElement0thOrder::DIRICHLET_BOUNDARY_NONZERO_VALUE ){ const std::complex value = std::complex(0.5, 0.0) * m_globalID2NonZeroValues[ dofMasterBeforeDegenerated[1] ]; m_vectorMPCConstants[ dofSlaves[0][1] ] += value; m_vectorMPCConstants[ dofSlaves[1][1] ] += value; } } if( dofMaster[2] < 0 ){ if( dofMaster[2] == Forward3DNonConformingHexaElement0thOrder::DIRICHLET_BOUNDARY_NONZERO_VALUE ){ const std::complex value = std::complex(0.5, 0.0) * m_globalID2NonZeroValues[ dofMasterBeforeDegenerated[2] ]; m_vectorMPCConstants[ dofSlaves[0][3] ] += value; m_vectorMPCConstants[ dofSlaves[2][3] ] += value; } } if( dofMaster[3] < 0 ){ if( dofMaster[3] == Forward3DNonConformingHexaElement0thOrder::DIRICHLET_BOUNDARY_NONZERO_VALUE ){ const std::complex value = std::complex(0.5, 0.0) * m_globalID2NonZeroValues[ dofMasterBeforeDegenerated[3] ]; m_vectorMPCConstants[ dofSlaves[0][3] ] += value; m_vectorMPCConstants[ dofSlaves[2][3] ] += value; } } }else{ OutputFiles::m_logFile << "Error : Number of neighbor elements is wrong : " << numNeibElements << std::endl; exit(1); } } } #ifdef _DEBUG_WRITE for( int i = 0; i < m_numOfEquationDegenerated; ++i ){ std::cout << "m_vectorMPCConstants[" << i << "] = " << m_vectorMPCConstants[i] << std::endl; } #endif } // Add master dof and factor pair to m_slaveDofToMasterDofAndFactors bool Forward3DNonConformingHexaElement0thOrder::doesIntegralXCompFirst( const CommonParameters::locationXY& startPoint, const CommonParameters::locationXY& endPoint, bool& rotationDirectionPlus, CommonParameters::locationXY& sharedPoint ) const{ const double eps = 1.0e-12; bool intersectTwoEdges = true; if( ( fabs( startPoint.X - 1.0 ) < eps && fabs( endPoint.Y - 1.0 ) < eps ) || ( fabs( startPoint.Y - 1.0 ) < eps && fabs( endPoint.X - 1.0 ) < eps ) ){ sharedPoint.X = 1.0; sharedPoint.Y = 1.0; }else if( ( fabs( startPoint.X - 1.0 ) < eps && fabs( endPoint.Y + 1.0 ) < eps ) || ( fabs( startPoint.Y + 1.0 ) < eps && fabs( endPoint.X - 1.0 ) < eps ) ){ sharedPoint.X = 1.0; sharedPoint.Y = -1.0; }else if( ( fabs( startPoint.X + 1.0 ) < eps && fabs( endPoint.Y + 1.0 ) < eps ) || ( fabs( startPoint.Y + 1.0 ) < eps && fabs( endPoint.X + 1.0 ) < eps ) ){ sharedPoint.X = -1.0; sharedPoint.Y = -1.0; }else if( ( fabs( startPoint.X + 1.0 ) < eps && fabs( endPoint.Y - 1.0 ) < eps ) || ( fabs( startPoint.Y - 1.0 ) < eps && fabs( endPoint.X + 1.0 ) < eps ) ){ sharedPoint.X = -1.0; sharedPoint.Y = 1.0; }else{// Not intersect two edges => integral X component first sharedPoint.X = startPoint.X; sharedPoint.Y = endPoint.Y; intersectTwoEdges = false; } const double outerProduct = ( sharedPoint.X - startPoint.X )*( endPoint.Y - startPoint.Y ) - ( sharedPoint.Y - startPoint.Y )*( endPoint.X - startPoint.X ); if( outerProduct > 0 ){ rotationDirectionPlus = true; }else{ rotationDirectionPlus = false; } if( intersectTwoEdges ){ if( sharedPoint.X * sharedPoint.Y < 0.0 ){ if( rotationDirectionPlus ){ return true; }else{ return false; } }else{ if( rotationDirectionPlus ){ return false; }else{ return true; } } }else{// Not intersect two edges => integral X component first return false; } } // Add master dof and factor pair to m_slaveDofToMasterDofAndFactors void Forward3DNonConformingHexaElement0thOrder::addMasterDofAndFactorPair( const int slaveDof, const int masterDof, const double factor ){ //std::map< int, std::vector< std::pair > >::iterator itr = m_slaveDofToMasterDofAndFactors.find(slaveDof); //if( itr == m_slaveDofToMasterDofAndFactors.end() ){ // // Pair has not been inserted // std::pair pair = std::make_pair( masterDof, factor ); // std::vector< std::pair > vec; // vec.push_back(pair); // m_slaveDofToMasterDofAndFactors.insert( std::make_pair( slaveDof, vec ) ); //}else{ // // Pair has already been inserted // std::vector< std::pair >& vec = itr->second; // bool found(false); // for( std::vector< std::pair >::iterator itrVec = vec.begin(); itrVec != vec.end(); ++itrVec ){ // if(itrVec->first == masterDof){ // found = true; // break; // } // } // if( !found ){ // // Insert only if the master has not been found // itr->second.push_back( std::make_pair( masterDof, factor ) ); // } //} std::vector< std::pair >& vec = m_slaveDofToMasterDofAndFactors[slaveDof];; bool found(false); for( std::vector< std::pair >::iterator itrVec = vec.begin(); itrVec != vec.end(); ++itrVec ){ if(itrVec->first == masterDof){ found = true; break; } } if( !found ){ // Insert only if the master has not been found vec.push_back( std::make_pair( masterDof, factor ) ); } } // Get shape functions of the x direction with respect to the 1st reference element coordinate system double Forward3DNonConformingHexaElement0thOrder::getShapeFuncX( const double xi, const double eta, const double zeta, const int num, const Forward3D::Matrix3x3& invJacobMat ) const{ switch( num ){ case 0:// Go through case 1:// Go through case 2:// Go through case 3: return 0.125 * ( 1.0 + m_etaAtEdge[num] * eta ) * ( 1.0 + m_zetaAtEdge[num] * zeta ) * invJacobMat.mat11; break; case 4:// Go through case 5:// Go through case 6:// Go through case 7: return 0.125 * ( 1.0 + m_zetaAtEdge[num] * zeta ) * ( 1.0 + m_xiAtEdge[num] * xi ) * invJacobMat.mat12; break; case 8:// Go through case 9:// Go through case 10:// Go through case 11: return 0.125 * ( 1.0 + m_xiAtEdge[num] * xi ) * ( 1.0 + m_etaAtEdge[num] * eta ) * invJacobMat.mat13; break; default: OutputFiles::m_logFile << "Error : Wrong number in " << __FUNCTION__ << " : num = " << num << std::endl; exit(1); break; } } // Get shape functions of the y direction with respect to the reference element coordinate system double Forward3DNonConformingHexaElement0thOrder::getShapeFuncY( const double xi, const double eta, const double zeta, const int num, const Forward3D::Matrix3x3& invJacobMat ) const{ switch( num ){ case 0:// Go through case 1:// Go through case 2:// Go through case 3: return 0.125 * ( 1.0 + m_etaAtEdge[num] * eta ) * ( 1.0 + m_zetaAtEdge[num] * zeta ) * invJacobMat.mat21; break; case 4:// Go through case 5:// Go through case 6:// Go through case 7: return 0.125 * ( 1.0 + m_zetaAtEdge[num] * zeta ) * ( 1.0 + m_xiAtEdge[num] * xi ) * invJacobMat.mat22; break; case 8:// Go through case 9:// Go through case 10:// Go through case 11: return 0.125 * ( 1.0 + m_xiAtEdge[num] * xi ) * ( 1.0 + m_etaAtEdge[num] * eta ) * invJacobMat.mat23; break; default: OutputFiles::m_logFile << "Error : Wrong number in " << __FUNCTION__ << " : num = " << num << std::endl; exit(1); break; } } // Get shape functions of the z direction with respect to the reference element coordinate system double Forward3DNonConformingHexaElement0thOrder::getShapeFuncZ( const double xi, const double eta, const double zeta, const int num, const Forward3D::Matrix3x3& invJacobMat ) const{ switch( num ){ case 0:// Go through case 1:// Go through case 2:// Go through case 3: return 0.125 * ( 1.0 + m_etaAtEdge[num] * eta ) * ( 1.0 + m_zetaAtEdge[num] * zeta ) * invJacobMat.mat31; break; case 4:// Go through case 5:// Go through case 6:// Go through case 7: return 0.125 * ( 1.0 + m_zetaAtEdge[num] * zeta ) * ( 1.0 + m_xiAtEdge[num] * xi ) * invJacobMat.mat32; break; case 8:// Go through case 9:// Go through case 10:// Go through case 11: return 0.125 * ( 1.0 + m_xiAtEdge[num] * xi ) * ( 1.0 + m_etaAtEdge[num] * eta ) * invJacobMat.mat33; break; default: OutputFiles::m_logFile << "Error : Wrong number in " << __FUNCTION__ << " : num = " << num << std::endl; exit(1); break; } } // Get x component of shape function rotated for 0th order edge-based elements double Forward3DNonConformingHexaElement0thOrder::getShapeFuncRotatedX( const double xi, const double eta, const double zeta, const int num, const Forward3D::Matrix3x3& invJacobMat ) const{ double tmp1(0.0); double tmp2(0.0); switch( num ){ case 0:// Go through case 1:// Go through case 2:// Go through case 3: tmp1 = 0.125 * m_etaAtEdge[num] * ( 1.0 + m_zetaAtEdge[num] * zeta )*( invJacobMat.mat31*invJacobMat.mat22 - invJacobMat.mat21*invJacobMat.mat32 ); tmp2 = 0.125 * m_zetaAtEdge[num] * ( 1.0 + m_etaAtEdge[num] * eta )*( invJacobMat.mat31*invJacobMat.mat23 - invJacobMat.mat21*invJacobMat.mat33 ); break; case 4:// Go through case 5:// Go through case 6:// Go through case 7: tmp1 = 0.125 * m_zetaAtEdge[num] * ( 1.0 + m_xiAtEdge[num] * xi )*( invJacobMat.mat32*invJacobMat.mat23 - invJacobMat.mat22*invJacobMat.mat33 ); tmp2 = 0.125 * m_xiAtEdge[num] * ( 1.0 + m_zetaAtEdge[num] * zeta )*( invJacobMat.mat32*invJacobMat.mat21 - invJacobMat.mat22*invJacobMat.mat31 ); break; case 8:// Go through case 9:// Go through case 10:// Go through case 11: tmp1 = 0.125 * m_xiAtEdge[num] * ( 1.0 + m_etaAtEdge[num] * eta )*( invJacobMat.mat33*invJacobMat.mat21 - invJacobMat.mat23*invJacobMat.mat31 ); tmp2 = 0.125 * m_etaAtEdge[num] * ( 1.0 + m_xiAtEdge[num] * xi )*( invJacobMat.mat33*invJacobMat.mat22 - invJacobMat.mat23*invJacobMat.mat32 ); break; default: OutputFiles::m_logFile << "Error : Wrong number in " << __FUNCTION__ << " : num = " << num << std::endl; exit(1); break; } return tmp1 + tmp2; } // Get y component of shape function rotated for 0th order edge-based elements double Forward3DNonConformingHexaElement0thOrder::getShapeFuncRotatedY( const double xi, const double eta, const double zeta, const int num, const Forward3D::Matrix3x3& invJacobMat ) const{ double tmp1(0.0); double tmp2(0.0); switch( num ){ case 0:// Go through case 1:// Go through case 2:// Go through case 3: tmp1 = 0.125 * m_etaAtEdge[num] * ( 1.0 + m_zetaAtEdge[num] * zeta )*( invJacobMat.mat11*invJacobMat.mat32 - invJacobMat.mat31*invJacobMat.mat12 ); tmp2 = 0.125 * m_zetaAtEdge[num] * ( 1.0 + m_etaAtEdge[num] * eta )*( invJacobMat.mat11*invJacobMat.mat33 - invJacobMat.mat31*invJacobMat.mat13 ); break; case 4:// Go through case 5:// Go through case 6:// Go through case 7: tmp1 = 0.125 * m_zetaAtEdge[num] * ( 1.0 + m_xiAtEdge[num] * xi )*( invJacobMat.mat12*invJacobMat.mat33 - invJacobMat.mat32*invJacobMat.mat13 ); tmp2 = 0.125 * m_xiAtEdge[num] * ( 1.0 + m_zetaAtEdge[num] * zeta )*( invJacobMat.mat12*invJacobMat.mat31 - invJacobMat.mat32*invJacobMat.mat11 ); break; case 8:// Go through case 9:// Go through case 10:// Go through case 11: tmp1 = 0.125 * m_xiAtEdge[num] * ( 1.0 + m_etaAtEdge[num] * eta )*( invJacobMat.mat13*invJacobMat.mat31 - invJacobMat.mat33*invJacobMat.mat11 ); tmp2 = 0.125 * m_etaAtEdge[num] * ( 1.0 + m_xiAtEdge[num] * xi )*( invJacobMat.mat13*invJacobMat.mat32 - invJacobMat.mat33*invJacobMat.mat12 ); break; default: OutputFiles::m_logFile << "Error : Wrong number in " << __FUNCTION__ << " : num = " << num << std::endl; exit(1); break; } return tmp1 + tmp2; } // Get z component of shape function rotated for 0th order edge-based elements double Forward3DNonConformingHexaElement0thOrder::getShapeFuncRotatedZ( const double xi, const double eta, const double zeta, const int num, const Forward3D::Matrix3x3& invJacobMat ) const{ double tmp1(0.0); double tmp2(0.0); switch( num ){ case 0:// Go through case 1:// Go through case 2:// Go through case 3: tmp1 = 0.125 * m_etaAtEdge[num] * ( 1.0 + m_zetaAtEdge[num] * zeta )*( invJacobMat.mat21*invJacobMat.mat12 - invJacobMat.mat11*invJacobMat.mat22 ); tmp2 = 0.125 * m_zetaAtEdge[num] * ( 1.0 + m_etaAtEdge[num] * eta )*( invJacobMat.mat21*invJacobMat.mat13 - invJacobMat.mat11*invJacobMat.mat23 ); break; case 4:// Go through case 5:// Go through case 6:// Go through case 7: tmp1 = 0.125 * m_zetaAtEdge[num] * ( 1.0 + m_xiAtEdge[num] * xi )*( invJacobMat.mat22*invJacobMat.mat13 - invJacobMat.mat12*invJacobMat.mat23 ); tmp2 = 0.125 * m_xiAtEdge[num] * ( 1.0 + m_zetaAtEdge[num] * zeta )*( invJacobMat.mat22*invJacobMat.mat11 - invJacobMat.mat12*invJacobMat.mat21 ); break; case 8:// Go through case 9:// Go through case 10:// Go through case 11: tmp1 = 0.125 * m_xiAtEdge[num] * ( 1.0 + m_etaAtEdge[num] * eta )*( invJacobMat.mat23*invJacobMat.mat11 - invJacobMat.mat13*invJacobMat.mat21 ); tmp2 = 0.125 * m_etaAtEdge[num] * ( 1.0 + m_xiAtEdge[num] * xi )*( invJacobMat.mat23*invJacobMat.mat12 - invJacobMat.mat13*invJacobMat.mat22 ); break; default: OutputFiles::m_logFile << "Error : Wrong number in " << __FUNCTION__ << " : num = " << num << std::endl; exit(1); break; } return tmp1 + tmp2; } // Calculate jacobian matrix of the elements double Forward3DNonConformingHexaElement0thOrder::get2DShapeFuncRotatedForEarthSurface( const double xi, const double eta, const int num, const Forward3D::Matrix2x2& invJacobMat ) const{ // Array of reference coord xi values for each edge const double xiAtEdge[4] = { -9999.999, -9999.999, -1.0, 1.0 }; // Array of reference coord eta values for each edge const double etaAtEdge[4] = { -1.0, 1.0, -9999.999, -9999.999 }; switch( num ){ case 0:// go through case 1: return 0.25 * etaAtEdge[num] * (invJacobMat.mat21*invJacobMat.mat12 - invJacobMat.mat11*invJacobMat.mat22 ); break; case 2:// go through case 3: return 0.25 * xiAtEdge[num] * (invJacobMat.mat22*invJacobMat.mat11 - invJacobMat.mat12*invJacobMat.mat21 ); break; default: OutputFiles::m_logFile << "Error : Wrong number in " << __FUNCTION__ <<" : num = " << num << std::endl; exit(1); break; } } // Calculate jacobian matrix of the elements double Forward3DNonConformingHexaElement0thOrder::calcJacobianMatrix( const int elemID, const double xi, const double eta, const double zeta, Forward3D::Matrix3x3& JacobMat ) const{ double xCoord[8] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; double yCoord[8] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; double zCoord[8] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; for( int i = 0; i < 8; ++i ){ const int nodeID = m_MeshDataNonConformingHexaElement.getNodesOfElements(elemID, i); xCoord[i] = m_MeshDataNonConformingHexaElement.getXCoordinatesOfNodes(nodeID); yCoord[i] = m_MeshDataNonConformingHexaElement.getYCoordinatesOfNodes(nodeID); zCoord[i] = m_MeshDataNonConformingHexaElement.getZCoordinatesOfNodes(nodeID); } // Zero clear JacobMat.mat11 = 0.0; JacobMat.mat12 = 0.0; JacobMat.mat13 = 0.0; JacobMat.mat21 = 0.0; JacobMat.mat22 = 0.0; JacobMat.mat23 = 0.0; JacobMat.mat31 = 0.0; JacobMat.mat32 = 0.0; JacobMat.mat33 = 0.0; for( int i = 0; i < 8; ++i ){ const double xiNode = m_xiAtNode[i]; const double etaNode = m_etaAtNode[i]; const double zetaNode = m_zetaAtNode[i]; const double tmp1 = 0.125 * xiNode * (1.0 + etaNode * eta) * (1.0 + zetaNode * zeta); const double tmp2 = 0.125 * etaNode * (1.0 + zetaNode * zeta) * (1.0 + xiNode * xi); const double tmp3 = 0.125 * zetaNode * (1.0 + xiNode * xi) * (1.0 + etaNode * eta); JacobMat.mat11 += tmp1 * xCoord[i]; JacobMat.mat12 += tmp1 * yCoord[i]; JacobMat.mat13 += tmp1 * zCoord[i]; JacobMat.mat21 += tmp2 * xCoord[i]; JacobMat.mat22 += tmp2 * yCoord[i]; JacobMat.mat23 += tmp2 * zCoord[i]; JacobMat.mat31 += tmp3 * xCoord[i]; JacobMat.mat32 += tmp3 * yCoord[i]; JacobMat.mat33 += tmp3 * zCoord[i]; } const double determinant = JacobMat.mat11 * JacobMat.mat22 * JacobMat.mat33 + JacobMat.mat12 * JacobMat.mat23 * JacobMat.mat31 + JacobMat.mat13 * JacobMat.mat21 * JacobMat.mat32 - JacobMat.mat13 * JacobMat.mat22 * JacobMat.mat31 - JacobMat.mat12 * JacobMat.mat21 * JacobMat.mat33 - JacobMat.mat11 * JacobMat.mat23 * JacobMat.mat32; return determinant; } // Calculate inverse of jacobian matrix multiplied by determinant void Forward3DNonConformingHexaElement0thOrder::calcInverseOfJacobianMatrix( const Forward3D::Matrix3x3& jacobMat, const double determinant, Forward3D::Matrix3x3& invJacobMat ) const{ const double invDet = 1.0 / determinant; invJacobMat.mat11 = ( jacobMat.mat22 * jacobMat.mat33 - jacobMat.mat23 * jacobMat.mat32 ) * invDet; invJacobMat.mat12 = ( jacobMat.mat13 * jacobMat.mat32 - jacobMat.mat12 * jacobMat.mat33 ) * invDet; invJacobMat.mat13 = ( jacobMat.mat12 * jacobMat.mat23 - jacobMat.mat13 * jacobMat.mat22 ) * invDet; invJacobMat.mat21 = ( jacobMat.mat23 * jacobMat.mat31 - jacobMat.mat21 * jacobMat.mat33 ) * invDet; invJacobMat.mat22 = ( jacobMat.mat11 * jacobMat.mat33 - jacobMat.mat13 * jacobMat.mat31 ) * invDet; invJacobMat.mat23 = ( jacobMat.mat13 * jacobMat.mat21 - jacobMat.mat11 * jacobMat.mat23 ) * invDet; invJacobMat.mat31 = ( jacobMat.mat21 * jacobMat.mat32 - jacobMat.mat22 * jacobMat.mat31 ) * invDet; invJacobMat.mat32 = ( jacobMat.mat12 * jacobMat.mat31 - jacobMat.mat11 * jacobMat.mat32 ) * invDet; invJacobMat.mat33 = ( jacobMat.mat11 * jacobMat.mat22 - jacobMat.mat12 * jacobMat.mat21 ) * invDet; } // Output results of forward calculation to VTK file void Forward3DNonConformingHexaElement0thOrder::outputResultToVTK() const{ if( !OutputFiles::m_vtkFile.is_open() ){ return; } const AnalysisControl* const pAnalysisControl = AnalysisControl::getInstance(); std::string stringPolarization; const int iPol = getPolarizationCurrent(); if( iPol == CommonParameters::EX_POLARIZATION ){// Ex Polarization //stringPolarization = "Ex_polarization"; stringPolarization = "ExPol"; }else{// Ey Polarization //stringPolarization = "Ey_polarization"; stringPolarization = "EyPol"; } //--- Total element number const int nElem = m_MeshDataNonConformingHexaElement.getNumElemTotal(); const double freq = getFrequencyCurrent(); if( pAnalysisControl->doesOutputToVTK( AnalysisControl::OUTPUT_ELECTRIC_FIELD_VECTORS_TO_VTK ) ){// Output electric field vector OutputFiles::m_vtkFile << "VECTORS Re(E)_" << freq <<"(Hz)_" << stringPolarization << " float" << std::endl; for( int iElem = 0 ; iElem < nElem; ++iElem ){ const float Ex = static_cast( real( calcValueElectricFieldXDirection( iElem, 0.0, 0.0, 0.0 ) ) ); const float Ey = static_cast( real( calcValueElectricFieldYDirection( iElem, 0.0, 0.0, 0.0 ) ) ); const float Ez = static_cast( real( calcValueElectricFieldZDirection( iElem, 0.0, 0.0, 0.0 ) ) ); OutputFiles::m_vtkFile << Ex << " " << Ey << " " << Ez << std::endl; } OutputFiles::m_vtkFile << "VECTORS Im(E)_" << freq <<"(Hz)_" << stringPolarization << " float" << std::endl; for( int iElem = 0 ; iElem < nElem; ++iElem ){ const float Ex = static_cast( imag( calcValueElectricFieldXDirection( iElem, 0.0, 0.0, 0.0 ) ) ); const float Ey = static_cast( imag( calcValueElectricFieldYDirection( iElem, 0.0, 0.0, 0.0 ) ) ); const float Ez = static_cast( imag( calcValueElectricFieldZDirection( iElem, 0.0, 0.0, 0.0 ) ) ); OutputFiles::m_vtkFile << Ex << " " << Ey << " " << Ez << std::endl; } } if( pAnalysisControl->doesOutputToVTK( AnalysisControl::OUTPUT_MAGNETIC_FIELD_VECTORS_TO_VTK ) ){// Output magnetic field vector OutputFiles::m_vtkFile << "VECTORS Re(H)_" << freq <<"(Hz)_" << stringPolarization << " float" << std::endl; for( int iElem = 0 ; iElem < nElem; ++iElem ){ const float Hx = static_cast( real( calcValueMagneticFieldXDirection( iElem, 0.0, 0.0, 0.0 ) ) ); const float Hy = static_cast( real( calcValueMagneticFieldYDirection( iElem, 0.0, 0.0, 0.0 ) ) ); const float Hz = static_cast( real( calcValueMagneticFieldZDirection( iElem, 0.0, 0.0, 0.0 ) ) ); OutputFiles::m_vtkFile << Hx << " " << Hy << " " << Hz << std::endl; } OutputFiles::m_vtkFile << "VECTORS Im(H)_" << freq <<"(Hz)_" << stringPolarization << " float" << std::endl; for( int iElem = 0 ; iElem < nElem; ++iElem ){ const float Hx = static_cast( imag( calcValueMagneticFieldXDirection( iElem, 0.0, 0.0, 0.0 ) ) ); const float Hy = static_cast( imag( calcValueMagneticFieldYDirection( iElem, 0.0, 0.0, 0.0 ) ) ); const float Hz = static_cast( imag( calcValueMagneticFieldZDirection( iElem, 0.0, 0.0, 0.0 ) ) ); OutputFiles::m_vtkFile << Hx << " " << Hy << " " << Hz << std::endl; } } if( pAnalysisControl->doesOutputToVTK( AnalysisControl::OUTPUT_CURRENT_DENSITY ) ){// Output corrent density const ResistivityBlock* pResistivityBlock = ResistivityBlock::getInstance(); OutputFiles::m_vtkFile << "VECTORS Re(j)_" << freq <<"(Hz)_" << stringPolarization << " float" << std::endl; for( int iElem = 0 ; iElem < nElem; ++iElem ){ const double sigma = pResistivityBlock->getConductivityValuesFromElemID(iElem); const float jx = static_cast( sigma * real( calcValueElectricFieldXDirection( iElem, 0.0, 0.0, 0.0 ) ) ); const float jy = static_cast( sigma * real( calcValueElectricFieldYDirection( iElem, 0.0, 0.0, 0.0 ) ) ); const float jz = static_cast( sigma * real( calcValueElectricFieldZDirection( iElem, 0.0, 0.0, 0.0 ) ) ); OutputFiles::m_vtkFile << jx << " " << jy << " " << jz << std::endl; } OutputFiles::m_vtkFile << "VECTORS Im(j)_" << freq <<"(Hz)_" << stringPolarization << " float" << std::endl; for( int iElem = 0 ; iElem < nElem; ++iElem ){ const double sigma = pResistivityBlock->getConductivityValuesFromElemID(iElem); const float jx = static_cast( sigma * imag( calcValueElectricFieldXDirection( iElem, 0.0, 0.0, 0.0 ) ) ); const float jy = static_cast( sigma * imag( calcValueElectricFieldYDirection( iElem, 0.0, 0.0, 0.0 ) ) ); const float jz = static_cast( sigma * imag( calcValueElectricFieldZDirection( iElem, 0.0, 0.0, 0.0 ) ) ); OutputFiles::m_vtkFile << jx << " " << jy << " " << jz << std::endl; } } } // Output results of forward calculation to binary file void Forward3DNonConformingHexaElement0thOrder::outputResultToBinary( const int iFreq, const int iPol ) const{ const std::string stringPolarization = iPol == CommonParameters::EX_POLARIZATION ? "ExPol" : "EyPol"; const AnalysisControl* const pAnalysisControl = AnalysisControl::getInstance(); //--- Total element number const int nElem = m_MeshDataNonConformingHexaElement.getNumElemTotal(); const double freq = getFrequencyCurrent(); if( pAnalysisControl->doesOutputToVTK( AnalysisControl::OUTPUT_ELECTRIC_FIELD_VECTORS_TO_VTK ) ){ // Output real part of electric field vector std::ostringstream oss; oss << "ReE_Freq" << iFreq << "_" << stringPolarization << ".iter" << pAnalysisControl->getIterationNumCurrent(); std::ofstream fout; fout.open( oss.str().c_str(), std::ios::out | std::ios::binary | std::ios::trunc ); char line[80]; std::ostringstream ossTitle; ossTitle << "Real(E) of " << stringPolarization << " at " << freq << " [Hz]"; strcpy( line, ossTitle.str().c_str() ); fout.write( line, 80 ); strcpy( line, "part" ); fout.write( line, 80 ); int ibuf(1); fout.write( (char*) &ibuf, sizeof( int ) ); strcpy( line, "hexa8" ); fout.write( line, 80 ); for( int iElem = 0 ; iElem < nElem; ++iElem ){ float Ex = static_cast( real( calcValueElectricFieldXDirection( iElem, 0.0, 0.0, 0.0 ) ) ); fout.write( (char*) &Ex, sizeof( float ) ); } for( int iElem = 0 ; iElem < nElem; ++iElem ){ float Ey = static_cast( real( calcValueElectricFieldYDirection( iElem, 0.0, 0.0, 0.0 ) ) ); fout.write( (char*) &Ey, sizeof( float ) ); } for( int iElem = 0 ; iElem < nElem; ++iElem ){ float Ez = static_cast( real( calcValueElectricFieldZDirection( iElem, 0.0, 0.0, 0.0 ) ) ); fout.write( (char*) &Ez, sizeof( float ) ); } fout.close(); } if( pAnalysisControl->doesOutputToVTK( AnalysisControl::OUTPUT_ELECTRIC_FIELD_VECTORS_TO_VTK ) ){ // Output imaginary part of electric field vector std::ostringstream oss; oss << "ImE_Freq" << iFreq << "_" << stringPolarization << ".iter" << pAnalysisControl->getIterationNumCurrent(); std::ofstream fout; fout.open( oss.str().c_str(), std::ios::out | std::ios::binary | std::ios::trunc ); char line[80]; std::ostringstream ossTitle; ossTitle << "Imag(E) of " << stringPolarization << " at " << freq << " [Hz]"; strcpy( line, ossTitle.str().c_str() ); fout.write( line, 80 ); strcpy( line, "part" ); fout.write( line, 80 ); int ibuf(1); fout.write( (char*) &ibuf, sizeof( int ) ); strcpy( line, "hexa8" ); fout.write( line, 80 ); for( int iElem = 0 ; iElem < nElem; ++iElem ){ float Ex = static_cast( imag( calcValueElectricFieldXDirection( iElem, 0.0, 0.0, 0.0 ) ) ); fout.write( (char*) &Ex, sizeof( float ) ); } for( int iElem = 0 ; iElem < nElem; ++iElem ){ float Ey = static_cast( imag( calcValueElectricFieldYDirection( iElem, 0.0, 0.0, 0.0 ) ) ); fout.write( (char*) &Ey, sizeof( float ) ); } for( int iElem = 0 ; iElem < nElem; ++iElem ){ float Ez = static_cast( imag( calcValueElectricFieldZDirection( iElem, 0.0, 0.0, 0.0 ) ) ); fout.write( (char*) &Ez, sizeof( float ) ); } fout.close(); } if( pAnalysisControl->doesOutputToVTK( AnalysisControl::OUTPUT_MAGNETIC_FIELD_VECTORS_TO_VTK ) ){ // Output real part of magnetic field vector std::ostringstream oss; oss << "ReH_Freq" << iFreq << "_" << stringPolarization << ".iter" << pAnalysisControl->getIterationNumCurrent(); std::ofstream fout; fout.open( oss.str().c_str(), std::ios::out | std::ios::binary | std::ios::trunc ); char line[80]; std::ostringstream ossTitle; ossTitle << "Real(H) of " << stringPolarization << " at " << freq << " [Hz]"; strcpy( line, ossTitle.str().c_str() ); fout.write( line, 80 ); strcpy( line, "part" ); fout.write( line, 80 ); int ibuf(1); fout.write( (char*) &ibuf, sizeof( int ) ); strcpy( line, "hexa8" ); fout.write( line, 80 ); for( int iElem = 0 ; iElem < nElem; ++iElem ){ float Hx = static_cast( real( calcValueMagneticFieldXDirection( iElem, 0.0, 0.0, 0.0 ) ) ); fout.write( (char*) &Hx, sizeof( float ) ); } for( int iElem = 0 ; iElem < nElem; ++iElem ){ float Hy = static_cast( real( calcValueMagneticFieldYDirection( iElem, 0.0, 0.0, 0.0 ) ) ); fout.write( (char*) &Hy, sizeof( float ) ); } for( int iElem = 0 ; iElem < nElem; ++iElem ){ float Hz = static_cast( real( calcValueMagneticFieldZDirection( iElem, 0.0, 0.0, 0.0 ) ) ); fout.write( (char*) &Hz, sizeof( float ) ); } fout.close(); } if( pAnalysisControl->doesOutputToVTK( AnalysisControl::OUTPUT_MAGNETIC_FIELD_VECTORS_TO_VTK ) ){ // Output imaginary part of magnetic field vector const ResistivityBlock* const pResistivityBlock = ResistivityBlock::getInstance(); std::ostringstream oss; oss << "ImH_Freq" << iFreq << "_" << stringPolarization << ".iter" << pAnalysisControl->getIterationNumCurrent(); std::ofstream fout; fout.open( oss.str().c_str(), std::ios::out | std::ios::binary | std::ios::trunc ); char line[80]; std::ostringstream ossTitle; ossTitle << "Imag(H) of " << stringPolarization << " at " << freq << " [Hz]"; strcpy( line, ossTitle.str().c_str() ); fout.write( line, 80 ); strcpy( line, "part" ); fout.write( line, 80 ); int ibuf(1); fout.write( (char*) &ibuf, sizeof( int ) ); strcpy( line, "hexa8" ); fout.write( line, 80 ); for( int iElem = 0 ; iElem < nElem; ++iElem ){ float Hx = static_cast( imag( calcValueMagneticFieldXDirection( iElem, 0.0, 0.0, 0.0 ) ) ); fout.write( (char*) &Hx, sizeof( float ) ); } for( int iElem = 0 ; iElem < nElem; ++iElem ){ float Hy = static_cast( imag( calcValueMagneticFieldYDirection( iElem, 0.0, 0.0, 0.0 ) ) ); fout.write( (char*) &Hy, sizeof( float ) ); } for( int iElem = 0 ; iElem < nElem; ++iElem ){ float Hz = static_cast( imag( calcValueMagneticFieldZDirection( iElem, 0.0, 0.0, 0.0 ) ) ); fout.write( (char*) &Hz, sizeof( float ) ); } fout.close(); } if( pAnalysisControl->doesOutputToVTK( AnalysisControl::OUTPUT_CURRENT_DENSITY ) ){ // Output real part of corrent density const ResistivityBlock* const pResistivityBlock = ResistivityBlock::getInstance(); std::ostringstream oss; oss << "Rej_Freq" << iFreq << "_" << stringPolarization << ".iter" << pAnalysisControl->getIterationNumCurrent(); std::ofstream fout; fout.open( oss.str().c_str(), std::ios::out | std::ios::binary | std::ios::trunc ); char line[80]; std::ostringstream ossTitle; ossTitle << "Real(j) of " << stringPolarization << " at " << freq << " [Hz]"; strcpy( line, ossTitle.str().c_str() ); fout.write( line, 80 ); strcpy( line, "part" ); fout.write( line, 80 ); int ibuf(1); fout.write( (char*) &ibuf, sizeof( int ) ); strcpy( line, "hexa8" ); fout.write( line, 80 ); for( int iElem = 0 ; iElem < nElem; ++iElem ){ const double sigma = pResistivityBlock->getConductivityValuesFromElemID(iElem); float jx = static_cast( sigma * real( calcValueElectricFieldXDirection( iElem, 0.0, 0.0, 0.0 ) ) ); fout.write( (char*) &jx, sizeof( float ) ); } for( int iElem = 0 ; iElem < nElem; ++iElem ){ const double sigma = pResistivityBlock->getConductivityValuesFromElemID(iElem); float jy = static_cast( sigma * real( calcValueElectricFieldYDirection( iElem, 0.0, 0.0, 0.0 ) ) ); fout.write( (char*) &jy, sizeof( float ) ); } for( int iElem = 0 ; iElem < nElem; ++iElem ){ const double sigma = pResistivityBlock->getConductivityValuesFromElemID(iElem); float jz = static_cast( sigma * real( calcValueElectricFieldZDirection( iElem, 0.0, 0.0, 0.0 ) ) ); fout.write( (char*) &jz, sizeof( float ) ); } fout.close(); } if( pAnalysisControl->doesOutputToVTK( AnalysisControl::OUTPUT_CURRENT_DENSITY ) ){ // Output imaginary part of corrent density const ResistivityBlock* const pResistivityBlock = ResistivityBlock::getInstance(); std::ostringstream oss; oss << "Imj_Freq" << iFreq << "_" << stringPolarization << ".iter" << pAnalysisControl->getIterationNumCurrent(); std::ofstream fout; fout.open( oss.str().c_str(), std::ios::out | std::ios::binary | std::ios::trunc ); char line[80]; std::ostringstream ossTitle; ossTitle << "Imag(j) of " << stringPolarization << " at " << freq << " [Hz]"; strcpy( line, ossTitle.str().c_str() ); fout.write( line, 80 ); strcpy( line, "part" ); fout.write( line, 80 ); int ibuf(1); fout.write( (char*) &ibuf, sizeof( int ) ); strcpy( line, "hexa8" ); fout.write( line, 80 ); for( int iElem = 0 ; iElem < nElem; ++iElem ){ const double sigma = pResistivityBlock->getConductivityValuesFromElemID(iElem); float jx = static_cast( sigma * imag( calcValueElectricFieldXDirection( iElem, 0.0, 0.0, 0.0 ) ) ); fout.write( (char*) &jx, sizeof( float ) ); } for( int iElem = 0 ; iElem < nElem; ++iElem ){ const double sigma = pResistivityBlock->getConductivityValuesFromElemID(iElem); float jy = static_cast( sigma * imag( calcValueElectricFieldYDirection( iElem, 0.0, 0.0, 0.0 ) ) ); fout.write( (char*) &jy, sizeof( float ) ); } for( int iElem = 0 ; iElem < nElem; ++iElem ){ const double sigma = pResistivityBlock->getConductivityValuesFromElemID(iElem); float jz = static_cast( sigma * imag( calcValueElectricFieldZDirection( iElem, 0.0, 0.0, 0.0 ) ) ); fout.write( (char*) &jz, sizeof( float ) ); } fout.close(); } } // Add values to right-hand sides matrix consisting of interpolator vectors by taking into account MPC void Forward3DNonConformingHexaElement0thOrder::addValuesToRhsVectorsByConsideringMPC( const int irow, const int irhs, const std::complex& val ){ const std::vector< std::pair >& rowMasters= m_slaveDofToMasterDofAndFactors[irow]; for( std::vector< std::pair >::const_iterator itrRow = rowMasters.begin(); itrRow != rowMasters.end(); ++itrRow ){ const int iRowMod = m_IDsAfterDegenerated2AfterConstrained[itrRow->first]; const std::complex valMod = val * std::complex(itrRow->second, 0.0); addValuesToRhsVectors( iRowMod, irhs, valMod ); } } //// Make pair of master dof and factor for a slave dof //void Forward3DNonConformingHexaElement0thOrder::makePairOfMasterDofAndFactorForASlaveDof( const int slaveDofAfterDegenerated, std::vector< std::pair >& masterDofAndFactorsAfterDegenerated ) const{ // // std::map< int, std::vector< std::pair > > masterDofBeforeDegeneratedAndFactorsAll; // // const int slaveDofBeforeDegenerated = getDofBeforeDegenerationFromDofAfterDegeneration(slaveDofAfterDegenerated); // // std::vector< std::pair >& masterDofBeforeDegeneratedAndFactors = masterDofBeforeDegeneratedAndFactorsAll[slaveDofBeforeDegenerated]; // if( static_cast( masterDofBeforeDegeneratedAndFactors.size() ) == 0 ){ // // This dof is master // masterDofAndFactorsAfterDegenerated.push_back( std::make_pair(slaveDofAfterDegenerated, 1.0) ); // return; // } // // // This dof depends on some master dofs // std::vector< std::pair > masterDofAndFactorsBeforeDegenerated; // //for( std::vector< std::pair >::const_iterator itr = masterDofBeforeDegeneratedAndFactors.begin(); itr != masterDofBeforeDegeneratedAndFactors.end(); ++itr ){ // // const int masterDofBeforeDegenerated = itr->first; // // const double factor = itr->second; // // masterDofAndFactorsBeforeDegenerated.push_back( std::make_pair(masterDofBeforeDegenerated, factor) ); // //} // masterDofAndFactorsBeforeDegenerated.push_back( std::make_pair(slaveDofBeforeDegenerated, 1.0) ); // // bool found(true); // while (found){ // found = false; // for( std::vector< std::pair >::iterator itr = masterDofAndFactorsBeforeDegenerated.begin(); itr != masterDofAndFactorsBeforeDegenerated.end(); ++itr ){ // const int masterDofBeforeDegeneratedOrg = itr->first; // std::vector< std::pair > masterDofAndFactorsBeforeDegeneratedAux; // makePairOfMasterDofAndFactorForASlaveDofAux( masterDofBeforeDegeneratedOrg, masterDofAndFactorsBeforeDegeneratedAux ); // if( static_cast( masterDofAndFactorsBeforeDegeneratedAux.size() ) == 0 ){ // // The dof does not has masters // continue; // } // // The dofhas masters // found = true; // const double factorOrg = itr->second; // std::vector< std::pair >::const_iterator itrSub = masterDofAndFactorsBeforeDegeneratedAux.begin(); // itr->first = itrSub->first;// Replace dof // itr->second = factorOrg * itrSub->second;// Replace factor // for( ; itrSub != masterDofAndFactorsBeforeDegeneratedAux.end(); ++itrSub ){ // const int masterDofBeforeDegenerated = itrSub->first; // const double factor = factorOrg * itrSub->second; // masterDofAndFactorsBeforeDegenerated.push_back( std::make_pair(masterDofBeforeDegenerated, factor) ); // } // } // } // // const int iPol = CommonParameters::EX_POLARIZATION;// Constraint matrix does not depend on the type of polarization // for( std::vector< std::pair >::const_iterator itr = masterDofAndFactorsBeforeDegenerated.begin(); itr != masterDofAndFactorsBeforeDegenerated.end(); ++itr ){ // const int dofBeforeDegenerated = itr->first; // const double factor = itr->second; // //std::map::const_iterator itrBeforeToAfter = arrayDofBeforeDegeneratedToAfterDegenerated.find(dofBeforeDegenerated); // //if( itrBeforeToAfter == arrayDofBeforeDegeneratedToAfterDegenerated.end() ){ // // OutputFiles::m_logFile << "Error : Key " << dofBeforeDegenerated << " is not found in arrayDofBeforeDegeneratedToAfterDegenerated." << std::endl; // // exit(1); // //} // //masterDofAndFactorsAfterDegenerated.push_back( std::make_pair( itrBeforeToAfter->second, factor ) ); // const int dofAfterDegenerated = m_IDsGlobal2AfterDegenerated[iPol][dofBeforeDegenerated]; // masterDofAndFactorsAfterDegenerated.push_back( std::make_pair( dofAfterDegenerated, factor ) ); // } // //} // //void Forward3DNonConformingHexaElement0thOrder::makePairOfMasterDofAndFactorForASlaveDofAux( const int slaveDofBeforeDegenerated, std::vector< std::pair >& masterDofAndFactorsBeforeDegenerated ) const{ // // std::map< int, std::vector< std::pair > > masterDofBeforeDegeneratedAndFactorsAll; // // std::vector< std::pair >& masterDofBeforeDegeneratedAndFactors = masterDofBeforeDegeneratedAndFactorsAll[slaveDofBeforeDegenerated]; // if( static_cast( masterDofBeforeDegeneratedAndFactors.size() ) == 0 ){ // return; // } // // // This dof depends on some master dofs // for( std::vector< std::pair >::const_iterator itr = masterDofBeforeDegeneratedAndFactors.begin(); itr != masterDofBeforeDegeneratedAndFactors.end(); ++itr ){ // const int masterDofBeforeDegenerated = itr->first; // const double factor = itr->second; // masterDofAndFactorsBeforeDegenerated.push_back( std::make_pair(masterDofBeforeDegenerated, factor) ); // } // //} // //// Get dof before degeneration from the after degeneration //int Forward3DNonConformingHexaElement0thOrder::getDofBeforeDegenerationFromDofAfterDegeneration( const int dofAfterDegeneration ) const{ // // //}