v2.0.0
Loading...
Searching...
No Matches
inv_pwl_rap_music.cpp
Go to the documentation of this file.
1//=============================================================================================================
35
36//=============================================================================================================
37// INCLUDES
38//=============================================================================================================
39
40#include "inv_pwl_rap_music.h"
41
42#include <QDebug>
43
44#ifdef _OPENMP
45#include <omp.h>
46#endif
47
48#include <stdexcept>
49//=============================================================================================================
50// USED NAMESPACES
51//=============================================================================================================
52
53using namespace INVLIB;
54using namespace MNELIB;
55using namespace FIFFLIB;
56
57//=============================================================================================================
58// DEFINE MEMBER METHODS
59//=============================================================================================================
60
65
66//=============================================================================================================
67
68InvPwlRapMusic::InvPwlRapMusic(MNEForwardSolution& p_pFwd, bool p_bSparsed, int p_iN, double p_dThr)
69: InvRapMusic(p_pFwd, p_bSparsed, p_iN, p_dThr)
70{
71 //Init
72 init(p_pFwd, p_bSparsed, p_iN, p_dThr);
73}
74
75//=============================================================================================================
76
80
81//=============================================================================================================
82
83const char* InvPwlRapMusic::getName() const
84{
85 return "Powell RAP MUSIC";
86}
87
88//=============================================================================================================
89
91{
92 return InvRapMusic::calculateInverse(p_fiffEvoked, pick_normal);
93}
94
95//=============================================================================================================
96
97InvSourceEstimate InvPwlRapMusic::calculateInverse(const MatrixXd &data, float tmin, float tstep) const
98{
99 return InvRapMusic::calculateInverse(data, tmin, tstep);
100}
101
102//=============================================================================================================
103
104InvSourceEstimate InvPwlRapMusic::calculateInverse(const MatrixXd& p_matMeasurement, QList< InvDipolePair<double> > &p_RapDipoles) const
105{
106 InvSourceEstimate p_SourceEstimate;
107
108 //if not initialized -> break
109 if(!m_bIsInit)
110 {
111 throw std::logic_error("RAP MUSIC was not initialized");
112 }
113
114 //Test if data are correct
115 if(p_matMeasurement.rows() != m_iNumChannels)
116 {
117 throw std::invalid_argument("Lead field channels do not match number of measurement channels");
118 }
119
120 //Inits
121 //Stop the time for benchmark purpose
122 clock_t start, end;
123 start = clock();
124
125// //Map HPCMatrix to Eigen Matrix
126// Eigen::Map<MatrixXT>
127// t_MappedMatMeasurement( p_pMatMeasurement->data(),
128// p_pMatMeasurement->rows(),
129// p_pMatMeasurement->cols() );
130
131 //Calculate the signal subspace (t_pMatPhi_s)
132 MatrixXT* t_pMatPhi_s = nullptr;//(m_iNumChannels, m_iN < t_r ? m_iN : t_r);
133 int t_r = calcPhi_s(/*(MatrixXT)*/p_matMeasurement, t_pMatPhi_s);
134
135 int t_iMaxSearch = m_iN < t_r ? m_iN : t_r; //The smallest of Rank and Iterations
136
137 if (t_r < m_iN)
138 {
139 qDebug() << "Warning: Rank " << t_r << " of the measurement data is smaller than the " << m_iN;
140 qDebug() << " sources to find.";
141 qDebug() << " Searching now for " << t_iMaxSearch << " correlated sources.";
142 qDebug();
143 }
144
145 //Create Orthogonal Projector
146 //OrthProj
148 t_matOrthProj.setIdentity();
149
150 //A_k_1
151 MatrixXT t_matA_k_1(m_iNumChannels, t_iMaxSearch);
152 t_matA_k_1.setZero();
153
154// if (m_pMatGrid != nullptr)
155// {
156// if(p_pRapDipoles != nullptr)
157// p_pRapDipoles->initRapDipoles(m_pMatGrid);
158// else
159// p_pRapDipoles = new RapDipoles<T>(m_pMatGrid);
160// }
161// else
162// {
163// if(p_pRapDipoles != nullptr)
164// delete p_pRapDipoles;
165
166// p_pRapDipoles = new RapDipoles<T>();
167// }
168 p_RapDipoles.clear();
169
170 qDebug() << "##### Calculation of PWL RAP MUSIC started ######\n\n";
171
172 MatrixXT t_matProj_Phi_s(t_matOrthProj.rows(), t_pMatPhi_s->cols());
173 //new Version: Calculate projection before
174 MatrixXT t_matProj_LeadField(m_ForwardSolution.sol->data.rows(), m_ForwardSolution.sol->data.cols());
175
176 for(int r = 0; r < t_iMaxSearch ; ++r)
177 {
178 t_matProj_Phi_s = t_matOrthProj*(*t_pMatPhi_s);
179
180 //new Version: Calculating Projection before
181 t_matProj_LeadField = t_matOrthProj * m_ForwardSolution.sol->data;//Subtract the found sources from the current found source
182
183 //###First Option###
184 //Step 1: lt. Mosher 1998 -> Maybe tmp_Proj_Phi_S is already orthogonal -> so no SVD needed -> U_B = tmp_Proj_Phi_S;
185 Eigen::JacobiSVD< MatrixXT > t_svdProj_Phi_S(t_matProj_Phi_s, Eigen::ComputeThinU);
186 MatrixXT t_matU_B;
187 useFullRank(t_svdProj_Phi_S.matrixU(), t_svdProj_Phi_S.singularValues().asDiagonal(), t_matU_B);
188
189 //Inits
191 t_vecRoh.setZero();
192
193 //subcorr benchmark
194 //Stop the time
195 clock_t start_subcorr, end_subcorr;
196 start_subcorr = clock();
197
198 double t_val_roh_k;
199
200 //Powell
201 int t_iCurrentRow = 2;
202
203 int t_iIdx1 = -1;
204 int t_iIdx2 = -1;
205
206 int t_iMaxIdx_old = -1;
207
208 int t_iMaxFound = 0;
209
210 Eigen::VectorXi t_pVecIdxElements(m_iNumGridPoints);
211
212 PowellIdxVec(t_iCurrentRow, m_iNumGridPoints, t_pVecIdxElements);
213
214 int t_iNumVecElements = m_iNumGridPoints;
215
216 while(t_iMaxFound == 0)
217 {
218
219 //Multithreading correlation calculation
220 #ifdef _OPENMP
221 #pragma omp parallel num_threads(m_iMaxNumThreads)
222 #endif
223 {
224 #ifdef _OPENMP
225 #pragma omp for
226 #endif
227 for(int i = 0; i < t_iNumVecElements; i++)
228 {
229 int k = t_pVecIdxElements(i);
230 //new Version: calculate matrix multiplication before
231 //Create Lead Field combinations -> It would be better to use a pointer construction, to increase performance
232 MatrixX6T t_matProj_G(t_matProj_LeadField.rows(),6);
233
234 int idx1 = m_ppPairIdxCombinations[k].x1;
235 int idx2 = m_ppPairIdxCombinations[k].x2;
236
237 InvRapMusic::getGainMatrixPair(t_matProj_LeadField, t_matProj_G, idx1, idx2);
238
239 t_vecRoh(k) = InvRapMusic::subcorr(t_matProj_G, t_matU_B);//t_vecRoh holds the correlations roh_k
240 }
241 }
242
243 // if(r==0)
244 // {
245 // std::fstream filestr;
246 // std::stringstream filename;
247 // filename << "Roh_gold.txt";
248 //
249 // filestr.open ( filename.str().c_str(), std::fstream::out);
250 // for(int i = 0; i < m_iNumLeadFieldCombinations; ++i)
251 // {
252 // filestr << t_vecRoh(i) << "\n";
253 // }
254 // filestr.close();
255 //
256 // //exit(0);
257 // }
258
259 //Find the maximum of correlation - can't put this in the for loop because it's running in different threads.
260
261 VectorXT::Index t_iMaxIdx;
262
263 t_val_roh_k = t_vecRoh.maxCoeff(&t_iMaxIdx);//p_vecCor = ^roh_k
264
265 if(static_cast<int>(t_iMaxIdx) == t_iMaxIdx_old)
266 {
267 t_iMaxFound = 1;
268 break;
269 }
270 else
271 {
272 t_iMaxIdx_old = t_iMaxIdx;
273 //get positions in sparsed leadfield from index combinations;
274 t_iIdx1 = m_ppPairIdxCombinations[t_iMaxIdx].x1;
275 t_iIdx2 = m_ppPairIdxCombinations[t_iMaxIdx].x2;
276 }
277
278 //set new index
279 if(t_iIdx1 == t_iCurrentRow)
280 t_iCurrentRow = t_iIdx2;
281 else
282 t_iCurrentRow = t_iIdx1;
283
284 PowellIdxVec(t_iCurrentRow, m_iNumGridPoints, t_pVecIdxElements);
285 }
286
287 //subcorr benchmark
288 end_subcorr = clock();
289
290 float t_fSubcorrElapsedTime = ( static_cast<float>(end_subcorr-start_subcorr) / static_cast<float>(CLOCKS_PER_SEC) ) * 1000.0f;
291 qDebug() << "Time Elapsed: " << t_fSubcorrElapsedTime << " ms";
292
293 // (Idx+1) because of MATLAB positions -> starting with 1 not with 0
294 qDebug() << "Iteration: " << r+1 << " of " << t_iMaxSearch
295 << "; Correlation: " << t_val_roh_k<< "; Position (Idx+1): " << t_iIdx1+1 << " - " << t_iIdx2+1 <<"\n\n";
296
297 //Calculations with the max correlated dipole pair G_k_1
298 MatrixX6T t_matG_k_1(m_ForwardSolution.sol->data.rows(),6);
299 InvRapMusic::getGainMatrixPair(m_ForwardSolution.sol->data, t_matG_k_1, t_iIdx1, t_iIdx2);
300
301 MatrixX6T t_matProj_G_k_1(t_matOrthProj.rows(), t_matG_k_1.cols());
302 t_matProj_G_k_1 = t_matOrthProj * t_matG_k_1;//Subtract the found sources from the current found source
303// MatrixX6T t_matProj_G_k_1(t_matProj_LeadField.rows(), 6);
304// getLeadFieldPair(t_matProj_LeadField, t_matProj_G_k_1, t_iIdx1, t_iIdx2);
305
306 //Calculate source direction
307 //source direction (p_pMatPhi) for current source r (phi_k_1)
308 Vector6T t_vec_phi_k_1(6, 1);
309 InvRapMusic::subcorr(t_matProj_G_k_1, t_matU_B, t_vec_phi_k_1);//Correlate the current source to calculate the direction
310
311 //Set return values
312 InvRapMusic::insertSource(t_iIdx1, t_iIdx2, t_vec_phi_k_1, t_val_roh_k, p_RapDipoles);
313
314 //Stop Searching when Correlation is smaller then the Threshold
315 if (t_val_roh_k < m_dThreshold)
316 {
317 qDebug() << "Searching stopped, last correlation " << t_val_roh_k;
318 qDebug() << " is smaller then the given threshold " << m_dThreshold;
319 break;
320 }
321
322 //Calculate A_k_1 = [a_theta_1..a_theta_k_1] matrix for subtraction of found source
323 InvRapMusic::calcA_k_1(t_matG_k_1, t_vec_phi_k_1, r, t_matA_k_1);
324
325 //Calculate new orthogonal Projector (Pi_k_1)
326 calcOrthProj(t_matA_k_1, t_matOrthProj);
327
328 //garbage collecting
329 //ToDo
330 }
331
332 qDebug() << "##### Calculation of PWL RAP MUSIC completed ######";
333
334 end = clock();
335
336 float t_fElapsedTime = ( static_cast<float>(end-start) / static_cast<float>(CLOCKS_PER_SEC) ) * 1000.0f;
337 qDebug() << "Total Time Elapsed: " << t_fElapsedTime << " ms";
338
339 //garbage collecting
340 delete t_pMatPhi_s;
341
342 return p_SourceEstimate;
343}
344
345//=============================================================================================================
346
347int InvPwlRapMusic::PowellOffset(int p_iRow, int p_iNumPoints)
348{
349
350 return p_iRow*p_iNumPoints - (( (p_iRow-1)*p_iRow) / 2); //triangular series 1 3 6 10 ... = (num_pairs*(num_pairs+1))/2
351}
352
353//=============================================================================================================
354
355void InvPwlRapMusic::PowellIdxVec(int p_iRow, int p_iNumPoints, Eigen::VectorXi& p_pVecElements)
356{
357
358 // if(p_pVecElements != nullptr)
359 // delete[] p_pVecElements;
360 //
361 // p_pVecElements = new int(p_iNumPoints);
362
363 if (p_pVecElements.size() != p_iNumPoints)
364 p_pVecElements.resize(p_iNumPoints);
365
366 //col combination index
367 for(int i = 0; i <= p_iRow; ++i)//=p_iNumPoints-1
368 p_pVecElements(i) = InvPwlRapMusic::PowellOffset(i+1,p_iNumPoints)-(p_iNumPoints-p_iRow);
369
370 //row combination index
371 int off = InvPwlRapMusic::PowellOffset(p_iRow,p_iNumPoints);
372 int length = p_iNumPoints - p_iRow;
373 int k=0;
374 for(int i = p_iRow; i < p_iRow+length; ++i)//=p_iNumPoints-1
375 {
376 p_pVecElements(i) = off+k;
377 k = k + 1;
378 }
379}
InvPwlRapMusic algorithm class declaration.
Core MNE data structures (source spaces, source estimates, hemispheres).
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
Inverse source estimation (MNE, dSPM, sLORETA, dipole fitting).
Pair of correlated dipole indices and orientations found by the RAP MUSIC scanning step.
Definition inv_dipole.h:59
static int PowellOffset(int p_iRow, int p_iNumPoints)
virtual InvSourceEstimate calculateInverse(const FIFFLIB::FiffEvoked &p_fiffEvoked, bool pick_normal=false)
static void PowellIdxVec(int p_iRow, int p_iNumPoints, Eigen::VectorXi &p_pVecElements)
virtual const char * getName() const
Eigen::Matrix< double, 6, 1 > Vector6T
static void calcA_k_1(const MatrixX6T &p_matG_k_1, const Vector6T &p_matPhi_k_1, const int p_iIdxk_1, MatrixXT &p_matA_k_1)
virtual InvSourceEstimate calculateInverse(const FIFFLIB::FiffEvoked &p_fiffEvoked, bool pick_normal=false)
static void insertSource(int p_iDipoleIdx1, int p_iDipoleIdx2, const Vector6T &p_vec_phi_k_1, double p_valCor, QList< InvDipolePair< double > > &p_RapDipoles)
bool init(MNELIB::MNEForwardSolution &p_pFwd, bool p_bSparsed=false, int p_iN=2, double p_dThr=0.5)
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixXT
Eigen::Matrix< double, Eigen::Dynamic, 1 > VectorXT
void calcOrthProj(const MatrixXT &p_matA_k_1, MatrixXT &p_matOrthProj) const
int calcPhi_s(const MatrixXT &p_matMeasurement, MatrixXT *&p_pMatPhi_s) const
static int useFullRank(const MatrixXT &p_Mat, const MatrixXT &p_matSigma_src, MatrixXT &p_matFull_Rank, int type=NOT_TRANSPOSED)
Eigen::Matrix< double, Eigen::Dynamic, 6 > MatrixX6T
MNELIB::MNEForwardSolution m_ForwardSolution
std::vector< Pair > m_ppPairIdxCombinations
static void getGainMatrixPair(const MatrixXT &p_matGainMarix, MatrixX6T &p_matGainMarix_Pair, int p_iIdx1, int p_iIdx2)
static double subcorr(MatrixX6T &p_matProj_G, const MatrixXT &p_pMatU_B)