v2.0.0
Loading...
Searching...
No Matches
inv_guess_data.cpp
Go to the documentation of this file.
1//=============================================================================================================
19
20//=============================================================================================================
21// INCLUDES
22//=============================================================================================================
23
24#include "inv_guess_data.h"
25#include "inv_dipole_fit_data.h"
26#include "inv_dipole_forward.h"
27#include <mne/mne_surface.h>
29
30#include <fiff/fiff_stream.h>
31#include <fiff/fiff_tag.h>
32
33#include <memory>
34#include <QFile>
35#include <QDebug>
36
37//=============================================================================================================
38// USED NAMESPACES
39//=============================================================================================================
40
41using namespace Eigen;
42using namespace FIFFLIB;
43using namespace MNELIB;
44using namespace FWDLIB;
45using namespace INVLIB;
46
47constexpr int FAIL = -1;
48constexpr int OK = 0;
49
50//=============================================================================================================
51// DEFINE MEMBER METHODS
52//=============================================================================================================
53
58
59//=============================================================================================================
60
61//InvGuessData::InvGuessData(const InvGuessData& p_GuessData)
62//{
63//}
64
65//=============================================================================================================
66
67InvGuessData::InvGuessData(const QString &guessname, const QString &guess_surfname, float mindist, float exclude, float grid, InvDipoleFitData *f)
68{
69// InvGuessData* res = new InvGuessData();
70 int k,p;
71 float guessrad = 0.080;
72 std::unique_ptr<MNESourceSpace> guesses;
73 dipoleFitFuncs orig;
74
75 if (!guessname.isEmpty()) {
76 /*
77 * Read the guesses and transform to the appropriate coordinate frame
78 */
79 std::vector<std::unique_ptr<MNESourceSpace>> sp;
80 if (MNESourceSpace::read_source_spaces(guessname,sp) == FAIL)
81 return;
82 if (static_cast<int>(sp.size()) != 1) {
83 qCritical("Incorrect number of source spaces in guess file");
84 return;
85 }
86 qInfo("Read guesses from %s\n",guessname.toUtf8().constData());
87 guesses = std::move(sp[0]);
88 }
89 else {
90 MNESurface* inner_skull = nullptr;
91 std::unique_ptr<MNESurface> inner_skull_owned;
92 Eigen::Vector3f r0 = f->r0;
93
94 Q_ASSERT(f->mri_head_t);
96 if (f->bem_model) {
97 qInfo("Using inner skull surface from the BEM (%s)...\n",f->bemname.toUtf8().constData());
98 if ((inner_skull = f->bem_model->fwd_bem_find_surface(FIFFV_BEM_SURF_ID_BRAIN)) == nullptr)
99 return;
100 }
101 else if (!guess_surfname.isEmpty()) {
102 qInfo("Reading inner skull surface from %s...\n",guess_surfname.toUtf8().data());
103 inner_skull_owned = MNESurface::read_bem_surface(guess_surfname,FIFFV_BEM_SURF_ID_BRAIN,true);
104 if (!inner_skull_owned)
105 return;
106 inner_skull = inner_skull_owned.get();
107 }
108 guesses.reset(reinterpret_cast<MNESourceSpace*>(FwdBemModel::make_guesses(inner_skull,guessrad,r0,grid,exclude,mindist).release()));
109 if (!guesses)
110 return;
111 }
112 {
113 std::vector<std::unique_ptr<MNESourceSpace>> guesses_vec;
114 guesses_vec.push_back(std::move(guesses));
116 return;
117 guesses = std::move(guesses_vec[0]);
118 }
119 qInfo("Guess locations are now in %s coordinates.\n",FiffCoordTrans::frame_name(f->coord_frame).toUtf8().constData());
120
121 this->nguess = guesses->nuse;
122 this->rr.resize(guesses->nuse, 3);
123 for (k = 0, p = 0; k < guesses->np; k++)
124 if (guesses->inuse[k]) {
125 this->rr.row(p) = guesses->rr.row(k);
126 p++;
127 }
128 guesses.reset();
129
130 qInfo("Go through all guess source locations...");
131 this->guess_fwd.resize(this->nguess);
132 /*
133 * Compute the guesses using the sphere model for speed
134 */
135 orig = f->funcs;
136 if (f->fit_mag_dipoles)
137 f->funcs = f->mag_dipole_funcs.get();
138 else
139 f->funcs = f->sphere_funcs.get();
140
141 for (k = 0; k < this->nguess; k++) {
142 this->guess_fwd[k].reset(InvDipoleFitData::dipole_forward_one(f,Eigen::Vector3f(this->rr.row(k).transpose()),nullptr));
143 if (!this->guess_fwd[k])
144 return;
145#ifdef DEBUG
146 sing = this->guess_fwd[k]->sing;
147 qInfo("%f %f %f\n",sing[0],sing[1],sing[2]);
148#endif
149 }
150 f->funcs = orig;
151
152 qInfo("[done %d sources]\n",p);
153
154 return;
155// return res;
156}
157
158//=============================================================================================================
159
160InvGuessData::InvGuessData(const QString &guessname, const QString &guess_surfname, float mindist, float exclude, float grid, InvDipoleFitData *f, char *guess_save_name)
161{
162 int k,p;
163 float guessrad = 0.080f;
164 std::unique_ptr<MNESourceSpace> guesses;
165
166 if (!guessname.isEmpty()) {
167 /*
168 * Read the guesses and transform to the appropriate coordinate frame
169 */
170 std::vector<std::unique_ptr<MNESourceSpace>> sp;
172 return;
173 if (static_cast<int>(sp.size()) != 1) {
174 qCritical("Incorrect number of source spaces in guess file");
175 return;
176 }
177 qInfo("Read guesses from %s\n",guessname.toUtf8().constData());
178 guesses = std::move(sp[0]);
179 }
180 else {
181 MNESurface* inner_skull = nullptr;
182 std::unique_ptr<MNESurface> inner_skull_owned;
183 Eigen::Vector3f r0 = f->r0;
184
185 Q_ASSERT(f->mri_head_t);
187 if (f->bem_model) {
188 qInfo("Using inner skull surface from the BEM (%s)...\n",f->bemname.toUtf8().constData());
189 if ((inner_skull = f->bem_model->fwd_bem_find_surface(FIFFV_BEM_SURF_ID_BRAIN)) == nullptr)
190 return;
191 }
192 else if (!guess_surfname.isEmpty()) {
193 qInfo("Reading inner skull surface from %s...\n",guess_surfname.toUtf8().data());
194 inner_skull_owned = MNESurface::read_bem_surface(guess_surfname,FIFFV_BEM_SURF_ID_BRAIN,true);
195 if (!inner_skull_owned)
196 return;
197 inner_skull = inner_skull_owned.get();
198 }
199 guesses.reset(reinterpret_cast<MNESourceSpace*>(FwdBemModel::make_guesses(inner_skull,guessrad,r0,grid,exclude,mindist).release()));
200 if (!guesses)
201 return;
202 }
203 /*
204 * Save the guesses for future use
205 */
206 if (guesses->nuse == 0) {
207 qCritical("No active guess locations remaining.");
208 return;
209 }
210 if (guess_save_name) {
211 qCritical("###################DEBUG writing source spaces not yet implemented.");
212 // if (mne_write_source_spaces(guess_save_name,&guesses,1,false) != OK)
213 // goto bad;
214 // qInfo("Wrote guess locations to %s\n",guess_save_name);
215 }
216 /*
217 * Transform the guess locations to the appropriate coordinate frame
218 */
219 {
220 std::vector<std::unique_ptr<MNESourceSpace>> guesses_vec;
221 guesses_vec.push_back(std::move(guesses));
223 return;
224 guesses = std::move(guesses_vec[0]);
225 }
226 qInfo("Guess locations are now in %s coordinates.\n",FiffCoordTrans::frame_name(f->coord_frame).toUtf8().constData());
227
228 this->nguess = guesses->nuse;
229 this->rr.resize(guesses->nuse, 3);
230 for (k = 0, p = 0; k < guesses->np; k++)
231 if (guesses->inuse[k]) {
232 this->rr.row(p) = guesses->rr.row(k);
233 p++;
234 }
235 guesses.reset();
236
237 this->guess_fwd.resize(this->nguess);
238 /*
239 * Compute the guesses using the sphere model for speed
240 */
241 if (!this->compute_guess_fields(f))
242 return;
243
244 return;
245}
246
247//=============================================================================================================
248
250
251//=============================================================================================================
252
254{
255 dipoleFitFuncs orig = nullptr;
256
257 if (!f) {
258 qCritical("Data missing in compute_guess_fields");
259 return false;
260 }
261 if (!f->noise) {
262 qCritical("Noise covariance missing in compute_guess_fields");
263 return false;
264 }
265 qInfo("Go through all guess source locations...");
266 orig = f->funcs;
267 if (f->fit_mag_dipoles)
268 f->funcs = f->mag_dipole_funcs.get();
269 else
270 f->funcs = f->sphere_funcs.get();
271 for (int k = 0; k < this->nguess; k++) {
272 this->guess_fwd[k].reset(InvDipoleFitData::dipole_forward_one(f,Eigen::Vector3f(this->rr.row(k).transpose()),this->guess_fwd[k].release()));
273 if (!this->guess_fwd[k]) {
274 if (orig)
275 f->funcs = orig;
276 return false;
277 }
278#ifdef DEBUG
279 sing = this->guess_fwd[k]->sing;
280 qInfo("%f %f %f\n",sing[0],sing[1],sing[2]);
281#endif
282 }
283 f->funcs = orig;
284 qInfo("[done %d sources]\n",this->nguess);
285
286 return true;
287}
constexpr int FAIL
constexpr int OK
Lightweight triangulated surface (vertices, triangles, normals) used by surface-based routines.
Single-hemisphere source space (cortical surface or volume grid) loaded from FIFF.
#define FIFF_FAIL
#define FIFFV_BEM_SURF_ID_BRAIN
Definition fiff_file.h:742
FIFF tag: the 16-byte tag header (kind, type, size, next) plus its decoded payload.
FIFF binary tag-stream layer: wraps a QIODevice to read and write FIFF tags, directories,...
Per-iteration forward-field cache (forward matrix, SVD, column normalisation) used by the dipole-fit ...
Initial-guess grid for the dipole-fit optimiser, with per-guess forward fields pre-computed.
Dipole-fit workspace bundling sensor geometry, forward-model function pointers, noise covariance and ...
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).
dipoleFitFuncsRec * dipoleFitFuncs
Pointer alias for dipoleFitFuncsRec, used throughout the dipole fitting module.
Forward modelling — BEM solver, spherical models, sensor/coil definitions and the lead-field assembly...
Definition compute_fwd.h:83
static QString frame_name(int frame)
Eigen::MatrixX3f apply_inverse_trans(const Eigen::MatrixX3f &rr, bool do_move=true) const
static std::unique_ptr< MNELIB::MNESurface > make_guesses(MNELIB::MNESurface *guess_surf, float guessrad, const Eigen::Vector3f &guess_r0, float grid, float exclude, float mindist)
Generate a set of dipole guess locations inside a boundary surface.
Dipole fit workspace holding sensor geometry, forward model, noise covariance, and projection data.
std::unique_ptr< FIFFLIB::FiffCoordTrans > mri_head_t
static InvDipoleForward * dipole_forward_one(InvDipoleFitData *d, const Eigen::Vector3f &rd, InvDipoleForward *old)
Compute the forward solution for a single dipole position.
std::unique_ptr< MNELIB::MNECovMatrix > noise
std::unique_ptr< dipoleFitFuncsRec > sphere_funcs
std::unique_ptr< FWDLIB::FwdBemModel > bem_model
std::unique_ptr< dipoleFitFuncsRec > mag_dipole_funcs
std::vector< InvDipoleForward::UPtr > guess_fwd
Eigen::Matrix< float, Eigen::Dynamic, 3, Eigen::RowMajor > rr
bool compute_guess_fields(InvDipoleFitData *f)
This defines a source space.
static int read_source_spaces(const QString &name, std::vector< std::unique_ptr< MNESourceSpace > > &spaces)
static int transform_source_spaces_to(int coord_frame, const FIFFLIB::FiffCoordTrans &t, std::vector< std::unique_ptr< MNESourceSpace > > &spaces)
Lightweight triangulated surface (vertices, triangles, normals).
Definition mne_surface.h:66
static std::unique_ptr< MNESurface > read_bem_surface(const QString &name, int which, bool add_geometry)