def setup_class(cls): """ Called once for all tests for Pipelines. Sets rounding_precision, and does a one-time load of dynamic and static trial data as dictionaries from SampleData/Sample_2/. """ cls.rounding_precision = 8 cwd = os.getcwd() if(cwd.split(os.sep)[-1]=="pyCGM_Single"): parent = os.path.dirname(cwd) os.chdir(parent) cls.cwd = os.getcwd() cur_dir = cls.cwd dynamic_trial, static_trial,_,_,_ = getfilenames(3) dynamic_trial = os.path.join(cur_dir, dynamic_trial) static_trial = os.path.join(cur_dir, static_trial) motionData = loadData(dynamic_trial) staticData = loadData(static_trial) cls.data_original = dataAsDict(motionData, npArray=True) cls.static_original = dataAsDict(staticData, npArray=True) for frame in motionData: frame['SACR'] = pelvisJointCenter(frame)[2] cls.data_with_sacrum_original = dataAsDict(motionData, npArray=True) Pipelines.clearMarker(motionData, 'LFHD') cls.data_with_sacrum_clear_marker = dataAsDict(motionData, npArray=True)
def test_transform_from_mov_exceptions(self,key,clust,last_time,i): """ We test exceptions raised when there are not enough usable markers, the frame number is out of range, and the marker name does not exist. """ data = self.data with pytest.raises(Exception): Pipelines.transform_from_mov(data,key,clust,last_time,i)
def test_segmentFinder_exceptions(self,key,target_dict,segment_dict,j,missings): """ We test the exception that is raised when the marker name does not exist. """ data = self.data with pytest.raises(Exception): Pipelines.segmentFinder(key,data,target_dict,segment_dict,j,missings)
def test_butterFilter_exceptions(self, data, cutoff, Fs): """ We test exceptions raised when the length of the input data is too short, when the cutoff frequency value is negative, zero, or too large, and when the sampling frequency value is negative, zero, or too small. """ with pytest.raises(Exception): Pipelines.butterFilter(data, cutoff, Fs)
def test_transform_from_static_exceptions(self, key, useables, s): """ We test exceptions raised when there are not enough usable markers, the frame number is out of range, or the marker name does not exist. """ data = self.data static = self.static with pytest.raises(Exception): Pipelines.transform_from_static(data,static,key,useables,s)
def test_filt_exceptions(self, data, cutoff, Fs): """ We test exceptions raised when the arrays in data are not of the same shape, when the length of data is too short, when the cutoff frequency value is negative, zero, or too large, when the sampling frequency value is negative, zero, or too small, and when data is not a numpy array. """ with pytest.raises(Exception): Pipelines.filt(data, cutoff, Fs)
def test_rigid_fill_exceptions(self): """ We test the exception raised when the marker SACR does not exist in Data. """ #Test that the marker SACR must exist: with pytest.raises(Exception): data = self.data static = self.static Pipelines.rigid_fill(data, static)
def test_prep_accuracy(self, trajs, expected_result): """ This function tests Pipelines.prep(trajs), where trajs is a dictionary containing numpy arrays. """ result = Pipelines.prep(trajs) np.testing.assert_equal(result, expected_result)
def test_clearMarker_accuracy(self, data, name, expected_result): """ This function tests Pipelines.clearMarker(data, name), where data is an array of dictionary of markers lists and name is the name of a marker to clear. We test cases where the values in data are lists and numpy arrays. We test the case where the marker name is not a key in data. """ result = Pipelines.clearMarker(data, name) np.testing.assert_equal(result, expected_result)
def test_filtering_accuracy(self, Data, expected_result): """ This function tests Pipelines.filtering(Data), where Data is a dictionary of marker lists. Pipelines.filtering() calls Pipelines.filt(), and uses the same fourth-order Butterworth filter constructed in Pipelines.butterFilter(). We test cases where inputs are numpy arrays of positive and negative floats and ints. """ result = Pipelines.filtering(Data) for key in Data: np.testing.assert_almost_equal(result[key], expected_result[key], self.rounding_precision)
def test_filt_accuracy(self, data, cutoff, Fs, expected_result): """ This function tests Pipelines.filt(data, cutoff, Fs), where data is a 2darray of numbers to filter, cutoff is the cutoff frequency to filter, and Fs is the sampling frequency of the data. Pipelines.filt() uses the same fourth-order Butterworth filter constructed in Pipelines.butterFilter(). We test cases where inputs are lists of positive and negative floats and ints. """ result = Pipelines.filt(data, cutoff, Fs) np.testing.assert_almost_equal(result, expected_result, self.rounding_precision)
def test_butterFilter_accuracy(self, data, cutoff, Fs, expected_result): """ This function tests Pipelines.butterFilter(data, cutoff, Fs), where data is an array of numbers to filter, cutoff is the cutoff frequency to filter, and Fs is the sampling frequency of the data. Pipelines.butterFilter applies a fourth-order low-pass Butterworth filter that is constructed using the scipy functions butter() and filtfilt(). For each case, we test that the Butterworth filter is applied correctly by testing its output is accurate in cases where inputs are positive and negative floats and integers. We test cases where inputs are lists and numpy arrays. """ #Call butterFilter() with parametrized values result = Pipelines.butterFilter(data, cutoff, Fs) np.testing.assert_almost_equal(result, expected_result, self.rounding_precision)
def test_segmentFinder_accuracy(self,key,target_dict,segment_dict,j,missings,expected_result): """ This function tests Pipelines.segmentFinder(key,data,target_dict,segment_dict,j,missings), where data is an array of dictionaries of marker data, key is the name of the missing marker to find the segment for, target_dict is a dictionary of marker to segment, segment_dict is a dictionary of segments to marker names, j is the frame number the marker is missing for, and missings is a dictionary indicating other missing markers. We test to ensure that missing markers are not used to reconstruct other missing markers. """ data = self.data result = Pipelines.segmentFinder(key,data,target_dict,segment_dict,j,missings) assert result == expected_result
def test_transform_from_mov_SampleData(self,key,clust,last_time,i,expected_result): """ This function tests Pipelines.transform_from_mov(data,key,clust,last_time,i), where data is an array of dictionaries of marker data, key is the name of the missing marker to perform gap filling for, clust is a list of markers in the same cluster as key, last_time is the last frame the the missing marker was visible, and i is the frame number the marker is missing for. We use files from SampleData/Sample_2/ for testing. We test for 6 missing frames from the loaded data. """ data = self.data data[key][i] = np.array([np.nan, np.nan, np.nan]) result = Pipelines.transform_from_mov(data,key,clust,last_time,i) np.testing.assert_almost_equal(result, expected_result, self.rounding_precision)
def test_transform_from_static_SampleData(self, key, useables, s, expected_result): """ This function tests Pipelines.transform_from_static(data,static,key,useables,s), where data is an array of dictionaries of marker data, static is an array of static marker data, key is the name of the missing marker to perform gap filling for, useables is a list of markers in the same cluster as key, and s is the frame number that the marker data is missing for. We use files from SampleData/Sample_2/ for testing. We test for 6 missing frames from the loaded data. """ data = self.data static = self.static #Clear given key and frame to test gap filling data[key][s] = np.array([np.nan, np.nan, np.nan]) result = Pipelines.transform_from_static(data,static,key,useables,s) np.testing.assert_almost_equal(result, expected_result, self.rounding_precision)
def test_transform_from_static(self): """ This function tests Pipelines.transform_from_static(). Pipelines.transform_from_static() uses a transformation that is stored between a 4 marker cluster. It requires an inverse transformation matrix to be stored between the combination of 3 marker groupings, with the 4th marker stored in relation to that frame. Pipelines.transform_from_static() takes in as input the missing marker, and uses static data to create an inverse transformation matrix, multiplying the new frame by the stored inverse transform to get the missing marker position. We test that Pipelines.transform_from_mov() is accurate by creating four markers in a square in static data, and adding one to all but one of their x-coordinates for motion data. We ensure that the correct position is reconstructed from the static data. """ #Define the four markers, A, B, C, D, as the four corners of a square. static = { 'A': np.array([[1, 1, 0]]), 'B': np.array([[-1, 1, 0]]), 'C': np.array([[1, -1, 0]]), 'D': np.array([[-1, -1, 0]]) } #Use the three markers, B, C, D to reconstruct the position of A useables = ['B', 'C', 'D'] #Add one to all of the x-coordinates of B, C, D data = { 'B': np.array([[0, 1, 0]]), 'C': np.array([[2, -1, 0]]), 'D': np.array([[0, -1, 0]]) } #We expect that A is at [2, 1, 0] expected = np.array([2, 1, 0]) result = Pipelines.transform_from_static(data, static, 'A', useables, 0) np.testing.assert_equal(result, expected)
def test_transform_from_mov(self): """ This function tests Pipelines.transform_from_mov(). Pipelines.transform_from_mov() uses a transformation that is stored between a 4 marker cluster. It requires an inverse transformation matrix to be stored between the combination of 3 marker groupings, with the 4th marker stored in relation to that frame. Pipelines.transform_from_mov() takes in as input the missing marker, and uses previous frames of motion data to create an inverse transformation matrix, multiplying the new frame by the stored inverse transform to get the missing marker position. We test that Pipelines.transform_from_mov() is accurate by creating four markers in a square at frame zero, and adding one to all but one of their x-coordinates in frame 1. We ensure that the correct position is reconstructed from the previous frame data, and that the fourth marker is in the correct position after the transform. """ #Define the four markers, A, B, C, D, as the four corners of a square in frame 0. #Add one to the x-coordinate of all markers but A in frame 1. data = { 'A': np.array([[1, 1, 0], [np.nan, np.nan, np.nan]]), 'B': np.array([[-1, 1, 0], [0, 1, 0]]), 'C': np.array([[1, -1, 0], [2, -1, 0]]), 'D': np.array([[-1, -1, 0], [0, -1, 0]]) } #Use the three markers, B, C, D to reconstruct the position of A clust = ['B', 'C', 'D'] #Last frame in which all four markers were visible last_time = 0 #Frame for which a marker is missing data i = 1 #We expect that A is at [2, 1, 0] expected = np.array([2, 1, 0]) result = Pipelines.transform_from_mov(data, 'A', clust, last_time, i) np.testing.assert_equal(result, expected)
def test_rigid_fill_transform_from_static(self): """ This function tests Pipelines.rigid_fill(Data, static), where Data is an array of dictionaries of marker data, and static is an array of dictionaries of static trial data. Pipelines.rigid_fill() fills gaps for frames with missing data using the transform functions Pipelines.transform_from_static and Pipelines.transform_from_mov. Pipelines.rigid_fill() determines whether to call transform_from_static or transform_from_mov by determining if there is a previous frame where all markers in the cluster of the missing marker exist, and can be used to create an inverse transformation matrix to determine the position of the missing marker in the current frame. If there is, transform_from_mov is used. Otherwise, transform_from_static, which uses static data to reconstruct missing markers, is used. This function tests that rigid_fill will properly call transform_from_static by using Pipelines.clearMarker() to clear the value of a given key at all frames. Since there are no other frames to reconstruct the inverse transform off of, we expect the function to use transform_from_static. """ #The sacrum marker must exist in data to use rigid_fill #Use data with the LFHD marker cleared from every frame data = self.data_with_sacrum_clear_marker static = self.static #Return value from transform_from_static is mocked mock_return_val = np.array([1, 2, 3]) with mock.patch.object(Pipelines, 'transform_from_static', return_value=mock_return_val) as mock_transform_from_static: #Call Pipelines.rigid_fill with the mocked transform_from_static rigid_fill_data = Pipelines.rigid_fill(data, static) mock_transform_from_static.assert_called() result = rigid_fill_data['LFHD'][10] np.testing.assert_almost_equal(result, np.array([1, 2, 3]), self.rounding_precision)
def test_rigid_fill_transform_from_mov(self): """ This function tests that Pipelines.rigid_fill() will properly call transform_from_mov by clearing the value of a marker at only one frame. We expect transform_from_mov to be called in this case since there are previous markers to create the inverse transform matrix from. """ #Use data with all markers data = self.data_with_sacrum static = self.static #Clear marker LFHD from frame 10 data['LFHD'][10] = np.array([np.nan, np.nan, np.nan]) #Return value from transform_from_mov is mocked mock_return_val = np.array([1, 2, 3]) with mock.patch.object(Pipelines, 'transform_from_mov', return_value=mock_return_val) as mock_transform_from_mov: #Call Pipelines.rigid_fill with the mocked transform_from_static rigid_fill_data = Pipelines.rigid_fill(data, static) mock_transform_from_mov.assert_called() result = rigid_fill_data['LFHD'][10] np.testing.assert_almost_equal(result, np.array([1, 2, 3]), self.rounding_precision)
def test_prep_exceptions(self, trajs): with pytest.raises(Exception): Pipelines.prep(trajs)
def test_filtering_exceptions(self, Data): with pytest.raises(Exception): Pipelines.filtering(Data)