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