48bool parseFloat(
const char* arg,
float& value)
51 const float parsed = QString::fromUtf8(arg).toFloat(&bOk);
68bool parseInt(
const char* arg,
int& value)
71 const int parsed = QString::fromUtf8(arg).toInt(&bOk);
88bool parseTriplet(
const char* arg, Eigen::Vector3f& values)
90 const QStringList parts = QString::fromUtf8(arg).split(
':');
91 if (parts.size() != 3) {
95 Eigen::Vector3f parsed;
96 for (
int i = 0; i < 3; ++i) {
98 parsed[i] = parts.at(i).toFloat(&bOk);
126 if (!check_args(argc, argv))
140void InvDipoleFitSettings::initMembers()
143 r0 << 0.0f, 0.0f, 0.04f;
202 qCritical(
"Data file name missing. Please specify one using the --meas option.");
206 qCritical(
"Output file name missing. Please use the --dip or --bdip options to do this.");
211 qCritical(
"Please specify the MRI/head coordinate transformation with the --mri option");
216 qCritical(
"Specify one or both of the --eeg and --meg options");
223 qInfo(
"BEM : %s",
bemname.toUtf8().data());
225 qInfo(
"Sphere model : origin at (% 7.2f % 7.2f % 7.2f) mm",
226 1000 *
r0[0], 1000 *
r0[1], 1000 *
r0[2]);
228 qInfo(
"Using %s MEG coil definitions.",
accurate ?
"accurate" :
"standard");
230 qInfo(
"MRI transform : %s",
mriname.toUtf8().data());
232 qInfo(
"Guesses : %s",
guessname.toUtf8().data());
235 qInfo(
"Guess space bounded by %s",
guess_surfname.toUtf8().data());
237 qInfo(
"Spherical guess space, rad = %.1f mm", 1000 *
guess_rad);
238 qInfo(
"Guess grid : %6.1f mm", 1000 *
guess_grid);
244 qInfo(
"Data : %s",
measname.toUtf8().data());
246 qInfo(
"SSP sources :");
247 for (
int k = 0; k <
projnames.size(); k++)
248 qInfo(
"\t%s",
projnames[k].toUtf8().data());
251 qInfo(
"Bad channels : %s",
badname.toUtf8().data());
253 qInfo(
"Baseline : %10.2f ... %10.2f ms", 1000 *
bmin, 1000 *
bmax);
255 qInfo(
"Noise covariance : %s",
noisename.toUtf8().data());
258 qInfo(
"\tNoise-covariance regularization (mag) : %-5.2f",
mag_reg);
260 qInfo(
"\tNoise-covariance regularization (grad) : %-5.2f",
grad_reg);
263 qInfo(
"\tNoise-covariance regularization (EEG) : %-5.2f",
eeg_reg);
266 qInfo(
"Fit data with magnetic dipoles");
268 qInfo(
"dip output : %s",
dipname.toUtf8().data());
270 qInfo(
"bdip output : %s",
bdipname.toUtf8().data());
275void InvDipoleFitSettings::usage(
const char* name)
277 qInfo(
"usage: %s [options]", name);
278 qInfo(
"This is a program for sequential single dipole fitting.");
279 qInfo(
"\nInput data:\n");
280 qInfo(
"\t--meas name specify an evoked-response data file");
281 qInfo(
"\t--set no evoked data set number to use (default: 1)");
282 qInfo(
"\t--bad name take bad channel list from here");
284 qInfo(
"\nModality selection:\n");
285 qInfo(
"\t--meg employ MEG data in fitting");
286 qInfo(
"\t--eeg employ EEG data in fitting");
288 qInfo(
"\nTime scale selection:\n");
289 qInfo(
"\t--tmin time/ms specify the starting analysis time");
290 qInfo(
"\t--tmax time/ms specify the ending analysis time");
291 qInfo(
"\t--tstep time/ms specify the time step between frames (default 1/(sampling frequency))");
292 qInfo(
"\t--integ time/ms specify the time integration for each frame (default 0)");
294 qInfo(
"\nPreprocessing:\n");
295 qInfo(
"\t--bmin time/ms specify the baseline starting time (evoked data only)");
296 qInfo(
"\t--bmax time/ms specify the baseline ending time (evoked data only)");
297 qInfo(
"\t--proj name Load the linear projection from here");
298 qInfo(
"\t Multiple projections can be specified.");
299 qInfo(
"\t The data file will be automatically included, unless --noproj is present.");
300 qInfo(
"\t--noproj Do not load the projection from the data file, just those given with the --proj option.");
301 qInfo(
"\n\tFiltering (raw data only):\n");
302 qInfo(
"\t--filtersize size desired filter length (default = %d)",
filter.
size);
303 qInfo(
"\t--highpass val/Hz highpass corner (default = %6.1f Hz)",
filter.
highpass);
304 qInfo(
"\t--lowpass val/Hz lowpass corner (default = %6.1f Hz)",
filter.
lowpass);
305 qInfo(
"\t--lowpassw val/Hz lowpass transition width (default = %6.1f Hz)",
filter.
lowpass_width);
306 qInfo(
"\t--filteroff do not filter the data");
308 qInfo(
"\nNoise specification:\n");
309 qInfo(
"\t--noise name take the noise-covariance matrix from here");
310 qInfo(
"\t--gradnoise val specify a gradiometer noise value in fT/cm");
311 qInfo(
"\t--magnoise val specify a magnetometer noise value in fT");
312 qInfo(
"\t--eegnoise val specify an EEG value in uV");
313 qInfo(
"\t NOTE: The above will be used only if --noise is missing");
314 qInfo(
"\t--diagnoise omit off-diagonal terms from the noise-covariance matrix");
315 qInfo(
"\t--reg amount Apply regularization to the noise-covariance matrix (same fraction for all channels).");
316 qInfo(
"\t--gradreg amount Apply regularization to the MEG noise-covariance matrix (planar gradiometers, default = %6.2f).",
grad_reg);
317 qInfo(
"\t--magreg amount Apply regularization to the MEG noise-covariance matrix (axial gradiometers and magnetometers, default = %6.2f).",
mag_reg);
318 qInfo(
"\t--eegreg amount Apply regularization to the EEG noise-covariance matrix (default = %6.2f).",
eeg_reg);
320 qInfo(
"\nForward model:\n");
321 qInfo(
"\t--mri name take head/MRI coordinate transform from here (Neuromag MRI description file)");
322 qInfo(
"\t--bem name BEM model name");
323 qInfo(
"\t--origin x:y:z/mm use a sphere model with this origin (head coordinates/mm)");
324 qInfo(
"\t--eegscalp scale the electrode locations to the surface of the scalp when using a sphere model");
325 qInfo(
"\t--eegmodels name read EEG sphere model specifications from here.");
326 qInfo(
"\t--eegmodel name name of the EEG sphere model to use (default : Default)");
327 qInfo(
"\t--eegrad val radius of the scalp surface to use in EEG sphere model (default : %7.1f mm)", 1000 *
eeg_sphere_rad);
328 qInfo(
"\t--accurate use accurate coil definitions in MEG forward computation");
330 qInfo(
"\nFitting parameters:\n");
331 qInfo(
"\t--guess name The source space of initial guesses.");
332 qInfo(
"\t If not present, the values below are used to generate the guess grid.");
333 qInfo(
"\t--guesssurf name Read the inner skull surface from this fif file to generate the guesses.");
334 qInfo(
"\t--guessrad value Radius of a spherical guess volume if neither of the above is present (default : %.1f mm)", 1000 *
guess_rad);
335 qInfo(
"\t--exclude dist/mm Exclude points which are closer than this distance from the CM of the inner skull surface (default = %6.1f mm).", 1000 *
guess_exclude);
336 qInfo(
"\t--mindist dist/mm Exclude points which are closer than this distance from the inner skull surface (default = %6.1f mm).", 1000 *
guess_mindist);
337 qInfo(
"\t--grid dist/mm Source space grid size (default = %6.1f mm).", 1000 *
guess_grid);
338 qInfo(
"\t--magdip Fit magnetic dipoles instead of current dipoles.");
339 qInfo(
"\nOutput:\n");
340 qInfo(
"\t--dip name xfit dip format output file name");
341 qInfo(
"\t--bdip name xfit bdip format output file name");
342 qInfo(
"\nGeneral:\n");
343 qInfo(
"\t--gui Enables the gui.");
344 qInfo(
"\t--help print this info.");
345 qInfo(
"\t--version print version info.");
350bool InvDipoleFitSettings::check_unrecognized_args(
int argc,
char** argv)
354 for (
int k = 1; k < argc; k++)
355 args += QString(argv[k]) +
" ";
356 qCritical(
"Unrecognized arguments : %s", args.trimmed().toUtf8().data());
364bool InvDipoleFitSettings::check_args(
int* argc,
char** argv)
368 int ival, filter_size;
370 for (
int k = 0; k < *argc; k++) {
372 if (strcmp(argv[k],
"--gui") == 0) {
375 }
else if (strcmp(argv[k],
"--version") == 0) {
376 qInfo(
"%s compiled at %s %s",
377 argv[0], __DATE__, __TIME__);
379 }
else if (strcmp(argv[k],
"--help") == 0) {
382 }
else if (strcmp(argv[k],
"--guess") == 0) {
384 if (k == *argc - 1) {
385 qCritical(
"--guess: argument required.");
389 }
else if (strcmp(argv[k],
"--gsurf") == 0) {
391 if (k == *argc - 1) {
392 qCritical(
"--gsurf: argument required.");
396 }
else if (strcmp(argv[k],
"--guesssurf") == 0) {
398 if (k == *argc - 1) {
399 qCritical(
"--guesssurf: argument required.");
403 }
else if (strcmp(argv[k],
"--guessrad") == 0) {
405 if (k == *argc - 1) {
406 qCritical(
"--guessrad: argument required.");
409 if (!parseFloat(argv[k + 1], fval)) {
410 qCritical(
"Could not interpret the radius.");
414 qCritical(
"Radius should be positive");
418 }
else if (strcmp(argv[k],
"--mindist") == 0) {
420 if (k == *argc - 1) {
421 qCritical(
"--mindist: argument required.");
424 if (!parseFloat(argv[k + 1], fval)) {
425 qCritical(
"Could not interpret the distance.");
431 }
else if (strcmp(argv[k],
"--exclude") == 0) {
433 if (k == *argc - 1) {
434 qCritical(
"--exclude: argument required.");
437 if (!parseFloat(argv[k + 1], fval)) {
438 qCritical(
"Could not interpret the distance.");
444 }
else if (strcmp(argv[k],
"--grid") == 0) {
446 if (k == *argc - 1) {
447 qCritical(
"--grid: argument required.");
450 if (!parseFloat(argv[k + 1], fval)) {
451 qCritical(
"Could not interpret the distance.");
455 qCritical(
"Grid spacing should be positive");
460 }
else if (strcmp(argv[k],
"--mri") == 0) {
462 if (k == *argc - 1) {
463 qCritical(
"--mri: argument required.");
466 mriname = QString(argv[k + 1]);
467 }
else if (strcmp(argv[k],
"--bem") == 0) {
469 if (k == *argc - 1) {
470 qCritical(
"--bem: argument required.");
473 bemname = QString(argv[k + 1]);
474 }
else if (strcmp(argv[k],
"--accurate") == 0) {
477 }
else if (strcmp(argv[k],
"--meg") == 0) {
480 }
else if (strcmp(argv[k],
"--eeg") == 0) {
483 }
else if (strcmp(argv[k],
"--origin") == 0) {
485 if (k == *argc - 1) {
486 qCritical(
"--origin: argument required.");
489 if (!parseTriplet(argv[k + 1],
r0)) {
490 qCritical(
"Could not interpret the origin.");
493 r0[0] =
r0[0] / 1000.0f;
494 r0[1] =
r0[1] / 1000.0f;
495 r0[2] =
r0[2] / 1000.0f;
496 }
else if (strcmp(argv[k],
"--eegrad") == 0) {
498 if (k == *argc - 1) {
499 qCritical(
"--eegrad: argument required.");
503 qCritical() <<
"Incomprehensible radius:" << argv[k + 1];
507 qCritical(
"Radius must be positive");
511 }
else if (strcmp(argv[k],
"--eegmodels") == 0) {
513 if (k == *argc - 1) {
514 qCritical(
"--eegmodels: argument required.");
518 }
else if (strcmp(argv[k],
"--eegmodel") == 0) {
520 if (k == *argc - 1) {
521 qCritical(
"--eegmodel: argument required.");
525 }
else if (strcmp(argv[k],
"--eegscalp") == 0) {
528 }
else if (strcmp(argv[k],
"--meas") == 0) {
530 if (k == *argc - 1) {
531 qCritical(
"--meas: argument required.");
536 }
else if (strcmp(argv[k],
"--raw") == 0) {
538 if (k == *argc - 1) {
539 qCritical(
"--raw: argument required.");
544 }
else if (strcmp(argv[k],
"--proj") == 0) {
546 if (k == *argc - 1) {
547 qCritical(
"--proj: argument required.");
551 }
else if (strcmp(argv[k],
"--noproj") == 0) {
554 }
else if (strcmp(argv[k],
"--bad") == 0) {
556 if (k == *argc - 1) {
557 qCritical(
"--bad: argument required.");
560 badname = QString(argv[k + 1]);
561 }
else if (strcmp(argv[k],
"--noise") == 0) {
563 if (k == *argc - 1) {
564 qCritical(
"--noise: argument required.");
568 }
else if (strcmp(argv[k],
"--gradnoise") == 0) {
570 if (k == *argc - 1) {
571 qCritical(
"--gradnoise: argument required.");
574 if (!parseFloat(argv[k + 1], fval)) {
575 qCritical() <<
"Incomprehensible value:" << argv[k + 1];
579 qCritical(
"Value should be positive");
583 }
else if (strcmp(argv[k],
"--magnoise") == 0) {
585 if (k == *argc - 1) {
586 qCritical(
"--magnoise: argument required.");
589 if (!parseFloat(argv[k + 1], fval)) {
590 qCritical() <<
"Incomprehensible value:" << argv[k + 1];
594 qCritical(
"Value should be positive");
598 }
else if (strcmp(argv[k],
"--eegnoise") == 0) {
600 if (k == *argc - 1) {
601 qCritical(
"--eegnoise: argument required.");
604 if (!parseFloat(argv[k + 1], fval)) {
605 qCritical() <<
"Incomprehensible value:" << argv[k + 1];
609 qCritical(
"Value should be positive");
613 }
else if (strcmp(argv[k],
"--diagnoise") == 0) {
616 }
else if (strcmp(argv[k],
"--eegreg") == 0) {
618 if (k == *argc - 1) {
619 qCritical(
"--eegreg: argument required.");
622 if (!parseFloat(argv[k + 1], fval)) {
623 qCritical() <<
"Incomprehensible value:" << argv[k + 1];
626 if (fval < 0 || fval > 1) {
627 qCritical(
"Regularization value should be positive and smaller than one.");
631 }
else if (strcmp(argv[k],
"--magreg") == 0) {
633 if (k == *argc - 1) {
634 qCritical(
"--magreg: argument required.");
637 if (!parseFloat(argv[k + 1], fval)) {
638 qCritical() <<
"Incomprehensible value:" << argv[k + 1];
641 if (fval < 0 || fval > 1) {
642 qCritical(
"Regularization value should be positive and smaller than one.");
646 }
else if (strcmp(argv[k],
"--gradreg") == 0) {
648 if (k == *argc - 1) {
649 qCritical(
"--gradreg: argument required.");
652 if (!parseFloat(argv[k + 1], fval)) {
653 qCritical() <<
"Incomprehensible value:" << argv[k + 1];
656 if (fval < 0 || fval > 1) {
657 qCritical(
"Regularization value should be positive and smaller than one.");
661 }
else if (strcmp(argv[k],
"--reg") == 0) {
663 if (k == *argc - 1) {
664 qCritical(
"--reg: argument required.");
667 if (!parseFloat(argv[k + 1], fval)) {
668 qCritical() <<
"Incomprehensible value:" << argv[k + 1];
671 if (fval < 0 || fval > 1) {
672 qCritical(
"Regularization value should be positive and smaller than one.");
678 }
else if (strcmp(argv[k],
"--tstep") == 0) {
680 if (k == *argc - 1) {
681 qCritical(
"--tstep: argument required.");
684 if (!parseFloat(argv[k + 1], fval)) {
685 qCritical() <<
"Incomprehensible tstep:" << argv[k + 1];
689 qCritical(
"Time step should be positive");
692 tstep = fval / 1000.0;
693 }
else if (strcmp(argv[k],
"--integ") == 0) {
695 if (k == *argc - 1) {
696 qCritical(
"--integ: argument required.");
699 if (!parseFloat(argv[k + 1], fval)) {
700 qCritical() <<
"Incomprehensible integration time:" << argv[k + 1];
704 qCritical(
"Integration time should be positive.");
707 integ = fval / 1000.0f;
708 }
else if (strcmp(argv[k],
"--tmin") == 0) {
710 if (k == *argc - 1) {
711 qCritical(
"--tmin: argument required.");
714 if (!parseFloat(argv[k + 1], fval)) {
715 qCritical() <<
"Incomprehensible tmin:" << argv[k + 1];
718 tmin = fval / 1000.0f;
719 }
else if (strcmp(argv[k],
"--tmax") == 0) {
721 if (k == *argc - 1) {
722 qCritical(
"--tmax: argument required.");
725 if (!parseFloat(argv[k + 1], fval)) {
726 qCritical() <<
"Incomprehensible tmax:" << argv[k + 1];
729 tmax = fval / 1000.0;
730 }
else if (strcmp(argv[k],
"--bmin") == 0) {
732 if (k == *argc - 1) {
733 qCritical(
"--bmin: argument required.");
736 if (!parseFloat(argv[k + 1], fval)) {
737 qCritical() <<
"Incomprehensible bmin:" << argv[k + 1];
740 bmin = fval / 1000.0f;
741 }
else if (strcmp(argv[k],
"--bmax") == 0) {
743 if (k == *argc - 1) {
744 qCritical(
"--bmax: argument required.");
747 if (!parseFloat(argv[k + 1], fval)) {
748 qCritical() <<
"Incomprehensible bmax:" << argv[k + 1];
751 bmax = fval / 1000.0f;
752 }
else if (strcmp(argv[k],
"--set") == 0) {
754 if (k == *argc - 1) {
755 qCritical(
"--set: argument required.");
758 if (!parseInt(argv[k + 1],
setno)) {
759 qCritical() <<
"Incomprehensible data set number:" << argv[k + 1];
763 qCritical(
"Data set number must be > 0");
766 }
else if (strcmp(argv[k],
"--filteroff") == 0) {
769 }
else if (strcmp(argv[k],
"--lowpass") == 0) {
771 if (k == *argc - 1) {
772 qCritical(
"--lowpass: argument required.");
775 if (!parseFloat(argv[k + 1], fval)) {
776 qCritical() <<
"Illegal number:" << argv[k + 1];
780 qCritical(
"Lowpass corner must be positive");
784 }
else if (strcmp(argv[k],
"--lowpassw") == 0) {
786 if (k == *argc - 1) {
787 qCritical(
"--lowpassw: argument required.");
790 if (!parseFloat(argv[k + 1], fval)) {
791 qCritical() <<
"Illegal number:" << argv[k + 1];
795 qCritical(
"Lowpass width must be positive");
798 filter.lowpass_width = fval;
799 }
else if (strcmp(argv[k],
"--highpass") == 0) {
801 if (k == *argc - 1) {
802 qCritical(
"--highpass: argument required.");
805 if (!parseFloat(argv[k + 1], fval)) {
806 qCritical() <<
"Illegal number:" << argv[k + 1];
810 qCritical(
"Highpass corner must be positive");
814 }
else if (strcmp(argv[k],
"--filtersize") == 0) {
816 if (k == *argc - 1) {
817 qCritical(
"--filtersize: argument required.");
820 if (!parseInt(argv[k + 1], ival)) {
821 qCritical() <<
"Illegal number:" << argv[k + 1];
825 qCritical(
"Filtersize should be at least 1024.");
828 for (filter_size = 1024; filter_size < ival; filter_size = 2 * filter_size)
830 filter.size = filter_size;
831 filter.taper_size = filter_size / 2;
832 }
else if (strcmp(argv[k],
"--magdip") == 0) {
835 }
else if (strcmp(argv[k],
"--dip") == 0) {
837 if (k == *argc - 1) {
838 qCritical(
"--dip: argument required.");
841 dipname = QString(argv[k + 1]);
842 }
else if (strcmp(argv[k],
"--bdip") == 0) {
844 if (k == *argc - 1) {
845 qCritical(
"--bdip: argument required.");
849 }
else if (strcmp(argv[k],
"--verbose") == 0) {
854 for (
int p = k; p < *argc - found; p++)
855 argv[p] = argv[p + found];
856 *argc = *argc - found;
860 return check_unrecognized_args(*argc, argv);
Command-line and programmatic settings struct for the mne_dipole_fit driver.
Inverse source estimation (MNE, dSPM, sLORETA, dipole fitting).
constexpr double BIG_TIME
MNELIB::MNEFilterDef filter
virtual ~InvDipoleFitSettings()