//------------------------------------------------------------------------------------------------------- // 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 #include #include #include #include #include #include "ObservedDataStationHTF.h" #include "OutputFiles.h" #include "CommonParameters.h" #include "ResistivityBlock.h" // Constructer ObservedDataStationHTF::ObservedDataStationHTF(): ObservedDataStationPoint(), m_TxxObserved(NULL), m_TxyObserved(NULL), m_TyxObserved(NULL), m_TyyObserved(NULL), m_TxxSD(NULL), m_TxySD(NULL), m_TyxSD(NULL), m_TyySD(NULL), m_TxxCalculated(NULL), m_TxyCalculated(NULL), m_TyxCalculated(NULL), m_TyyCalculated(NULL), m_TxxResidual(NULL), m_TxyResidual(NULL), m_TyxResidual(NULL), m_TyyResidual(NULL), m_dataIDOfTxx(NULL), m_dataIDOfTxy(NULL), m_dataIDOfTyx(NULL), m_dataIDOfTyy(NULL) { } // Destructer ObservedDataStationHTF::~ObservedDataStationHTF(){ if( m_TxxObserved != NULL){ delete[] m_TxxObserved; m_TxxObserved = NULL; } if( m_TxyObserved != NULL){ delete[] m_TxyObserved; m_TxyObserved = NULL; } if( m_TyxObserved != NULL){ delete[] m_TyxObserved; m_TyxObserved = NULL; } if( m_TyyObserved != NULL){ delete[] m_TyyObserved; m_TyyObserved = NULL; } if( m_TxxSD != NULL){ delete[] m_TxxSD; m_TxxSD = NULL; } if( m_TxySD != NULL){ delete[] m_TxySD; m_TxySD = NULL; } if( m_TyxSD != NULL){ delete[] m_TyxSD; m_TyxSD = NULL; } if( m_TyySD != NULL){ delete[] m_TyySD; m_TyySD = NULL; } if( m_TxxCalculated != NULL){ delete[] m_TxxCalculated; m_TxxCalculated = NULL; } if( m_TxyCalculated != NULL){ delete[] m_TxyCalculated; m_TxyCalculated = NULL; } if( m_TyxCalculated != NULL){ delete[] m_TyxCalculated; m_TyxCalculated = NULL; } if( m_TyyCalculated != NULL){ delete[] m_TyyCalculated; m_TyyCalculated = NULL; } if( m_TxxResidual != NULL){ delete[] m_TxxResidual; m_TxxResidual = NULL; } if( m_TxyResidual != NULL){ delete[] m_TxyResidual; m_TxyResidual = NULL; } if( m_TyxResidual != NULL){ delete[] m_TyxResidual; m_TyxResidual = NULL; } if( m_TyyResidual != NULL){ delete[] m_TyyResidual; m_TyyResidual = NULL; } if( m_dataIDOfTxx != NULL){ delete[] m_dataIDOfTxx; m_dataIDOfTxx = NULL; } if( m_dataIDOfTxy != NULL){ delete[] m_dataIDOfTxy; m_dataIDOfTxy = NULL; } if( m_dataIDOfTyx != NULL){ delete[] m_dataIDOfTyx; m_dataIDOfTyx = NULL; } if( m_dataIDOfTyy != NULL){ delete[] m_dataIDOfTyy; m_dataIDOfTyy = NULL; } } // Read data from input file void ObservedDataStationHTF::inputObservedData( std::ifstream& inFile ){ inFile >> m_stationID; inFile >> m_IDOfMagneticFieldStation; if( m_stationID == m_IDOfMagneticFieldStation ){ OutputFiles::m_logFile << "HTF station (" << m_stationID << ") must be different from its reference station (" << m_IDOfMagneticFieldStation << ") !!" << std::endl; exit(1); } OutputFiles::m_logFile << "# " << std::setw(15) << std::left << m_stationID << std::setw(18) << std::left << m_IDOfMagneticFieldStation; const AnalysisControl* const pAnalysisControl = AnalysisControl::getInstance(); // Type of owner element int ownerType(-1); std::string ownerElemType; if( pAnalysisControl->isTypeOfOwnerElementSetIndivisually() ){ // Owner element type of each site is specified inFile >> ownerType; } else{ ownerType = pAnalysisControl->getTypeOfOwnerElement(); } switch(ownerType){ case AnalysisControl::USE_LOWER_ELEMENT: m_useUpperElementForInterpolationOfEMField = false; ownerElemType = "Lower"; break; case AnalysisControl::USE_UPPER_ELEMENT: m_useUpperElementForInterpolationOfEMField = true; ownerElemType = "Upper"; break; default: OutputFiles::m_logFile << std::endl << "Error : Unknown type of owner element : " << ownerType << std::endl; exit(1); break; } OutputFiles::m_logFile << std::left << ownerElemType << std::endl; double dbuf(0.0); inFile >> dbuf; m_location.X = dbuf * CommonParameters::convKilometerToMeter; inFile >> dbuf; m_location.Y = dbuf * CommonParameters::convKilometerToMeter; inFile >> m_numOfFrequency; const int nFreq = m_numOfFrequency; if( nFreq > 0 ){ m_freq = new double[nFreq]; m_TxxObserved = new std::complex[nFreq]; m_TxyObserved = new std::complex[nFreq]; m_TyxObserved = new std::complex[nFreq]; m_TyyObserved = new std::complex[nFreq]; m_TxxSD = new CommonParameters::DoubleComplexValues[nFreq]; m_TxySD = new CommonParameters::DoubleComplexValues[nFreq]; m_TyxSD = new CommonParameters::DoubleComplexValues[nFreq]; m_TyySD = new CommonParameters::DoubleComplexValues[nFreq]; for( int i = 0; i < nFreq; ++i ){ inFile >> m_freq[i]; double dbuf1(0.0); double dbuf2(0.0); inFile >> dbuf1 >> dbuf2; m_TxxObserved[i] = std::complex(dbuf1,dbuf2); inFile >> dbuf1 >> dbuf2; m_TxyObserved[i] = std::complex(dbuf1,dbuf2); inFile >> dbuf1 >> dbuf2; m_TyxObserved[i] = std::complex(dbuf1,dbuf2); inFile >> dbuf1 >> dbuf2; m_TyyObserved[i] = std::complex(dbuf1,dbuf2); inFile >> m_TxxSD[i].realPart; inFile >> m_TxxSD[i].imagPart; inFile >> m_TxySD[i].realPart; inFile >> m_TxySD[i].imagPart; inFile >> m_TyxSD[i].realPart; inFile >> m_TyxSD[i].imagPart; inFile >> m_TyySD[i].realPart; inFile >> m_TyySD[i].imagPart; } } #ifdef _DEBUG_WRITE std::cout << " HTF " << m_stationID << " " << m_IDOfMagneticFieldStation << std::endl; std::cout << m_location.X << " " << m_location.Y << std::endl; std::cout << m_numOfFrequency << std::endl; for( int i = 0; i < m_numOfFrequency; ++i ){ std::cout << m_freq[i] << " " << m_TxxObserved[i] << " " << m_TxyObserved[i] << " " << m_TyxObserved[i] << " " << m_TyyObserved[i] << " " << m_TxxSD[i].realPart << " " << m_TxxSD[i].imagPart << " " << m_TxySD[i].realPart << " " << m_TxySD[i].imagPart << " " << m_TyxSD[i].realPart << " " << m_TyxSD[i].imagPart << " " << m_TyySD[i].realPart << " " << m_TyySD[i].imagPart << std::endl; } #endif } // Calulate horizontal magnetic field transfer function void ObservedDataStationHTF::calculateHTF( const double freq, const ObservedDataStationPoint* const ptrStationOfMagneticField, int& icount ){ const int freqIDThisPEInSta = getFreqIDsAmongThisPE( freq ); if( freqIDThisPEInSta < 0 ){// Specified frequency is not the ones calculated by this PE in this station return; } const int freqIDGlobalInSta = m_freqIDsAmongThisStationCalculatedByThisPE[ freqIDThisPEInSta ]; const std::complex HxCalRef[2] = { ptrStationOfMagneticField->getHxCalculated( 0 ), ptrStationOfMagneticField->getHxCalculated( 1 ) }; const std::complex HyCalRef[2] = { ptrStationOfMagneticField->getHyCalculated( 0 ), ptrStationOfMagneticField->getHyCalculated( 1 ) }; const std::complex det = HxCalRef[0]*HyCalRef[1] - HxCalRef[1]*HyCalRef[0]; m_TxxCalculated[freqIDThisPEInSta] = ( m_HxCalculated[0]*HyCalRef[1] - m_HxCalculated[1]*HyCalRef[0] ) / det; m_TxyCalculated[freqIDThisPEInSta] = ( m_HxCalculated[1]*HxCalRef[0] - m_HxCalculated[0]*HxCalRef[1] ) / det; m_TyxCalculated[freqIDThisPEInSta] = ( m_HyCalculated[0]*HyCalRef[1] - m_HyCalculated[1]*HyCalRef[0] ) / det; m_TyyCalculated[freqIDThisPEInSta] = ( m_HyCalculated[1]*HxCalRef[0] - m_HyCalculated[0]*HxCalRef[1] ) / det; m_TxxResidual[freqIDThisPEInSta].realPart = ( m_TxxObserved[freqIDGlobalInSta].real() - m_TxxCalculated[freqIDThisPEInSta].real() ) / m_TxxSD[freqIDGlobalInSta].realPart; m_TxxResidual[freqIDThisPEInSta].imagPart = ( m_TxxObserved[freqIDGlobalInSta].imag() - m_TxxCalculated[freqIDThisPEInSta].imag() ) / m_TxxSD[freqIDGlobalInSta].imagPart; m_TxyResidual[freqIDThisPEInSta].realPart = ( m_TxyObserved[freqIDGlobalInSta].real() - m_TxyCalculated[freqIDThisPEInSta].real() ) / m_TxySD[freqIDGlobalInSta].realPart; m_TxyResidual[freqIDThisPEInSta].imagPart = ( m_TxyObserved[freqIDGlobalInSta].imag() - m_TxyCalculated[freqIDThisPEInSta].imag() ) / m_TxySD[freqIDGlobalInSta].imagPart; m_TyxResidual[freqIDThisPEInSta].realPart = ( m_TyxObserved[freqIDGlobalInSta].real() - m_TyxCalculated[freqIDThisPEInSta].real() ) / m_TyxSD[freqIDGlobalInSta].realPart; m_TyxResidual[freqIDThisPEInSta].imagPart = ( m_TyxObserved[freqIDGlobalInSta].imag() - m_TyxCalculated[freqIDThisPEInSta].imag() ) / m_TyxSD[freqIDGlobalInSta].imagPart; m_TyyResidual[freqIDThisPEInSta].realPart = ( m_TyyObserved[freqIDGlobalInSta].real() - m_TyyCalculated[freqIDThisPEInSta].real() ) / m_TyySD[freqIDGlobalInSta].realPart; m_TyyResidual[freqIDThisPEInSta].imagPart = ( m_TyyObserved[freqIDGlobalInSta].imag() - m_TyyCalculated[freqIDThisPEInSta].imag() ) / m_TyySD[freqIDGlobalInSta].imagPart; #ifdef _DEBUG_WRITE std::cout << "freqIDThisPEInSta Txx Txy Tyx Tyy : " << freqIDThisPEInSta << " " << m_TxxCalculated[freqIDThisPEInSta] << " " << m_TxyCalculated[freqIDThisPEInSta] << " " << m_TyxCalculated[freqIDThisPEInSta] << " " << m_TyyCalculated[freqIDThisPEInSta] << std::endl; #endif // For inversion m_dataIDOfTxx[freqIDThisPEInSta].realPart = icount++; m_dataIDOfTxx[freqIDThisPEInSta].imagPart = icount++; m_dataIDOfTxy[freqIDThisPEInSta].realPart = icount++; m_dataIDOfTxy[freqIDThisPEInSta].imagPart = icount++; m_dataIDOfTyx[freqIDThisPEInSta].realPart = icount++; m_dataIDOfTyx[freqIDThisPEInSta].imagPart = icount++; m_dataIDOfTyy[freqIDThisPEInSta].realPart = icount++; m_dataIDOfTyy[freqIDThisPEInSta].imagPart = icount++; } // Initialize horizontal magnetic field transfer functions and errors void ObservedDataStationHTF::initializeHTFsAndErrors(){ for( int i = 0; i < m_numOfFreqCalculatedByThisStaAndPE; ++i ){ m_TxxResidual[i].realPart = 0.0; m_TxxResidual[i].imagPart = 0.0; m_TxyResidual[i].realPart = 0.0; m_TxyResidual[i].imagPart = 0.0; m_TyxResidual[i].realPart = 0.0; m_TyxResidual[i].imagPart = 0.0; m_TyyResidual[i].realPart = 0.0; m_TyyResidual[i].imagPart = 0.0; m_TxxCalculated[i] = std::complex(0.0,0.0); m_TxyCalculated[i] = std::complex(0.0,0.0); m_TyxCalculated[i] = std::complex(0.0,0.0); m_TyyCalculated[i] = std::complex(0.0,0.0); } } // Allocate memory for the calculated values of horizontal magnetic field transfer functions and errors void ObservedDataStationHTF::allocateMemoryForCalculatedValues(){ if( m_TxxCalculated != NULL){ delete[] m_TxxCalculated; m_TxxCalculated = NULL; } if( m_TxyCalculated != NULL){ delete[] m_TxyCalculated; m_TxyCalculated = NULL; } if( m_TyxCalculated != NULL){ delete[] m_TyxCalculated; m_TyxCalculated = NULL; } if( m_TyyCalculated != NULL){ delete[] m_TyyCalculated; m_TyyCalculated = NULL; } if( m_TxxResidual != NULL){ delete[] m_TxxResidual; m_TxxResidual = NULL; } if( m_TxyResidual != NULL){ delete[] m_TxyResidual; m_TxyResidual = NULL; } if( m_TyxResidual != NULL){ delete[] m_TyxResidual; m_TyxResidual = NULL; } if( m_TyyResidual != NULL){ delete[] m_TyyResidual; m_TyyResidual = NULL; } if( m_dataIDOfTxx != NULL){ delete[] m_dataIDOfTxx; m_dataIDOfTxx = NULL; } if( m_dataIDOfTxy != NULL){ delete[] m_dataIDOfTxy; m_dataIDOfTxy = NULL; } if( m_dataIDOfTyx != NULL){ delete[] m_dataIDOfTyx; m_dataIDOfTyx = NULL; } if( m_dataIDOfTyy != NULL){ delete[] m_dataIDOfTyy; m_dataIDOfTyy = NULL; } if( m_numOfFreqCalculatedByThisStaAndPE > 0 ){ // If total number of frequencies calculated by this PE is not more than zero, do not allocate memory m_TxxCalculated = new std::complex[m_numOfFreqCalculatedByThisStaAndPE]; m_TxyCalculated = new std::complex[m_numOfFreqCalculatedByThisStaAndPE]; m_TyxCalculated = new std::complex[m_numOfFreqCalculatedByThisStaAndPE]; m_TyyCalculated = new std::complex[m_numOfFreqCalculatedByThisStaAndPE]; m_TxxResidual = new CommonParameters::DoubleComplexValues[m_numOfFreqCalculatedByThisStaAndPE]; m_TxyResidual = new CommonParameters::DoubleComplexValues[m_numOfFreqCalculatedByThisStaAndPE]; m_TyxResidual = new CommonParameters::DoubleComplexValues[m_numOfFreqCalculatedByThisStaAndPE]; m_TyyResidual = new CommonParameters::DoubleComplexValues[m_numOfFreqCalculatedByThisStaAndPE]; m_dataIDOfTxx = new CommonParameters::InitComplexValues[m_numOfFreqCalculatedByThisStaAndPE]; m_dataIDOfTxy = new CommonParameters::InitComplexValues[m_numOfFreqCalculatedByThisStaAndPE]; m_dataIDOfTyx = new CommonParameters::InitComplexValues[m_numOfFreqCalculatedByThisStaAndPE]; m_dataIDOfTyy = new CommonParameters::InitComplexValues[m_numOfFreqCalculatedByThisStaAndPE]; // Initialize for( int i = 0; i < m_numOfFreqCalculatedByThisStaAndPE; ++i ){ m_TxxCalculated[i] = std::complex(0.0,0.0); m_TxyCalculated[i] = std::complex(0.0,0.0); m_TyxCalculated[i] = std::complex(0.0,0.0); m_TyyCalculated[i] = std::complex(0.0,0.0); m_TxxResidual[i].realPart = 0.0; m_TxxResidual[i].imagPart = 0.0; m_TxyResidual[i].realPart = 0.0; m_TxyResidual[i].imagPart = 0.0; m_TyxResidual[i].realPart = 0.0; m_TyxResidual[i].imagPart = 0.0; m_TyyResidual[i].realPart = 0.0; m_TyyResidual[i].imagPart = 0.0; m_dataIDOfTxx[i].realPart = -1; m_dataIDOfTxx[i].imagPart = -1; m_dataIDOfTxy[i].realPart = -1; m_dataIDOfTxy[i].imagPart = -1; m_dataIDOfTyx[i].realPart = -1; m_dataIDOfTyx[i].imagPart = -1; m_dataIDOfTyy[i].realPart = -1; m_dataIDOfTyy[i].imagPart = -1; } } } // Output calculated values of horizontal magnetic field transfer functions void ObservedDataStationHTF::outputCalculatedValues() const{ int icount(0); for( std::vector::const_iterator itr = m_freqIDsAmongThisStationCalculatedByThisPE.begin(); itr != m_freqIDsAmongThisStationCalculatedByThisPE.end(); ++itr ){ fprintf( OutputFiles::m_csvFile, "%10d, %15.6e, %15.6e, %15.6e, %15.6e, %15.6e, %15.6e, %15.6e, %15.6e, %15.6e,", m_stationID, m_freq[*itr], m_TxxCalculated[icount].real(), m_TxxCalculated[icount].imag(), m_TxyCalculated[icount].real(), m_TxyCalculated[icount].imag(), m_TyxCalculated[icount].real(), m_TyxCalculated[icount].imag(), m_TyyCalculated[icount].real(), m_TyyCalculated[icount].imag() ); fprintf( OutputFiles::m_csvFile, " %15.6e, %15.6e, %15.6e, %15.6e, %15.6e, %15.6e, %15.6e, %15.6e,", m_TxxResidual[icount].realPart, m_TxxResidual[icount].imagPart, m_TxyResidual[icount].realPart, m_TxyResidual[icount].imagPart, m_TyxResidual[icount].realPart, m_TyxResidual[icount].imagPart, m_TyyResidual[icount].realPart, m_TyyResidual[icount].imagPart ); fprintf( OutputFiles::m_csvFile, " %15.6e, %15.6e, %15.6e, %15.6e, %15.6e, %15.6e, %15.6e, %15.6e,", m_TxxObserved[*itr].real(), m_TxxObserved[*itr].imag(), m_TxyObserved[*itr].real(), m_TxyObserved[*itr].imag(), m_TyxObserved[*itr].real(), m_TyxObserved[*itr].imag(), m_TyyObserved[*itr].real(), m_TyyObserved[*itr].imag() ); fprintf( OutputFiles::m_csvFile, " %15.6e, %15.6e, %15.6e, %15.6e, %15.6e, %15.6e, %15.6e, %15.6e,\n", m_TxxSD[*itr].realPart, m_TxxSD[*itr].imagPart, m_TxySD[*itr].realPart, m_TxySD[*itr].imagPart, m_TyxSD[*itr].realPart, m_TyxSD[*itr].imagPart, m_TyySD[*itr].realPart, m_TyySD[*itr].imagPart ); ++icount; } } // Calulate sensitivity matrix of horizontal magnetic field transfer functions void ObservedDataStationHTF::calculateSensitivityMatrix( const double freq, const int nModel, const ObservedDataStationPoint* const ptrStationOfMagneticField, const std::complex* const derivativesOfEMFieldExPol, const std::complex* const derivativesOfEMFieldEyPol, double* const sensitivityMatrix ) const{ const int freqIDThisPEInSta = getFreqIDsAmongThisPE( freq ); if( freqIDThisPEInSta < 0 ){// Specified frequency is not the ones calculated by this PE in this station return; } const int freqIDGlobalInSta = m_freqIDsAmongThisStationCalculatedByThisPE[ freqIDThisPEInSta ]; const std::complex HxCalRef[2] = { ptrStationOfMagneticField->getHxCalculated( 0 ), ptrStationOfMagneticField->getHxCalculated( 1 ) }; const std::complex HyCalRef[2] = { ptrStationOfMagneticField->getHyCalculated( 0 ), ptrStationOfMagneticField->getHyCalculated( 1 ) }; const std::complex det = HxCalRef[0]*HyCalRef[1] - HxCalRef[1]*HyCalRef[0]; const std::complex divDet = std::complex(1.0,0.0) / det; const std::complex divDet2 = divDet * divDet; const long long rhsVectorIDOfHxRef = static_cast(ptrStationOfMagneticField->getRhsVectorIDOfHx()); const long long rhsVectorIDOfHyRef = static_cast(ptrStationOfMagneticField->getRhsVectorIDOfHy()); const long long nBlkNotFixed = static_cast( ( ResistivityBlock::getInstance() )->getNumResistivityBlockNotFixed() ); for( long long imdl = 0; imdl < nBlkNotFixed; ++imdl ){ const std::complex work1 = derivativesOfEMFieldExPol[ nBlkNotFixed * rhsVectorIDOfHxRef + imdl ] * HyCalRef[1] + derivativesOfEMFieldEyPol[ nBlkNotFixed * rhsVectorIDOfHyRef + imdl ] * HxCalRef[0] - derivativesOfEMFieldEyPol[ nBlkNotFixed * rhsVectorIDOfHxRef + imdl ] * HyCalRef[0] - derivativesOfEMFieldExPol[ nBlkNotFixed * rhsVectorIDOfHyRef + imdl ] * HxCalRef[1]; // dTxx/dm const std::complex workXX1 = derivativesOfEMFieldExPol[ nBlkNotFixed * static_cast(m_rhsVectorIDOfHx) + imdl ] * HyCalRef[1] + derivativesOfEMFieldEyPol[ nBlkNotFixed * rhsVectorIDOfHyRef + imdl ] * m_HxCalculated[0] - derivativesOfEMFieldEyPol[ nBlkNotFixed * static_cast(m_rhsVectorIDOfHx) + imdl ] * HyCalRef[0] - derivativesOfEMFieldExPol[ nBlkNotFixed * rhsVectorIDOfHyRef + imdl ] * m_HxCalculated[1]; const std::complex workXX2 = m_HxCalculated[0]*HyCalRef[1] - m_HxCalculated[1]*HyCalRef[0]; sensitivityMatrix[ static_cast(nModel) * static_cast(m_dataIDOfTxx[freqIDThisPEInSta].realPart) + imdl ] = ( workXX1 * divDet - work1 * workXX2 * divDet2 ).real() / m_TxxSD[freqIDGlobalInSta].realPart; sensitivityMatrix[ static_cast(nModel) * static_cast(m_dataIDOfTxx[freqIDThisPEInSta].imagPart) + imdl ] = ( workXX1 * divDet - work1 * workXX2 * divDet2 ).imag() / m_TxxSD[freqIDGlobalInSta].imagPart; // dTxy/dm const std::complex workXY1 = derivativesOfEMFieldEyPol[ nBlkNotFixed * static_cast(m_rhsVectorIDOfHx) + imdl ] * HxCalRef[0] + derivativesOfEMFieldExPol[ nBlkNotFixed * rhsVectorIDOfHxRef + imdl ] * m_HxCalculated[1] - derivativesOfEMFieldExPol[ nBlkNotFixed * static_cast(m_rhsVectorIDOfHx) + imdl ] * HxCalRef[1] - derivativesOfEMFieldEyPol[ nBlkNotFixed * rhsVectorIDOfHxRef + imdl ] * m_HxCalculated[0]; const std::complex workXY2 = m_HxCalculated[1]*HxCalRef[0] - m_HxCalculated[0]*HxCalRef[1]; sensitivityMatrix[ static_cast(nModel) * static_cast(m_dataIDOfTxy[freqIDThisPEInSta].realPart) + imdl ] = ( workXY1 * divDet - work1 * workXY2 * divDet2 ).real() / m_TxySD[freqIDGlobalInSta].realPart; sensitivityMatrix[ static_cast(nModel) * static_cast(m_dataIDOfTxy[freqIDThisPEInSta].imagPart) + imdl ] = ( workXY1 * divDet - work1 * workXY2 * divDet2 ).imag() / m_TxySD[freqIDGlobalInSta].imagPart; // dTyx/dm const std::complex workYX1 = derivativesOfEMFieldExPol[ nBlkNotFixed * static_cast(m_rhsVectorIDOfHy) + imdl ] * HyCalRef[1] + derivativesOfEMFieldEyPol[ nBlkNotFixed * rhsVectorIDOfHyRef + imdl ] * m_HyCalculated[0] - derivativesOfEMFieldEyPol[ nBlkNotFixed * static_cast(m_rhsVectorIDOfHy) + imdl ] * HyCalRef[0] - derivativesOfEMFieldExPol[ nBlkNotFixed * rhsVectorIDOfHyRef + imdl ] * m_HyCalculated[1]; const std::complex workYX2 = m_HyCalculated[0]*HyCalRef[1] - m_HyCalculated[1]*HyCalRef[0]; sensitivityMatrix[ static_cast(nModel) * static_cast(m_dataIDOfTyx[freqIDThisPEInSta].realPart) + imdl ] = ( workYX1 * divDet - work1 * workYX2 * divDet2 ).real() / m_TyxSD[freqIDGlobalInSta].realPart; sensitivityMatrix[ static_cast(nModel) * static_cast(m_dataIDOfTyx[freqIDThisPEInSta].imagPart) + imdl ] = ( workYX1 * divDet - work1 * workYX2 * divDet2 ).imag() / m_TyxSD[freqIDGlobalInSta].imagPart; // dTyy/dm const std::complex workYY1 = derivativesOfEMFieldEyPol[ nBlkNotFixed * static_cast(m_rhsVectorIDOfHy) + imdl ] * HxCalRef[0] + derivativesOfEMFieldExPol[ nBlkNotFixed * rhsVectorIDOfHxRef + imdl ] * m_HyCalculated[1] - derivativesOfEMFieldExPol[ nBlkNotFixed * static_cast(m_rhsVectorIDOfHy) + imdl ] * HxCalRef[1] - derivativesOfEMFieldEyPol[ nBlkNotFixed * rhsVectorIDOfHxRef + imdl ] * m_HyCalculated[0]; const std::complex workYY2 = m_HyCalculated[1]*HxCalRef[0] - m_HyCalculated[0]*HxCalRef[1]; sensitivityMatrix[ static_cast(nModel) * static_cast(m_dataIDOfTyy[freqIDThisPEInSta].realPart) + imdl ] = ( workYY1 * divDet - work1 * workYY2 * divDet2 ).real() / m_TyySD[freqIDGlobalInSta].realPart; sensitivityMatrix[ static_cast(nModel) * static_cast(m_dataIDOfTyy[freqIDThisPEInSta].imagPart) + imdl ] = ( workYY1 * divDet - work1 * workYY2 * divDet2 ).imag() / m_TyySD[freqIDGlobalInSta].imagPart; } } // Calculate data vector of this PE void ObservedDataStationHTF::calculateResidualVectorOfDataThisPE( const double freq, const int offset, double* vector ) const{ const int freqIDThisPEInSta = getFreqIDsAmongThisPE( freq ); if( freqIDThisPEInSta < 0 ){// Specified frequency is not the ones calculated by this PE in this station return; } vector[ offset + m_dataIDOfTxx[freqIDThisPEInSta].realPart ] = m_TxxResidual[freqIDThisPEInSta].realPart; vector[ offset + m_dataIDOfTxx[freqIDThisPEInSta].imagPart ] = m_TxxResidual[freqIDThisPEInSta].imagPart; vector[ offset + m_dataIDOfTxy[freqIDThisPEInSta].realPart ] = m_TxyResidual[freqIDThisPEInSta].realPart; vector[ offset + m_dataIDOfTxy[freqIDThisPEInSta].imagPart ] = m_TxyResidual[freqIDThisPEInSta].imagPart; vector[ offset + m_dataIDOfTyx[freqIDThisPEInSta].realPart ] = m_TyxResidual[freqIDThisPEInSta].realPart; vector[ offset + m_dataIDOfTyx[freqIDThisPEInSta].imagPart ] = m_TyxResidual[freqIDThisPEInSta].imagPart; vector[ offset + m_dataIDOfTyy[freqIDThisPEInSta].realPart ] = m_TyyResidual[freqIDThisPEInSta].realPart; vector[ offset + m_dataIDOfTyy[freqIDThisPEInSta].imagPart ] = m_TyyResidual[freqIDThisPEInSta].imagPart; } // Calulate L2 norm of misfit double ObservedDataStationHTF::calculateErrorSumOfSquaresThisPE() const{ double misfit(0.0); for( int ifreq = 0; ifreq < m_numOfFreqCalculatedByThisStaAndPE; ++ifreq ){ misfit += pow( m_TxxResidual[ifreq].realPart , 2 ); misfit += pow( m_TxxResidual[ifreq].imagPart , 2 ); misfit += pow( m_TxyResidual[ifreq].realPart , 2 ); misfit += pow( m_TxyResidual[ifreq].imagPart , 2 ); misfit += pow( m_TyxResidual[ifreq].realPart , 2 ); misfit += pow( m_TyxResidual[ifreq].imagPart , 2 ); misfit += pow( m_TyyResidual[ifreq].realPart , 2 ); misfit += pow( m_TyyResidual[ifreq].imagPart , 2 ); } return misfit; }