def get_config(subject: Optional[str] = None, session: Optional[str] = None) -> BunchConst: cfg = BunchConst( process_er=config.process_er, runs=config.get_runs(subject=subject), use_maxwell_filter=config.use_maxwell_filter, proc=config.proc, task=config.get_task(), datatype=config.get_datatype(), acq=config.acq, rec=config.rec, space=config.space, bids_root=config.get_bids_root(), deriv_root=config.get_deriv_root(), l_freq=config.l_freq, h_freq=config.h_freq, l_trans_bandwidth=config.l_trans_bandwidth, h_trans_bandwidth=config.h_trans_bandwidth, resample_sfreq=config.resample_sfreq, crop_runs=config.crop_runs, interactive=config.interactive, rename_events=config.rename_events, eeg_bipolar_channels=config.eeg_bipolar_channels, eeg_template_montage=config.eeg_template_montage, fix_stim_artifact=config.fix_stim_artifact, stim_artifact_tmin=config.stim_artifact_tmin, stim_artifact_tmax=config.stim_artifact_tmax, find_flat_channels_meg=config.find_flat_channels_meg, find_noisy_channels_meg=config.find_noisy_channels_meg, reference_run=config.get_mf_reference_run(), drop_channels=config.drop_channels, find_breaks=config.find_breaks, min_break_duration=config.min_break_duration, t_break_annot_start_after_previous_event=config. t_break_annot_start_after_previous_event, # noqa:E501 t_break_annot_stop_before_next_event=config. t_break_annot_stop_before_next_event, # noqa:E501 ) return cfg
def get_config( subject: Optional[str] = None, session: Optional[str] = None ) -> BunchConst: cfg = BunchConst( mf_cal_fname=config.get_mf_cal_fname(subject, session), mf_ctc_fname=config.get_mf_ctc_fname(subject, session), mf_st_duration=config.mf_st_duration, mf_head_origin=config.mf_head_origin, process_er=config.process_er, runs=config.get_runs(subject=subject), # XXX needs to accept session! use_maxwell_filter=config.use_maxwell_filter, proc=config.proc, task=config.get_task(), datatype=config.get_datatype(), acq=config.acq, rec=config.rec, space=config.space, bids_root=config.get_bids_root(), deriv_root=config.get_deriv_root(), crop_runs=config.crop_runs, interactive=config.interactive, rename_events=config.rename_events, eeg_template_montage=config.eeg_template_montage, fix_stim_artifact=config.fix_stim_artifact, stim_artifact_tmin=config.stim_artifact_tmin, stim_artifact_tmax=config.stim_artifact_tmax, find_flat_channels_meg=config.find_flat_channels_meg, find_noisy_channels_meg=config.find_noisy_channels_meg, mf_reference_run=config.get_mf_reference_run(), drop_channels=config.drop_channels, find_breaks=config.find_breaks, min_break_duration=config.min_break_duration, t_break_annot_start_after_previous_event=config.t_break_annot_start_after_previous_event, # noqa:E501 t_break_annot_stop_before_next_event=config.t_break_annot_stop_before_next_event, # noqa:E501 ) return cfg
def run_maxwell_filter(subject, session=None): if config.proc and 'sss' in config.proc and config.use_maxwell_filter: raise ValueError(f'You cannot set use_maxwell_filter to True ' f'if data have already processed with Maxwell-filter.' f' Got proc={config.proc}.') bids_path_in = BIDSPath(subject=subject, session=session, task=config.get_task(), acquisition=config.acq, processing=config.proc, recording=config.rec, space=config.space, suffix=config.get_datatype(), datatype=config.get_datatype(), root=config.bids_root) bids_path_out = bids_path_in.copy().update(suffix='raw', root=config.deriv_root, check=False) # Load dev_head_t and digitization points from MaxFilter reference run. # Re-use in all runs and for processing empty-room recording. if config.use_maxwell_filter: reference_run = config.get_mf_reference_run() msg = f'Loading reference run: {reference_run}.' logger.info( gen_log_message(message=msg, step=1, subject=subject, session=session)) bids_path_in.update(run=reference_run) info = mne.io.read_info(bids_path_in.fpath) dev_head_t = info['dev_head_t'] dig = info['dig'] del reference_run, info for run_idx, run in enumerate(config.get_runs()): bids_path_in.update(run=run) bids_path_out.update(run=run) raw = load_data(bids_path_in) # Fix stimulation artifact if config.fix_stim_artifact: events, _ = mne.events_from_annotations(raw) raw = mne.preprocessing.fix_stim_artifact( raw, events=events, event_id=None, tmin=config.stim_artifact_tmin, tmax=config.stim_artifact_tmax, mode='linear') # Auto-detect bad channels. if config.find_flat_channels_meg or config.find_noisy_channels_meg: find_bad_channels(raw=raw, subject=subject, session=session, task=config.get_task(), run=run) # Maxwell-filter experimental data. if config.use_maxwell_filter: msg = 'Applying Maxwell filter to experimental data.' logger.info( gen_log_message(message=msg, step=1, subject=subject, session=session)) # Warn if no bad channels are set before Maxwell filter if not raw.info['bads']: msg = '\nFound no bad channels. \n ' logger.warning( gen_log_message(message=msg, subject=subject, step=1, session=session)) if config.mf_st_duration: msg = ' st_duration=%d' % (config.mf_st_duration) logger.info( gen_log_message(message=msg, step=1, subject=subject, session=session)) # Keyword arguments shared between Maxwell filtering of the # experimental and the empty-room data. common_mf_kws = dict(calibration=get_mf_cal_fname( subject, session), cross_talk=get_mf_ctc_fname(subject, session), st_duration=config.mf_st_duration, origin=config.mf_head_origin, coord_frame='head', destination=dev_head_t) raw_sss = mne.preprocessing.maxwell_filter(raw, **common_mf_kws) raw_out = raw_sss raw_fname_out = (bids_path_out.copy().update(processing='sss', extension='.fif')) elif config.ch_types == ['eeg']: msg = 'Not applying Maxwell filter to EEG data.' logger.info( gen_log_message(message=msg, step=1, subject=subject, session=session)) raw_out = raw raw_fname_out = bids_path_out.copy().update(extension='.fif') else: msg = ('Not applying Maxwell filter.\nIf you wish to apply it, ' 'set use_maxwell_filter=True in your configuration.') logger.info( gen_log_message(message=msg, step=1, subject=subject, session=session)) raw_out = raw raw_fname_out = bids_path_out.copy().update(extension='.fif') # Save only the channel types we wish to analyze (including the # channels marked as "bad"). # We do not run `raw_out.pick()` here because it uses too much memory. chs_to_include = config.get_channels_to_analyze(raw_out.info) raw_out.save(raw_fname_out, picks=chs_to_include, overwrite=True, split_naming='bids') del raw_out if config.interactive: # Load the data we have just written, because it contains only # the relevant channels. raw = mne.io.read_raw_fif(raw_fname_out, allow_maxshield=True) raw.plot(n_channels=50, butterfly=True) # Empty-room processing. # # We pick the empty-room recording closest in time to the first run # of the experimental session. if run_idx == 0 and config.process_er: msg = 'Processing empty-room recording …' logger.info( gen_log_message(step=1, subject=subject, session=session, message=msg)) bids_path_er_in = bids_path_in.find_empty_room() raw_er = load_data(bids_path_er_in) raw_er.info['bads'] = [ ch for ch in raw.info['bads'] if ch.startswith('MEG') ] # Maxwell-filter empty-room data. if config.use_maxwell_filter: msg = 'Applying Maxwell filter to empty-room recording' logger.info( gen_log_message(message=msg, step=1, subject=subject, session=session)) # We want to ensure we use the same coordinate frame origin in # empty-room and experimental data processing. To do this, we # inject the sensor locations and the head <> device transform # into the empty-room recording's info, and leave all other # parameters the same as for the experimental data. This is not # very clean, as we normally should not alter info manually, # except for info['bads']. Will need improvement upstream in # MNE-Python. raw_er.info['dig'] = dig raw_er.info['dev_head_t'] = dev_head_t raw_er_sss = mne.preprocessing.maxwell_filter( raw_er, **common_mf_kws) # Perform a sanity check: empty-room rank should match the # experimental data rank after Maxwell filtering. rank_exp = mne.compute_rank(raw, rank='info')['meg'] rank_er = mne.compute_rank(raw_er, rank='info')['meg'] if not np.isclose(rank_exp, rank_er): msg = (f'Experimental data rank {rank_exp:.1f} does not ' f'match empty-room data rank {rank_er:.1f} after ' f'Maxwell filtering. This indicates that the data ' f'were processed differenlty.') raise RuntimeError(msg) raw_er_out = raw_er_sss raw_er_fname_out = bids_path_out.copy().update( processing='sss') else: raw_er_out = raw_er raw_er_fname_out = bids_path_out.copy() raw_er_fname_out = raw_er_fname_out.update(task='noise', extension='.fif', run=None) # Save only the channel types we wish to analyze # (same as for experimental data above). raw_er_out.save(raw_er_fname_out, picks=chs_to_include, overwrite=True, split_naming='bids') del raw_er_out