v2.0.0
Loading...
Searching...
No Matches
inv_ecd_set.cpp
Go to the documentation of this file.
1//=============================================================================================================
17
18//=============================================================================================================
19// INCLUDES
20//=============================================================================================================
21
22#include "inv_ecd_set.h"
23#include <fiff/fiff_byte_swap.h>
24#include <fiff/fiff_types.h>
25
26
27//=============================================================================================================
28// QT INCLUDES
29//=============================================================================================================
30
31#include <QDebug>
32#include <QFile>
33#include <QTextStream>
34#include <QString>
35#include <QRegularExpression>
36#include <QDebug>
37
38//=============================================================================================================
39// EIGEN INCLUDES
40//=============================================================================================================
41
42//=============================================================================================================
43// USED NAMESPACES
44//=============================================================================================================
45
46using namespace INVLIB;
47using namespace FIFFLIB;
48
49//=============================================================================================================
50// DEFINES
51//=============================================================================================================
52
53constexpr int X = 0;
54constexpr int Y = 1;
55constexpr int Z = 2;
56
57namespace INVLIB
58{
59
63typedef struct
64{
65 int dipole; /* Which dipole in a multi-dipole set */
66 float begin, end; /* Fitting time range */
67 float r0[3]; /* Sphere model origin */
68 float rd[3]; /* Dipole location */
69 float Q[3]; /* InvDipole amplitude */
70 float goodness; /* Goodness-of-fit */
71 int errors_computed; /* Have we computed the errors */
72 float noise_level; /* Noise level used for error computations */
73 float single_errors[5]; /* Single parameter error limits */
74 float error_matrix[5][5]; /* This fully describes the conf. ellipsoid */
75 float conf_vol; /* The xyz confidence volume */
76 float khi2; /* The khi^2 value */
77 float prob; /* Probability to exceed khi^2 by chance */
78 float noise_est; /* Total noise estimate */
81
82} // Namespace
83
84//=============================================================================================================
85// DEFINE MEMBER METHODS
86//=============================================================================================================
87
91
92//=============================================================================================================
93
95: dataname(p_ECDSet.dataname)
96, m_qListDips(p_ECDSet.m_qListDips)
97{
98}
99
100//=============================================================================================================
101
105
106//=============================================================================================================
107
108void InvEcdSet::addEcd(const InvEcd& p_ecd)
109{
110 m_qListDips.append(p_ecd);
111}
112
113//=============================================================================================================
114
116{
117 InvEcdSet set;
118
119 QFile inputFile(fileName);
120 if (inputFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
121 QTextStream in(&inputFile);
122 while (!in.atEnd()) {
123 QString line = in.readLine();
124 QStringList list = line.split(QRegularExpression("\\s+"));
125
126 if (list[0].contains("#") || list.size() != 11) {
127 continue;
128 } else {
129 InvEcd one;
130 one.valid = true;
131 one.time = list[1].toFloat() / 1000.0f;
132 one.rd[X] = list[3].toFloat() / 1000.0f;
133 one.rd[Y] = list[4].toFloat() / 1000.0f;
134 one.rd[Z] = list[5].toFloat() / 1000.0f;
135 one.Q[X] = list[7].toFloat() / 1e9f;
136 one.Q[Y] = list[8].toFloat() / 1e9f;
137 one.Q[Z] = list[9].toFloat() / 1e9f;
138 one.good = list[10].toFloat() / 100.0f;
139 set << one;
140 }
141 }
142 inputFile.close();
143
144 qInfo("Read %d dipoles in dip format from %s\n", set.size(), fileName.toUtf8().data());
145 } else {
146 qCritical("Not able to read from: %s\n", fileName.toUtf8().data());
147 }
148
149 return set;
150}
151
152//=============================================================================================================
153
154bool InvEcdSet::save_dipoles_bdip(const QString& fileName)
155/*
156 * Save dipoles in the bdip format employed by xfit
157 */
158{
159 QFile out(fileName);
160 bdipEcdRec one_out;
161 InvEcd one;
162 int k, p;
163 int nsave;
164
165 if (fileName.isEmpty() || this->size() == 0)
166 return true;
167
168 if (!out.open(QIODevice::WriteOnly)) {
169 qInfo("%s", fileName.toUtf8().constData());
170 return false;
171 }
172
173 for (k = 0, nsave = 0; k < this->size(); k++) {
174 one = m_qListDips[k];
175 if (one.valid) {
176 one_out.dipole = FIFFLIB::swap_int(1);
177 one_out.begin = FIFFLIB::swap_float(one.time);
178 for (p = 0; p < 3; p++) {
179 one_out.r0[p] = FIFFLIB::swap_float(0.0);
180 one_out.rd[p] = FIFFLIB::swap_float(one.rd[p]);
181 one_out.Q[p] = FIFFLIB::swap_float(one.Q[p]);
182 }
183 one_out.goodness = FIFFLIB::swap_float(one.good);
185 one_out.khi2 = FIFFLIB::swap_float(one.khi2);
186 if (out.write(reinterpret_cast<const char*>(&one_out), sizeof(bdipEcdRec)) != sizeof(bdipEcdRec)) {
187 qCritical("Failed to write a dipole");
188 out.close();
189 QFile::remove(fileName);
190 return false;
191 }
192 nsave++;
193 }
194 }
195 if (!out.flush()) {
196 qInfo("%s", fileName.toUtf8().constData());
197 return false;
198 }
199 out.close();
200 qInfo("Save %d dipoles in bdip format to %s\n", nsave, fileName.toUtf8().data());
201 return true;
202}
203
204//=============================================================================================================
205
206bool InvEcdSet::save_dipoles_dip(const QString& fileName) const
207{
208 QFile out(fileName);
209 int k, nsave;
210 InvEcd one;
211
212 if (fileName.isEmpty() || this->size() == 0)
213 return true;
214 if (!out.open(QIODevice::WriteOnly | QIODevice::Text)) {
215 qInfo("%s", fileName.toUtf8().constData());
216 return false;
217 }
218 //
219 // The column layout is read back by other tools, so keep printf style
220 // formatting rather than rebuilding the widths with stream manipulators.
221 //
222 QTextStream stream(&out);
223 stream << "# CoordinateSystem \"Head\"\n";
224 stream << QString::asprintf("# %7s %7s %8s %8s %8s %8s %8s %8s %8s %6s\n",
225 "begin", "end", "X (mm)", "Y (mm)", "Z (mm)", "Q(nAm)", "Qx(nAm)", "Qy(nAm)", "Qz(nAm)", "g/%");
226 for (k = 0, nsave = 0; k < this->size(); k++) {
227 one = this->m_qListDips[k];
228 if (one.valid) {
229 stream << QString::asprintf(" %7.1f %7.1f %8.2f %8.2f %8.2f %8.3f %8.3f %8.3f %8.3f %6.1f\n",
230 1000 * one.time, 1000 * one.time,
231 1000 * one.rd[X], 1000 * one.rd[Y], 1000 * one.rd[Z],
232 1e9 * one.Q.norm(), 1e9 * one.Q[X], 1e9 * one.Q[Y], 1e9 * one.Q[Z], 100.0 * one.good);
233 nsave++;
234 }
235 }
236 stream << QString::asprintf("## Name \"%s dipoles\" Style \"Dipoles\"\n", "ALL");
237 stream.flush();
238 if (!out.flush()) {
239 qInfo("%s", fileName.toUtf8().constData());
240 return false;
241 }
242 out.close();
243 qInfo("Save %d dipoles in dip format to %s\n", nsave, fileName.toUtf8().data());
244 return true;
245}
246
247//=============================================================================================================
248
249const InvEcd& InvEcdSet::operator[](int idx) const
250{
251 if (idx >= m_qListDips.length()) {
252 qWarning("Warning: Required InvEcd doesn't exist! Returning InvEcd '0'.");
253 idx = 0;
254 }
255 return m_qListDips[idx];
256}
257
258//=============================================================================================================
259
261{
262 if (idx >= m_qListDips.length()) {
263 qWarning("Warning: Required InvEcd doesn't exist! Returning InvEcd '0'.");
264 idx = 0;
265 }
266 return m_qListDips[idx];
267}
268
269//=============================================================================================================
270
272{
273 this->m_qListDips.append(p_ecd);
274 return *this;
275}
Endianness swap helpers for the FIFF binary tag I/O layer (FIFF is always written big-endian on disk)...
Primitive scalar typedefs and forward-compatible aliases backing the FIFF type system.
constexpr int Y
constexpr int Z
constexpr int X
Ordered set of INVLIB::InvEcd records — the result of a sequential dipole-fit run.
FIFF file I/O, in-memory data structures and high-level readers/writers.
float swap_float(float source)
qint32 swap_int(qint32 source)
Inverse source estimation (MNE, dSPM, sLORETA, dipole fitting).
bdipEcdRec * bdipEcd
Single equivalent current dipole with position, orientation, amplitude, and goodness-of-fit.
Definition inv_ecd.h:58
Eigen::Vector3f Q
Definition inv_ecd.h:106
Eigen::Vector3f rd
Definition inv_ecd.h:105
Binary-format dipole record for file I/O, storing fitted dipole parameters and error estimates.
float error_matrix[5][5]
qint32 size() const
InvEcdSet & operator<<(const InvEcd &p_ecd)
void addEcd(const InvEcd &p_ecd)
bool save_dipoles_dip(const QString &fileName) const
bool save_dipoles_bdip(const QString &fileName)
const InvEcd & operator[](int idx) const
static InvEcdSet read_dipoles_dip(const QString &fileName)