65constexpr float BIG = 0.5f;
71static QString readWord(QTextStream &in)
74 if (in.atEnd())
return QString();
92 if (ch.isSpace())
break;
98FwdCoil* FwdCoilSet::fwd_add_coil_to_set(
int type,
int coil_class,
int acc,
int np,
float size,
float base,
const QString& desc)
101 qWarning(
"Number of integration points should be positive (type = %d acc = %d)",type,acc);
107 qWarning(
"Illegal accuracy (type = %d acc = %d)",type,acc);
114 qWarning(
"Illegal coil class (type = %d acc = %d class = %d)",type,acc,coil_class);
118 coils.push_back(std::make_unique<FwdCoil>(np));
119 FwdCoil* def =
coils.back().get();
152 qWarning() << ch.
ch_name <<
"is not a MEG channel. Cannot create a coil definition.";
159 for (
int k = 0; k < this->
ncoil(); k++) {
161 this->coils[k]->accuracy == acc) {
162 def = this->
coils[k].get();
166 qWarning(
"Desired coil definition not found (type = %d acc = %d)",ch.
chpos.
coil_type,acc);
172 auto res = std::make_unique<FwdCoil>(def->
np);
175 if (!def->
desc.isEmpty())
176 res->desc = def->
desc;
179 res->base = def->
base;
180 res->size = def->
size;
195 res->coord_frame = t.
to;
200 for (
int p = 0; p < res->np; p++) {
201 res->w[p] = def->
w[p];
202 res->rmag.row(p) = res->r0 + def->
rmag(p, 0)*res->ex + def->
rmag(p, 1)*res->ey + def->
rmag(p, 2)*res->ez;
203 res->cosmag.row(p) = def->
cosmag(p, 0)*res->ex + def->
cosmag(p, 1)*res->ey + def->
cosmag(p, 2)*res->ez;
215 auto res = std::make_unique<FwdCoilSet>();
217 for (
int k = 0; k < nch; k++) {
221 res->coils.push_back(std::move(next));
224 res->coord_frame = t.
to;
234 auto res = std::make_unique<FwdCoilSet>();
236 for (
int k = 0; k < nch; k++) {
240 res->coils.push_back(std::move(next));
243 res->coord_frame = t.
to;
252 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
253 qWarning() <<
"FwdCoilSet::read_coil_defs - Cannot open" << name;
260 QTextStream fileIn(&file);
261 while (!fileIn.atEnd()) {
262 QString line = fileIn.readLine();
263 int idx = line.indexOf(
'#');
266 content += line +
'\n';
271 QTextStream in(&content);
272 in.setLocale(QLocale::c());
274 auto res = std::make_unique<FwdCoilSet>();
275 while (!in.atEnd()) {
281 if (in.status() != QTextStream::Ok)
287 in >> type >> acc >> np >> size >> base;
288 if (in.status() != QTextStream::Ok) {
289 qWarning(
"FwdCoilSet::read_coil_defs - Error reading coil header");
293 QString desc = readWord(in);
294 if (desc.isEmpty()) {
295 qWarning(
"FwdCoilSet::read_coil_defs - Missing coil description");
299 FwdCoil* def = res->fwd_add_coil_to_set(type,coil_class,acc,np,size,base,desc);
303 for (
int p = 0; p < def->
np; p++) {
308 >> def->
rmag(p, 0) >> def->
rmag(p, 1) >> def->
rmag(p, 2)
310 if (in.status() != QTextStream::Ok) {
311 qWarning(
"FwdCoilSet::read_coil_defs - Error reading integration point %d", p);
315 if (def->
pos(p).norm() >
BIG) {
316 qWarning(
"Unreasonable integration point: %f %f %f mm (coil type = %d acc = %d)", 1000*def->
rmag(p, 0),1000*def->
rmag(p, 1),1000*def->
rmag(p, 2), def->
type,def->
accuracy);
319 float cosmagNorm = def->
dir(p).norm();
320 if (cosmagNorm <= 0) {
321 qWarning(
"Unreasonable normal: %f %f %f (coil type = %d acc = %d)", def->
cosmag(p, 0),def->
cosmag(p, 1),def->
cosmag(p, 2), def->
type,def->
accuracy);
324 def->
cosmag.row(p).normalize();
328 qInfo(
"%d coil definitions read",res->ncoil());
340 qWarning(
"Coordinate frame of the transformation does not match the coil set in fwd_dup_coil_set");
344 res = std::make_unique<FwdCoilSet>();
346 res->coord_frame = t.
to;
350 res->coils.reserve(this->
ncoil());
352 for (
int k = 0; k < this->
ncoil(); k++) {
353 auto coil = std::make_unique<FwdCoil>(*(this->
coils[k]));
363 for (
int p = 0; p < coil->np; p++) {
367 coil->coord_frame = t.
to;
369 res->coils.push_back(std::move(coil));
380 for (
int k = 0; k < this->
ncoil(); k++)
381 if (this->
coils[k]->type == type)
392 for (
int k = 0; k < this->
ncoil(); k++)
393 if (this->
coils[k]->type == type)
406 for (
int k = 0; k < this->
ncoil(); k++)
407 if (this->
coils[k]->type == type)
#define FIFFV_COORD_DEVICE
#define FIFFV_COORD_UNKNOWN
FiffChInfo class declaration.
FwdBemSolution class declaration.
FwdCoil class declaration.
FwdCoilSet class declaration.
FIFF file I/O and data structures (raw, epochs, evoked, covariance, forward).
Forward modelling (BEM, MEG/EEG lead fields).
constexpr int FWD_COIL_ACCURACY_NORMAL
constexpr int FWD_COIL_ACCURACY_POINT
constexpr int FWD_COIL_ACCURACY_ACCURATE
constexpr int FWD_COILC_PLANAR_GRAD
constexpr int FWD_COILC_AXIAL_GRAD2
constexpr int FWD_COILC_AXIAL_GRAD
constexpr int FWD_COILC_MAG
Coordinate transformation description.
Single MEG or EEG sensor coil with integration points, weights, and coordinate frame.
std::unique_ptr< FwdCoil > UPtr
Eigen::Map< const Eigen::Vector3f > dir(int j) const
Eigen::Map< const Eigen::Vector3f > pos(int j) const
Eigen::Matrix< float, Eigen::Dynamic, 3, Eigen::RowMajor > cosmag
static FwdCoil::UPtr create_eeg_el(const FIFFLIB::FiffChInfo &ch, const FIFFLIB::FiffCoordTrans &t=FIFFLIB::FiffCoordTrans())
Eigen::Matrix< float, Eigen::Dynamic, 3, Eigen::RowMajor > rmag
static FwdCoilSet::UPtr read_coil_defs(const QString &name)
bool is_axial_coil_type(int type) const
bool is_magnetometer_coil_type(int type) const
bool is_planar_coil_type(int type) const
FwdCoil::UPtr create_meg_coil(const FIFFLIB::FiffChInfo &ch, int acc, const FIFFLIB::FiffCoordTrans &t=FIFFLIB::FiffCoordTrans())
bool is_eeg_electrode_type(int type) const
FwdCoilSet::UPtr create_meg_coils(const QList< FIFFLIB::FiffChInfo > &chs, int nch, int acc, const FIFFLIB::FiffCoordTrans &t=FIFFLIB::FiffCoordTrans())
static FwdCoilSet::UPtr create_eeg_els(const QList< FIFFLIB::FiffChInfo > &chs, int nch, const FIFFLIB::FiffCoordTrans &t=FIFFLIB::FiffCoordTrans())
std::unique_ptr< FwdCoilSet > UPtr
std::vector< FwdCoil::UPtr > coils
FwdCoilSet::UPtr dup_coil_set(const FIFFLIB::FiffCoordTrans &t=FIFFLIB::FiffCoordTrans()) const
Eigen::MatrixX3f apply_trans(const Eigen::MatrixX3f &rr, bool do_move=true) const