def test_transform_ie_simple(self): """Class SpharaTransform, mode='inv_euclidean', simple triangular mesh Determine the SPHARA forward and inverse transform with inverse Euclidean edge weight for a simple triangular mesh, 3 vertices, single triangle. """ # define the simple test mesh testtrimesh = tm.TriMesh([[0, 1, 2]], [[1, 0, 0], [0, 2, 0], [0, 0, 3]]) # create a SPHARA transform instance for the mesh st_ie_simple = st.SpharaTransform(testtrimesh, mode='inv_euclidean') # the data to transform data = np.concatenate([[[0., 0., 0.], [1., 1., 1.]], np.transpose(st_ie_simple.basis()[0])]) # SPHARA analysis coef_ie_simple = st_ie_simple.analysis(data) # SPHARA synthesis recon_ie_simple = st_ie_simple.synthesis(coef_ie_simple) self.assertTrue( np.allclose(np.absolute(coef_ie_simple), [[0.0, 0.0, 0.0], [1.73205081, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]) and np.allclose(recon_ie_simple, data))
def test_filter_fem_allpass_simple(self): """Class SpharaFilter, mode='fem', allpass, simple mesh Apply a SPHARA spatial allpass filter with fem edge weight to data sampled at a simple triangular mesh, 3 vertices, single triangle. """ # define the simple test mesh testtrimesh = tm.TriMesh([[0, 1, 2]], [[1, 0, 0], [0, 2, 0], [0, 0, 3]]) # create a SPHARA filter instance for the mesh sf_fem_simple = sf.SpharaFilter(testtrimesh, mode='fem', specification=0) # the data to filter data = np.concatenate([[[0., 0., 0.], [1., 1., 1.]], np.transpose(sf_fem_simple.basis()[0])]) # apply SPHARA based spatial allpass filter data_filt_fem_simple = sf_fem_simple.filter(data) self.assertTrue(np.allclose(data_filt_fem_simple, data))
def test_filter_unit_dc_simple(self): """Class SpharaFilter, mode='unit', dc-pass, simple mesh Apply a SPHARA spatial dc-pass filter with unit edge weight to data sampled at a simple triangular mesh, 3 vertices, single triangle. """ # define the simple test mesh testtrimesh = tm.TriMesh([[0, 1, 2]], [[1, 0, 0], [0, 2, 0], [0, 0, 3]]) # create a SPHARA filter instance for the mesh sf_unit_simple = sf.SpharaFilter(testtrimesh, mode='unit', specification=1) # the data to filter data = np.concatenate([[[0., 0., 0.], [1., 1., 1.]], np.transpose(sf_unit_simple.basis()[0])]) # reference for filtered data data_filt_ref = data.copy() data_filt_ref[3] = [0., 0., 0.] data_filt_ref[4] = [0., 0., 0.] # apply SPHARA based spatial dc-pass filter data_filt_unit_simple = sf_unit_simple.filter(data) self.assertTrue(np.allclose(data_filt_unit_simple, data_filt_ref))
def test_basis_fem_result(self): """Class SpharaBasis, method basis, mode='fem', triangular test mesh Determine the SPHARA basis with FEM discretization for a triangular mesh with 118 vertices. The valid basis vectors of the SPHARA basis can point in opposite directions (multiplication by -1). To compare the calculated basis with the reference basis, the transposed matrix of the calculated basis is multiplied by the matrix of the reference basis. If the calculated basis is correct, then the result matrix of the matrix multiplication contains only the elements 1 and -1 at the main diagonal, all other elements of the matrix are 0 or very small. """ testtrimesh = tm.TriMesh(self.testdatatriangles, self.testdatavertices) sb_fem = sb.SpharaBasis(testtrimesh, mode='fem') sb_fem_fun, sb_fem_freq = sb_fem.basis() self.assertTrue( np.allclose( np.absolute( np.matmul( np.matmul(np.transpose(sb_fem_fun), self.testdatamassmatrix), self.testdataspharabasisfemweight)), np.identity(np.size(sb_fem_freq))) and np.allclose(sb_fem_freq, self.testdataspharanatfreqfemweight))
def test_massmatrix_result(self): """ Class TriMesh, method massmatrix, triangular test mesh Determine the mass matrix for a triangular mesh with 118 vertices. """ testtrimesh = tm.TriMesh(self.testdatatriangles, self.testdatavertices) (self.assertTrue( np.allclose(testtrimesh.massmatrix(), self.testdatamassmatrix)))
def test_tri_mesh_constructor_dimension(self): """ Class TriMesh, constructor, dimension exception Raise an exception if triangle list has wrong dimension. """ with self.assertRaises(ValueError) as cm: tm.TriMesh([1, 2, 3, 4], [1, 2, 3, 4]) err = cm.exception self.assertEqual(str(err), 'Triangle list has to be 2D!')
def test_weightmatrix_unitweight_result(self): """ Class TriMesh, method weightmatrix, mode='unit', triangular test mesh Determine the weight matrix with unit edge weight for a triangular mesh with 118 vertices. """ testtrimesh = tm.TriMesh(self.testdatatriangles, self.testdatavertices) self.assertTrue( np.array_equal(testtrimesh.weightmatrix(mode='unit'), self.testdataweightmatrixunitweight))
def test_laplacianmatrix_halfcot_result(self): """ Class TriMesh, method laplacianmatrix, mode='half_cotangent', triangular test mesh Determine the laplacian matrix (half cotangent edge weighting) for a triangular mesh with 118 vertices. """ testtrimesh = tm.TriMesh(self.testdatatriangles, self.testdatavertices) (self.assertTrue( np.allclose(testtrimesh.laplacianmatrix(mode='half_cotangent'), self.testdatalaplacianmatrixhalfcotweight)))
def test_weightmatrix_unitweight_simple(self): """ Class TriMesh, method weightmatrix, mode='unit', simple triangular mesh Determine the weight matrix with unit edge weight for a simple triangular mesh, 3 vertices, single triangle, equilateral. """ testtrimesh = tm.TriMesh([[0, 1, 2]], [[1., 0., 0.], [0., 2., 0.], [0., 0., 3.]]) self.assertTrue( np.allclose(testtrimesh.weightmatrix(mode='unit'), [[0.0, 1.0, 1.0], [1.0, 0.0, 1.0], [1.0, 1.0, 0.0]]))
def test_laplacianmatrix_inveuclid_result(self): """ Class TriMesh, method laplacianmatrix, mode='inv_euclidean', triangular test mesh Determine the laplacian matrix (inverse euclidean edge weighting) for a triangular mesh with 118 vertices. """ testtrimesh = tm.TriMesh(self.testdatatriangles, self.testdatavertices) (self.assertTrue( np.allclose(testtrimesh.laplacianmatrix(mode='inv_euclidean'), self.testdatalaplacianmatrixieweight)))
def test_massmatrix_simple(self): """Class TriMesh, method massmatrix, simple triangular mesh Determine the mass matrix for a simple triangular mesh, 3 vertices, single triangle, equilateral. """ testtrimesh = tm.TriMesh([[0, 1, 2]], [[1., 0., 0.], [0., 2., 0.], [0., 0., 3.]]) self.assertTrue( np.allclose(testtrimesh.massmatrix(), [[0.58333333, 0.29166667, 0.29166667], [0.29166667, 0.58333333, 0.29166667], [0.29166667, 0.29166667, 0.58333333]]))
def test_tri_mesh_constructor_three_row(self): """ Class TriMesh, constructor, non 3 elem exception Raise an exception if the rows of the triangle list dont consists of 3 integers. """ with self.assertRaises(ValueError) as cm: tm.TriMesh([[0, 1], [2, 3]], [[1, 2], [3, 4]]) err = cm.exception self.assertEqual( str(err), 'Each entry of the triangle list has to ' 'consist of three elements!')
def test_stiffnessmatrix_simple(self): """Class TriMesh, method stiffnessmatrix, simple triangular mesh Determine the stiffness matrix for a simple triangular mesh, 3 vertices, single triangle, equilateral. """ testtrimesh = tm.TriMesh([[0, 1, 2]], [[1., 0., 0.], [0., 2., 0.], [0., 0., 3.]]) self.assertTrue( np.allclose(testtrimesh.stiffnessmatrix(), [[-0.92857143, 0.64285714, 0.28571429], [0.64285714, -0.71428571, 0.07142857], [0.28571429, 0.07142857, -0.35714286]]))
def test_laplacianmatrix_unit_simple(self): """ Class TriMesh, method laplacianmatrix, mode='unit', simple triangular mesh Determine the laplacian matrix (unit edge weighting) for a simple triangular mesh, 3 vertices, single triangle, equilateral. """ testtrimesh = tm.TriMesh([[0, 1, 2]], [[1., 0., 0.], [0., 2., 0.], [0., 0., 3.]]) self.assertTrue( np.allclose(testtrimesh.laplacianmatrix(mode='unit'), [[2, -1, -1], [-1, 2, -1], [-1, -1, 2]]))
def test_weightmatrix_inveuclid_simple(self): """ Class TriMesh, method weightmatrix, mode='inv_euclidean', simple triangular mesh Determine the weight matrix with inverse euclidean edge weight for a simple triangular mesh, 3 vertices, single triangle, equilateral. """ testtrimesh = tm.TriMesh([[0, 1, 2]], [[1., 0., 0.], [0., 2., 0.], [0., 0., 3.]]) self.assertTrue( np.allclose( testtrimesh.weightmatrix(mode='inv_euclidean'), [[0., 0.4472136, 0.31622777], [0.4472136, 0., 0.2773501], [0.31622777, 0.2773501, 0.]]))
def test_weightmatrix_halfcot_simple(self): """ Class TriMesh, method weightmatrix, mode='half_cotangent', simple triangular mesh Determine the weight matrix with unit edge weight for a simple triangular mesh, 3 vertices, single triangle, equilateral. """ testtrimesh = tm.TriMesh([[0, 1, 2]], [[1., 0., 0.], [0., 2., 0.], [0., 0., 3.]]) self.assertTrue( np.allclose( testtrimesh.weightmatrix(mode='half_cotangent'), [[0., 0.64285714, 0.28571429], [0.64285714, 0., 0.07142857], [0.28571429, 0.07142857, 0.]]))
def test_laplacianmatrix_halfcot_simple(self): """ Class TriMesh, method laplacianmatrix, mode='half_cotangent', simple triangular mesh Determine the laplacian matrix (half cotangent edge weighting) for a simple triangular mesh, 3 vertices, single triangle, equilateral. """ testtrimesh = tm.TriMesh([[0, 1, 2]], [[1., 0., 0.], [0., 2., 0.], [0., 0., 3.]]) (self.assertTrue( np.allclose(testtrimesh.laplacianmatrix(mode='half_cotangent'), [[0.92857143, -0.64285714, -0.28571429], [-0.64285714, 0.71428571, -0.07142857], [-0.28571429, -0.07142857, 0.35714286]])))
def test_laplacianmatrix_inveuclid_simple(self): """ Class TriMesh, method laplacianmatrix, mode='inv_euclidean', simple triangular mesh Determine the laplacian matrix (inverse euclidean edge weighting) for a simple triangular mesh, 3 vertices, single triangle, equilateral. """ testtrimesh = tm.TriMesh([[0, 1, 2]], [[1., 0., 0.], [0., 2., 0.], [0., 0., 3.]]) (self.assertTrue( np.allclose(testtrimesh.laplacianmatrix(mode='inv_euclidean'), [[0.76344136, -0.4472136, -0.31622777], [-0.4472136, 0.72456369, -0.2773501], [-0.31622777, -0.2773501, 0.59357786]])))
def test_basis_fem_simple(self): """ Class SpharaBasis, method basis, mode='fem', simple triangular mesh Determine the SPHARA basis with fem edge weight for a simple triangular mesh, 3 vertices, single triangle. """ testtrimesh = tm.TriMesh([[0, 1, 2]], [[1., 0., 0.], [0., 2., 0.], [0., 0., 3.]]) sb_fem = sb.SpharaBasis(testtrimesh, mode='fem') sb_fem_fun, sb_fem_freq = sb_fem.basis() self.assertTrue( np.allclose(sb_fem_fun, [[0.53452248, -0.49487166, 1.42857143], [0.53452248, -0.98974332, -1.14285714], [0.53452248, 1.48461498, -0.28571429]]) and np.allclose(sb_fem_freq, [2.33627569e-16, 1.71428571e+00, 5.14285714e+00]))
def test_basis_unit_simple(self): """ Class SpharaBasis, method basis, mode='unit', simple triangular mesh Determine the SPHARA basis with unit edge weight for a simple triangular mesh, 3 vertices, single triangle. """ testtrimesh = tm.TriMesh([[0, 1, 2]], [[1, 0, 0], [0, 2, 0], [0, 0, 3]]) sb_unit = sb.SpharaBasis(testtrimesh, mode='unit') sb_unit_fun, sb_unit_freq = sb_unit.basis() # print(sb_unit_freq.shape) self.assertTrue( np.allclose(sb_unit_fun, [[0.57735027, 0.81649658, 0.], [0.57735027, -0.40824829, -0.70710678], [0.57735027, -0.40824829, 0.70710678]]) and np.allclose(sb_unit_freq, [2.22044605e-15, 3.00000000e+00, 3.00000000e+00]))
def test_basis_inveuclid_simple(self): """ Class SpharaBasis, method basis, mode='inv_euclidean', simple triangular mesh Determine the SPHARA basis with inverse euclidean edge weight for a simple triangular mesh, 3 vertices, single triangle. """ testtrimesh = tm.TriMesh([[0, 1, 2]], [[1, 0, 0], [0, 2, 0], [0, 0, 3]]) sb_ie = sb.SpharaBasis(testtrimesh, mode='inv_euclidean') sb_ie_fun, sb_ie_freq = sb_ie.basis() self.assertTrue( np.allclose( sb_ie_fun, [[-0.577350269189626, -0.328082121693334, 0.747682277502862], [-0.577350269189626, -0.483470785430218, -0.657968590665356], [-0.577350269189626, 0.811552907123552, -0.0897136868375066]]) and np.allclose(sb_ie_freq, [0.0, 0.886644827600501, 1.19493809165832]))
axeeg.set_ylim(-3.5, 3.5) axeeg.set_xlim(-50, 130) axeeg.grid(True) plt.show() figeeg.savefig('sep_butterfly.pdf') # ## Create a SpharaPy TriMesh instance # In the next step we create an instance of the class `spharapy.trimesh.TriMesh` using the list of vertices and triangles. # In[9]: # create an instance of the TriMesh class mesh_eeg = tm.TriMesh(trilist, vertlist) # ## SPHARA analysis of EEG data # ### Create a SpharaPy SpharaTransform instance # Afterwards we determine an instance of the class SpharaTransform, which is used to execute the transformation. For the determination of the SPHARA basis we use a Laplace-Beltrami operator, which is discretized by the FEM approach. # In[10]: sphara_transform_fem = st.SpharaTransform(mesh_eeg, 'fem') basis_functions_fem, natural_frequencies_fem = sphara_transform_fem.basis()
# Determining the Laplace-Beltrami Operator # ----------------------------------------- # # In a further step, an instance of the class # :class:`spharapy.trimesh.TriMesh` is created from the lists of # vertices and triangles. The class :class:`spharapy.trimesh.TriMesh` # provides a number of methods to determine certain properties of the # triangle mesh required to generate the SPHARA basis. # print all implemented methods of the TriMesh class print([func for func in dir(tm.TriMesh) if not func.startswith('__')]) ###################################################################### # create an instance of the TriMesh class simple_mesh = tm.TriMesh(trilist, vertlist) ###################################################################### # For the simple triangle mesh an instance of the class SpharaBasis is # created and the finite element discretization ('fem') is used. The # complete set of SPHARA basis functions and the natural frequencies # associated with the basis functions are determined. sphara_basis = sb.SpharaBasis(simple_mesh, 'fem') basis_functions, natural_frequencies = sphara_basis.basis() ###################################################################### # The set of SPHARA basis functions can be used for spatial Fourier # analysis of the spatially irregularly sampled data. # # The first 15 spatially low-frequency SPHARA basis functions are