Example #1
0
def test_module(input_json):
    with patch("sys.argv", ["test_run", input_json]):
        with patch("logging.info"):
            run_ophys_time_sync.main()

    with open(input_json, "r") as f:
        input_data = json.load(f)

    output_file = input_data.pop("output_file")
    assert os.path.exists(output_file)

    input_data.pop("ophys_experiment_id")
    sync_file = input_data.pop("sync_file")
    aligner = ts.OphysTimeAligner(sync_file, **input_data)
    with h5py.File(output_file) as f:
        t, d = aligner.corrected_ophys_timestamps
        assert np.all(t == f['twop_vsync_fall'].value)
        assert np.all(d == f['ophys_delta'].value)
        st, sd, stim_delay = aligner.corrected_stim_timestamps
        align = ts.get_alignment_array(t, st)
        assert np.allclose(align,
                           f['stimulus_alignment'].value,
                           equal_nan=True)
        assert np.all(sd == f['stim_delta'].value)
        et, ed = aligner.corrected_eye_video_timestamps
        align = ts.get_alignment_array(et, t, int_method=np.ceil)
        assert np.allclose(align,
                           f['eye_tracking_alignment'].value,
                           equal_nan=True)
        assert np.all(ed == f['eye_delta'].value)
        bt, bd = aligner.corrected_behavior_video_timestamps
        align = ts.get_alignment_array(bt, t, int_method=np.ceil)
        assert np.allclose(align,
                           f['body_camera_alignment'].value,
                           equal_nan=True)
Example #2
0
def test_regression_stim_timestamps(nikon_input, scientifica_input):
    for input_data in [nikon_input, scientifica_input]:
        sync_file = input_data.pop("sync_file")
        aligner = ts.OphysTimeAligner(sync_file, **input_data)
        freq = aligner.dataset.meta_data['ni_daq']['counter_output_freq']
        old_times = calculate_stim_vsync_fall(aligner.dataset, freq)
        assert np.allclose(aligner.stim_timestamps, old_times)
Example #3
0
def test_get_corrected_ophys_times_nikon(ophys_data_length):
    true_times = np.arange(6000)

    with patch.object(ts, "get_keys", return_value=mock_keys):
        with patch.object(ts.Dataset, "load"):
            aligner = ts.OphysTimeAligner("test", "NIKONA1RMP")

    aligner.ophys_data_length = ophys_data_length
    with patch.object(ts.Dataset, "get_falling_edges",
                      return_value=true_times):
        with patch.object(ts.Dataset, "get_rising_edges", return_value=[0]):
            with patch("logging.info") as mock_log:
                if ophys_data_length is not None and \
                   ophys_data_length > len(true_times):
                    with pytest.raises(ValueError):
                        times, delta = aligner.corrected_ophys_timestamps
                else:
                    times, delta = aligner.corrected_ophys_timestamps
                    if ophys_data_length is None:
                        assert np.all(times == true_times)
                        mock_log.assert_called_once()
                        assert delta == 0
                    elif ophys_data_length != len(true_times):
                        assert np.all(times == true_times[:-delta])
                        mock_log.assert_called_once()
                    else:
                        assert mock_log.call_count == 0
                        assert np.all(times == true_times)

    aligner.scanner = "bad"
    with pytest.raises(ValueError):
        aligner.corrected_ophys_timestamps
Example #4
0
def test_get_corrected_behavior_times(behavior_data_length):
    true_times = np.arange(6000)

    with patch.object(ts, "get_keys", return_value=mock_keys):
        with patch.object(ts.Dataset, "load"):
            aligner = ts.OphysTimeAligner("test")

    aligner.behavior_data_length = behavior_data_length
    with patch.object(ts.Dataset, "get_falling_edges",
                      return_value=true_times) as mock_falling:
        with patch("logging.info") as mock_log:
            times, delta = aligner.corrected_behavior_video_timestamps

    if behavior_data_length != 6000:
        mock_log.assert_called_once()
    else:
        assert mock_log.call_count == 0

    mock_falling.assert_called_once()
    assert np.all(times == true_times)

    if behavior_data_length is None:
        assert delta == 0
    else:
        assert delta == (len(true_times) - behavior_data_length)
def main():
    parser = argparse.ArgumentParser("Generate brain observatory alignment.")
    parser.add_argument('input_json')
    parser.add_argument('--log-level', default=logging.DEBUG)
    mod = PipelineModule("Generate brain observatory alignment.", parser)

    input_data = mod.input_data()
    experiment_id = input_data.pop("ophys_experiment_id")
    sync_file = input_data.pop("sync_file")
    output_file = input_data.pop("output_file")

    aligner = ts.OphysTimeAligner(sync_file, **input_data)

    ophys_times, ophys_delta = aligner.corrected_ophys_timestamps
    stim_times, stim_delta = aligner.corrected_stim_timestamps
    eye_times, eye_delta = aligner.corrected_eye_video_timestamps
    beh_times, beh_delta = aligner.corrected_behavior_video_timestamps

    # stim array is index of ophys frame for each stim frame to match to
    # so len(stim_times)
    stim_alignment = ts.get_alignment_array(ophys_times, stim_times)

    # camera arrays are index of camera frame for each ophys frame ...
    # cam_nwb_creator depends on this so keeping it that way even though
    # it makes little sense... len(video_times)
    eye_alignment = ts.get_alignment_array(eye_times, ophys_times,
                                           int_method=np.ceil)

    behavior_alignment = ts.get_alignment_array(beh_times, ophys_times,
                                                int_method=np.ceil)

    write_output(output_file, ophys_times, stim_alignment, eye_alignment,
                 behavior_alignment, ophys_delta, stim_delta, eye_delta,
                 beh_delta)
Example #6
0
def test_regression_valid_2p_timestamps(nikon_input, scientifica_input):
    sync_file = nikon_input.pop("sync_file")
    aligner = ts.OphysTimeAligner(sync_file, **nikon_input)
    freq = aligner.dataset.meta_data['ni_daq']['counter_output_freq']
    old_times = calculate_valid_twop_vsync_fall(aligner.dataset, freq)
    new_times = aligner.ophys_timestamps
    assert np.allclose(new_times[1:], old_times)

    # old scientifica used falling edges as timestamps incorrectly
    sync_file = scientifica_input.pop("sync_file")
    aligner = ts.OphysTimeAligner(sync_file, **scientifica_input)
    freq = aligner.dataset.meta_data['ni_daq']['counter_output_freq']
    old_times = calculate_valid_twop_vsync_fall(aligner.dataset, freq)
    new_times = aligner.ophys_timestamps
    assert len(new_times) - len(old_times) == 1
    assert np.all(new_times[1:] < old_times)
    assert np.all(new_times[2:] > old_times[:-1])
Example #7
0
def test_get_corrected_stim_times(stim_data_length, start_delay):
    true_falling = np.arange(0, 60, 0.01)
    true_rising = true_falling + 0.005
    if start_delay:
        true_falling[0] -= 3
        true_rising[0] -= 3

    with patch.object(ts, "get_keys", return_value=mock_keys):
        with patch.object(ts.Dataset, "load"):
            aligner = ts.OphysTimeAligner("test")

    aligner.stim_data_length = stim_data_length
    with patch.object(ts,
                      "calculate_monitor_delay",
                      return_value=ASSUMED_DELAY):
        with patch.object(ts.Dataset,
                          "get_falling_edges",
                          return_value=true_falling):
            with patch.object(ts.Dataset,
                              "get_rising_edges",
                              return_value=true_rising) as mock_rising:
                with patch("logging.info") as mock_log:
                    times, delta, stim_delay = \
                            aligner.corrected_stim_timestamps

    if stim_data_length is None:
        mock_log.assert_called_once()
        assert mock_rising.call_count == 0
        assert delta == 0
    elif stim_data_length != len(true_falling) and start_delay:
        mock_rising.assert_called_once()
        assert mock_log.call_count == 2
        assert len(times) == len(true_falling) - 1
        assert delta == len(true_falling) - 1 - stim_data_length
        assert np.all(times == true_falling[1:] + ASSUMED_DELAY)
    elif stim_data_length != len(true_falling):
        mock_rising.assert_called_once()
        mock_log.assert_called_once()
        assert delta == len(true_falling) - stim_data_length
        assert np.all(times == true_falling + ASSUMED_DELAY)
    else:
        assert mock_rising.call_count == 0
        assert np.all(times == true_falling + ASSUMED_DELAY)
        assert mock_log.call_count == 0
        assert delta == 0
Example #8
0
def test_regression_calculate_stimulus_alignment(nikon_input,
                                                 scientifica_input):
    for input_data in [nikon_input, scientifica_input]:
        sync_file = input_data.pop("sync_file")
        aligner = ts.OphysTimeAligner(sync_file, **input_data)
        old_align = calculate_stimulus_alignment(aligner.stim_timestamps,
                                                 aligner.ophys_timestamps)
        new_align = ts.get_alignment_array(aligner.ophys_timestamps,
                                           aligner.stim_timestamps)

        # Old alignment assigned simultaneous stim frames to the previous ophys
        # frame. Methods should only differ when ophys and stim are identical.
        mismatch = old_align != new_align
        mis_o = aligner.ophys_timestamps[new_align[mismatch].astype(int)]
        mis_s = aligner.stim_timestamps[mismatch]
        assert np.all(mis_o == mis_s)
        # Occurence of mismatch should be rare
        assert len(mis_o) < 0.005 * len(aligner.ophys_timestamps)
Example #9
0
def main():
    parser = argparse.ArgumentParser("Generate brain observatory alignment.")
    parser.add_argument("input_json", type=str, 
        help="path to input json"
    )
    parser.add_argument("output_json", type=str, nargs="?",
        help="path to which output json will be written"
    )
    parser.add_argument("--log-level", default=logging.DEBUG)
    parser.add_argument("--min-stimulus-delay", type=float, default=0.0, 
        help="reject results if monitor delay less than this value (s)"
    )
    parser.add_argument("--max-stimulus-delay", type=float, default=0.07, 
        help="reject results if monitor delay greater than this value (s)"
    )
    mod = PipelineModule("Generate brain observatory alignment.", parser)

    input_data = mod.input_data()

    writer = TimeSyncWriter(input_data.get("output_file"), mod.args.output_json)
    writer.validate_paths()

    aligner = ts.OphysTimeAligner(
        input_data.get("sync_file"), 
        scanner=input_data.get("scanner", None),
        dff_file=input_data.get("dff_file", None),
        stimulus_pkl=input_data.get("stimulus_pkl", None),
        eye_video=input_data.get("eye_video", None),
        behavior_video=input_data.get("behavior_video", None),
        long_stim_threshold=input_data.get(
            "long_stim_threshold", ts.LONG_STIM_THRESHOLD
        )
    )

    outputs = run_ophys_time_sync(
        aligner, 
        input_data.get("ophys_experiment_id"), 
        mod.args.min_stimulus_delay, 
        mod.args.max_stimulus_delay
    )
    writer.write(outputs)
Example #10
0
def test_regression_calculate_camera_alignment(nikon_input, scientifica_input):
    for input_data in [nikon_input, scientifica_input]:
        sync_file = input_data.pop("sync_file")
        aligner = ts.OphysTimeAligner(sync_file, **input_data)
        freq = aligner.dataset.meta_data['ni_daq']['counter_output_freq']
        old_eye_align = sync_camera_stimulus(aligner.dataset, freq, 2, 1)
        # old alignment throws out the first ophys timestamp
        new_eye_align = ts.get_alignment_array(aligner.eye_video_timestamps,
                                               aligner.ophys_timestamps[1:],
                                               int_method=np.ceil)
        mismatch = np.where(old_eye_align[:, 0] != new_eye_align)
        mis_e = \
            aligner.eye_video_timestamps[new_eye_align[mismatch].astype(int)]
        mis_o = aligner.ophys_timestamps[1:][mismatch]
        mis_o_plus = aligner.ophys_timestamps[1:][(mismatch[0] + 1, )]
        # New method should only disagree when old method was wrong (old method
        # set an eye tracking frame to an earlier ophys frame).
        assert np.all(mis_o < mis_e)
        assert np.all(mis_o_plus >= mis_e)
        # Occurence of mismatch should be rare
        assert len(mis_o) < 0.005 * len(aligner.ophys_timestamps[1:])