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, bool pick_normal) const
81{
82 return InvRapMusic::calculateInverse(data, tmin, tstep, pick_normal);
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 throw std::logic_error("RAP MUSIC was not initialized");
94 }
95
96 //Test if data are correct
97 if (p_matMeasurement.rows() != m_iNumChannels) {
98 throw std::invalid_argument("Lead field channels do not match number of measurement channels");
99 }
100
101 //Inits
102 //Stop the time for benchmark purpose
103 clock_t start, end;
104 start = clock();
105
106 // //Map HPCMatrix to Eigen Matrix
107 // Eigen::Map<MatrixXT>
108 // t_MappedMatMeasurement( p_pMatMeasurement->data(),
109 // p_pMatMeasurement->rows(),
110 // p_pMatMeasurement->cols() );
111
112 //Calculate the signal subspace (t_pMatPhi_s)
113 MatrixXT* t_pMatPhi_s = nullptr; //(m_iNumChannels, m_iN < t_r ? m_iN : t_r);
114 int t_r = calcPhi_s(/*(MatrixXT)*/ p_matMeasurement, t_pMatPhi_s);
115
116 int t_iMaxSearch = m_iN < t_r ? m_iN : t_r; //The smallest of Rank and Iterations
117
118 if (t_r < m_iN) {
119 qDebug() << "Warning: Rank " << t_r << " of the measurement data is smaller than the " << m_iN;
120 qDebug() << " sources to find.";
121 qDebug() << " Searching now for " << t_iMaxSearch << " correlated sources.";
122 qDebug();
123 }
124
125 //Create Orthogonal Projector
126 //OrthProj
127 MatrixXT t_matOrthProj(m_iNumChannels, m_iNumChannels);
128 t_matOrthProj.setIdentity();
129
130 //A_k_1
131 MatrixXT t_matA_k_1(m_iNumChannels, t_iMaxSearch);
132 t_matA_k_1.setZero();
133
134 // if (m_pMatGrid != nullptr)
135 // {
136 // if(p_pRapDipoles != nullptr)
137 // p_pRapDipoles->initRapDipoles(m_pMatGrid);
138 // else
139 // p_pRapDipoles = new RapDipoles<T>(m_pMatGrid);
140 // }
141 // else
142 // {
143 // if(p_pRapDipoles != nullptr)
144 // delete p_pRapDipoles;
145
146 // p_pRapDipoles = new RapDipoles<T>();
147 // }
148 p_RapDipoles.clear();
149
150 qDebug() << "##### Calculation of PWL RAP MUSIC started ######\n\n";
151
152 MatrixXT t_matProj_Phi_s(t_matOrthProj.rows(), t_pMatPhi_s->cols());
153 //new Version: Calculate projection before
154 MatrixXT t_matProj_LeadField(m_ForwardSolution.sol->data.rows(), m_ForwardSolution.sol->data.cols());
155
156 for (int r = 0; r < t_iMaxSearch; ++r) {
157 t_matProj_Phi_s = t_matOrthProj * (*t_pMatPhi_s);
158
159 //new Version: Calculating Projection before
160 t_matProj_LeadField = t_matOrthProj * m_ForwardSolution.sol->data; //Subtract the found sources from the current found source
161
162 //###First Option###
163 //Step 1: lt. Mosher 1998 -> Maybe tmp_Proj_Phi_S is already orthogonal -> so no SVD needed -> U_B = tmp_Proj_Phi_S;
164 Eigen::JacobiSVD<MatrixXT> t_svdProj_Phi_S(t_matProj_Phi_s, Eigen::ComputeThinU);
165 MatrixXT t_matU_B;
166 useFullRank(t_svdProj_Phi_S.matrixU(), t_svdProj_Phi_S.singularValues().asDiagonal(), t_matU_B);
167
168 //Inits
170 t_vecRoh.setZero();
171
172 //subcorr benchmark
173 //Stop the time
174 clock_t start_subcorr, end_subcorr;
175 start_subcorr = clock();
176
177 // Assigned from the correlation search below; a search that finds no
178 // candidate must compare as "no correlation" rather than read garbage.
179 double t_val_roh_k = 0.0;
180
181 //Powell
182 int t_iCurrentRow = 2;
183
184 int t_iIdx1 = -1;
185 int t_iIdx2 = -1;
186
187 int t_iMaxIdx_old = -1;
188
189 int t_iMaxFound = 0;
190
191 Eigen::VectorXi t_pVecIdxElements(m_iNumGridPoints);
192
193 PowellIdxVec(t_iCurrentRow, m_iNumGridPoints, t_pVecIdxElements);
194
195 int t_iNumVecElements = m_iNumGridPoints;
196
197 while (t_iMaxFound == 0) {
198//Multithreading correlation calculation
199#ifdef _OPENMP
200#pragma omp parallel num_threads(m_iMaxNumThreads)
201#endif
202 {
203#ifdef _OPENMP
204#pragma omp for
205#endif
206 for (int i = 0; i < t_iNumVecElements; i++) {
207 int k = t_pVecIdxElements(i);
208 //new Version: calculate matrix multiplication before
209 //Create Lead Field combinations -> It would be better to use a pointer construction, to increase performance
210 MatrixX6T t_matProj_G(t_matProj_LeadField.rows(), 6);
211
212 int idx1 = m_ppPairIdxCombinations[k].x1;
213 int idx2 = m_ppPairIdxCombinations[k].x2;
214
215 InvRapMusic::getGainMatrixPair(t_matProj_LeadField, t_matProj_G, idx1, idx2);
216
217 t_vecRoh(k) = InvRapMusic::subcorr(t_matProj_G, t_matU_B); //t_vecRoh holds the correlations roh_k
218 }
219 }
220
221 // if(r==0)
222 // {
223 // std::fstream filestr;
224 // std::stringstream filename;
225 // filename << "Roh_gold.txt";
226 //
227 // filestr.open ( filename.str().c_str(), std::fstream::out);
228 // for(int i = 0; i < m_iNumLeadFieldCombinations; ++i)
229 // {
230 // filestr << t_vecRoh(i) << "\n";
231 // }
232 // filestr.close();
233 //
234 // //exit(0);
235 // }
236
237 //Find the maximum of correlation - can't put this in the for loop because it's running in different threads.
238
239 VectorXT::Index t_iMaxIdx;
240
241 t_val_roh_k = t_vecRoh.maxCoeff(&t_iMaxIdx); //p_vecCor = ^roh_k
242
243 if (static_cast<int>(t_iMaxIdx) == t_iMaxIdx_old) {
244 t_iMaxFound = 1;
245 break;
246 } else {
247 t_iMaxIdx_old = t_iMaxIdx;
248 //get positions in sparsed leadfield from index combinations;
249 t_iIdx1 = m_ppPairIdxCombinations[t_iMaxIdx].x1;
250 t_iIdx2 = m_ppPairIdxCombinations[t_iMaxIdx].x2;
251 }
252
253 //set new index
254 if (t_iIdx1 == t_iCurrentRow)
255 t_iCurrentRow = t_iIdx2;
256 else
257 t_iCurrentRow = t_iIdx1;
258
259 PowellIdxVec(t_iCurrentRow, m_iNumGridPoints, t_pVecIdxElements);
260 }
261
262 //subcorr benchmark
263 end_subcorr = clock();
264
265 float t_fSubcorrElapsedTime = (static_cast<float>(end_subcorr - start_subcorr) / static_cast<float>(CLOCKS_PER_SEC)) * 1000.0f;
266 qDebug() << "Time Elapsed: " << t_fSubcorrElapsedTime << " ms";
267
268 // (Idx+1) because of MATLAB positions -> starting with 1 not with 0
269 qDebug() << "Iteration: " << r + 1 << " of " << t_iMaxSearch
270 << "; Correlation: " << t_val_roh_k << "; Position (Idx+1): " << t_iIdx1 + 1 << " - " << t_iIdx2 + 1 << "\n\n";
271
272 //Calculations with the max correlated dipole pair G_k_1
273 MatrixX6T t_matG_k_1(m_ForwardSolution.sol->data.rows(), 6);
274 InvRapMusic::getGainMatrixPair(m_ForwardSolution.sol->data, t_matG_k_1, t_iIdx1, t_iIdx2);
275
276 MatrixX6T t_matProj_G_k_1(t_matOrthProj.rows(), t_matG_k_1.cols());
277 t_matProj_G_k_1 = t_matOrthProj * t_matG_k_1; //Subtract the found sources from the current found source
278 // MatrixX6T t_matProj_G_k_1(t_matProj_LeadField.rows(), 6);
279 // getLeadFieldPair(t_matProj_LeadField, t_matProj_G_k_1, t_iIdx1, t_iIdx2);
280
281 //Calculate source direction
282 //source direction (p_pMatPhi) for current source r (phi_k_1)
283 Vector6T t_vec_phi_k_1(6, 1);
284 InvRapMusic::subcorr(t_matProj_G_k_1, t_matU_B, t_vec_phi_k_1); //Correlate the current source to calculate the direction
285
286 //Set return values
287 InvRapMusic::insertSource(t_iIdx1, t_iIdx2, t_vec_phi_k_1, t_val_roh_k, p_RapDipoles);
288
289 //Stop Searching when Correlation is smaller then the Threshold
290 if (t_val_roh_k < m_dThreshold) {
291 qDebug() << "Searching stopped, last correlation " << t_val_roh_k;
292 qDebug() << " is smaller then the given threshold " << m_dThreshold;
293 break;
294 }
295
296 //Calculate A_k_1 = [a_theta_1..a_theta_k_1] matrix for subtraction of found source
297 InvRapMusic::calcA_k_1(t_matG_k_1, t_vec_phi_k_1, r, t_matA_k_1);
298
299 //Calculate new orthogonal Projector (Pi_k_1)
300 calcOrthProj(t_matA_k_1, t_matOrthProj);
301
302 //garbage collecting
303 //ToDo
304 }
305
306 qDebug() << "##### Calculation of PWL RAP MUSIC completed ######";
307
308 end = clock();
309
310 float t_fElapsedTime = (static_cast<float>(end - start) / static_cast<float>(CLOCKS_PER_SEC)) * 1000.0f;
311 qDebug() << "Total Time Elapsed: " << t_fElapsedTime << " ms";
312
313 //garbage collecting
314 delete t_pMatPhi_s;
315
316 return p_SourceEstimate;
317}
318
319//=============================================================================================================
320
321int InvPwlRapMusic::PowellOffset(int p_iRow, int p_iNumPoints)
322{
323 return p_iRow * p_iNumPoints - (((p_iRow - 1) * p_iRow) / 2); //triangular series 1 3 6 10 ... = (num_pairs*(num_pairs+1))/2
324}
325
326//=============================================================================================================
327
328void InvPwlRapMusic::PowellIdxVec(int p_iRow, int p_iNumPoints, Eigen::VectorXi& p_pVecElements)
329{
330 // if(p_pVecElements != nullptr)
331 // delete[] p_pVecElements;
332 //
333 // p_pVecElements = new int(p_iNumPoints);
334
335 if (p_pVecElements.size() != p_iNumPoints)
336 p_pVecElements.resize(p_iNumPoints);
337
338 //col combination index
339 for (int i = 0; i <= p_iRow; ++i) //=p_iNumPoints-1
340 p_pVecElements(i) = InvPwlRapMusic::PowellOffset(i + 1, p_iNumPoints) - (p_iNumPoints - p_iRow);
341
342 //row combination index
343 int off = InvPwlRapMusic::PowellOffset(p_iRow, p_iNumPoints);
344 int length = p_iNumPoints - p_iRow;
345 int k = 0;
346 for (int i = p_iRow; i < p_iRow + length; ++i) //=p_iNumPoints-1
347 {
348 p_pVecElements(i) = off + k;
349 k = k + 1;
350 }
351}
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:77
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:62
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.