Ejemplo n.º 1
0
def single_dipole_search(electrode_potential, leadfield, mesh_file, elements_to_consider=[1002]):
    from forward.mesh import read_mesh, get_closest_element_to_point
    from nipype import logging
    iflogger = logging.getLogger('interface')

    geo_file = op.abspath("search_points.geo")
    data_name = "leadfield"
    lf_data_file = h5py.File(leadfield, "r")
    lf_data = lf_data_file.get(data_name)
    leadfield_matrix = lf_data.value
    _, lf_name, _ = split_filename(leadfield)

    bounds = (0,leadfield_matrix.shape[0]/3)
    mesh_data, _, _, _ = read_mesh(mesh_file, elements_to_consider)

    centroids = []
    element_ids = []
    for poly in mesh_data:
        element_ids.append(poly["element_id"])
        centroids.append(poly["centroid"])
    

    p0, bounds = random_initial_guess(centroids)
    #p0 = np.array([0,0,60])

    mw = {}
    args = (leadfield_matrix, electrode_potential, centroids, element_ids)
    mw['args'] = args
    #mw['bounds'] = bounds

    #res = so.basinhopping(calculate_element_cost, p0, T=0.01, stepsize = 3, minimizer_kwargs=mw, disp=True, niter_success=20)

    # Perform downhill search, minimizing cost function
    xopt, fopt, n_iter, funcalls, _, allvecs = so.fmin(calculate_element_cost, p0, ftol=0.00000001, args=(leadfield_matrix, electrode_potential, centroids, element_ids), xtol = 1, disp=True, full_output=True, retall=True)

    write_search_points(allvecs, geo_file) 

    # Need to minimize cost by changing values of orientation and magnitude:
    _, element_idx, centroid, element_data, lf_idx = get_closest_element_to_point(mesh_file, elements_to_consider, np.array([xopt]))

    L = np.transpose(leadfield_matrix[lf_idx * 3:lf_idx * 3 + 3])
    V = electrode_potential
    qopt, _, _, _ = np.linalg.lstsq(L, V)
    return xopt, qopt, element_data, geo_file
Ejemplo n.º 2
0
def rewrite_mesh_from_binary_mask(mask_file,
                                  mesh_file,
                                  mesh_id,
                                  new_phys_id=1015):
    # Takes about 8 minutes
    import numpy as np
    import nibabel as nb
    import os.path as op
    from forward.mesh import read_mesh
    from nipype import logging

    iflogger = logging.getLogger('interface')

    mask_img = nb.load(mask_file)
    mask_data = mask_img.get_data()
    mask_affine = mask_img.get_affine()
    mask_header = mask_img.get_header()
    #tensor_data = np.flipud(tensor_image.get_data())

    # Define various constants
    elements_to_consider = [1002]  #Use only white matter
    vx, vy, vz = mask_header.get_zooms()[0:3]
    max_x, max_y, max_z = np.shape(mask_data)[0:3]
    halfx, halfy, halfz = np.array((vx * max_x, vy * max_y, vz * max_z)) / 2.0

    mesh_data, _, _, _ = read_mesh(mesh_file, elements_to_consider)

    elem_list = []
    for idx, poly in enumerate(mesh_data):
        i = np.round((poly['centroid'][0] + halfx) / vx).astype(int)
        j = np.round((poly['centroid'][1] + halfy) / vy).astype(int)
        k = np.round((poly['centroid'][2] + halfz) / vz).astype(int)
        if mask_data[i, j, k]:
            elem_list.append(poly['element_id'])
        #iflogger.info("%3.3f%%" % (float(idx)/num_polygons*100.0))
    new_elem_id = new_phys_id + 2000
    out_file = swap_element_ids(mesh_file, elem_list, new_elem_id, new_phys_id)
    print('Writing binary masked mesh file to %s' % out_file)
    return out_file
Ejemplo n.º 3
0
def rewrite_mesh_from_binary_mask(mask_file, mesh_file, mesh_id, new_phys_id=1015):
    # Takes about 8 minutes
    import numpy as np
    import nibabel as nb
    import os.path as op
    from forward.mesh import read_mesh
    from nipype import logging

    iflogger = logging.getLogger('interface')

    mask_img = nb.load(mask_file)
    mask_data = mask_img.get_data()
    mask_affine = mask_img.get_affine()
    mask_header = mask_img.get_header()
    #tensor_data = np.flipud(tensor_image.get_data())

    # Define various constants
    elements_to_consider = [1002] #Use only white matter
    vx, vy, vz = mask_header.get_zooms()[0:3]
    max_x, max_y, max_z = np.shape(mask_data)[0:3]
    halfx, halfy, halfz = np.array((vx*max_x, vy*max_y, vz*max_z))/2.0

    mesh_data, _, _, _ = read_mesh(mesh_file, elements_to_consider)

    elem_list = []
    for idx, poly in enumerate(mesh_data):
        i = np.round((poly['centroid'][0]+halfx)/vx).astype(int)
        j = np.round((poly['centroid'][1]+halfy)/vy).astype(int)
        k = np.round((poly['centroid'][2]+halfz)/vz).astype(int)
        if mask_data[i,j,k]:
            elem_list.append(poly['element_id'])
        #iflogger.info("%3.3f%%" % (float(idx)/num_polygons*100.0))
    new_elem_id = new_phys_id+2000
    out_file = swap_element_ids(mesh_file, elem_list, new_elem_id, new_phys_id)
    print('Writing binary masked mesh file to %s' % out_file)
    return out_file
Ejemplo n.º 4
0
def include_gmsh_tensor_elements(mesh_file, tensor_file, mask_file, mask_threshold=0.5, lower_triangular=True):
    import numpy as np
    import nibabel as nb
    from nipype.utils.filemanip import split_filename
    import os.path as op
    from forward.mesh import read_mesh
    from nipype import logging
    import shutil

    iflogger = logging.getLogger("interface")

    # Load 4D (6 volume upper or lower triangular) conductivity tensor image
    tensor_image = nb.load(tensor_file)
    tensor_data = np.flipud(tensor_image.get_data())

    # Correct the tensors after flipping in the X direction
    tensor_data[:, :, :, 1] *= -1
    if lower_triangular:
        tensor_data[:, :, :, 3] *= -1
    else:
        tensor_data[:, :, :, 2] *= -1

    # Load mask (usually fractional anisotropy) image
    mask_image = nb.load(mask_file)
    mask_data = np.flipud(mask_image.get_data())
    header = tensor_image.get_header()

    # Make sure the files share the same (3D) dimensions before continuing
    assert np.shape(tensor_data)[0:3] == np.shape(mask_data)[0:3]

    # Define various constants
    elements_to_consider = [1001]  # Use only white matter
    vx, vy, vz = header.get_zooms()[0:3]
    max_x, max_y, max_z = np.shape(tensor_data)[0:3]
    halfx, halfy, halfz = np.array((vx * max_x, vy * max_y, vz * max_z)) / 2.0

    mesh_data, _, _, _ = read_mesh(mesh_file, elements_to_consider)

    # Create the output mesh file
    path, name, ext = split_filename(mesh_file)
    out_file = op.abspath(name + "_cond.msh")
    iflogger.info("Copying current mesh file to %s" % out_file)
    shutil.copyfile(mesh_file, out_file)

    f = open(out_file, "a")  # Append to the end of the file
    iflogger.info("Appending Conductivity tensors to %s" % out_file)

    # Write the tag information to the file:
    num_polygons = len(mesh_data)
    f.write("$ElementData\n")
    str_tag = '"Conductivity"'
    timestep = 0.0001

    f.write("1\n")  # Num String tags
    f.write(str_tag + "\n")
    f.write("1\n")  # Num Real tags
    f.write("%f\n" % timestep)

    # Three integer tags: timestep, num field components, num elements
    f.write("3\n")  # Three int tags
    f.write("0\n")  # Time step index
    f.write("9\n")  # Num field components

    # Get the centroid of all white matter elements
    # Find out which voxel they lie inside
    iflogger.info("Getting tensor for each element")
    # ipdb.set_trace()
    nonzero = 0
    elem_list = []

    if lower_triangular:
        for idx, poly in enumerate(mesh_data):
            i = np.round((poly["centroid"][0] + halfx) / vx).astype(int)
            j = np.round((poly["centroid"][1] + halfy) / vy).astype(int)
            k = np.round((poly["centroid"][2] + halfz) / vz).astype(int)
            T = tensor_data[i, j, k]
            if not (all(T == 0) and mask_data[i, j, k] >= mask_threshold):
                elementdata_str = "%d %e %e %e %e %e %e %e %e %e\n" % (
                    poly["element_id"],
                    T[0],
                    T[1],
                    T[3],
                    T[1],
                    T[2],
                    T[4],
                    T[3],
                    T[4],
                    T[5],
                )
                elem_list.append(elementdata_str)
                nonzero += 1
            # iflogger.info("%3.3f%%" % (float(idx)/num_polygons*100.0))
    else:
        for idx, poly in enumerate(mesh_data):
            i = np.round((poly["centroid"][0] + halfx) / vx).astype(int)
            j = np.round((poly["centroid"][1] + halfy) / vy).astype(int)
            k = np.round((poly["centroid"][2] + halfz) / vz).astype(int)
            T = tensor_data[i, j, k]
            if not (all(T == 0) and mask_data[i, j, k] >= mask_threshold):
                elementdata_str = "%d %e %e %e %e %e %e %e %e %e\n" % (
                    poly["element_id"],
                    T[0],
                    T[1],
                    T[2],
                    T[1],
                    T[3],
                    T[4],
                    T[2],
                    T[4],
                    T[5],
                )
                elem_list.append(elementdata_str)
                nonzero += 1
            # iflogger.info("%3.3f%%" % (float(idx)/num_polygons*100.0))

    f.write("%d\n" % nonzero)  # Num nonzero field components
    for elementdata_str in elem_list:
        f.write(elementdata_str)

    f.write("$EndElementData\n")

    f.write("$ElementData\n")
    str_tag = '"FA"'
    timestep = 0.0002

    f.write("1\n")  # Num String tags
    f.write(str_tag + "\n")
    f.write("1\n")  # Num Real tags
    f.write("%f\n" % timestep)

    # Three integer tags: timestep, num field components, num elements
    f.write("3\n")  # Three int tags
    f.write("1\n")  # Time step index
    f.write("1\n")  # Num field components

    # Get the centroid of all white matter elements
    # Find out which voxel they lie inside
    iflogger.info("Writing FA for each element")
    # ipdb.set_trace()
    nonzero = 0
    elem_list = []
    for idx, poly in enumerate(mesh_data):
        i = np.round((poly["centroid"][0] + halfx) / vx).astype(int)
        j = np.round((poly["centroid"][1] + halfy) / vy).astype(int)
        k = np.round((poly["centroid"][2] + halfz) / vz).astype(int)
        if mask_data[i, j, k] > 0:
            elementdata_str = "%d %e\n" % (poly["element_id"], mask_data[i, j, k])
            elem_list.append(elementdata_str)
            nonzero += 1
        # iflogger.info("%3.3f%%" % (float(idx)/num_polygons*100.0))

    f.write("%d\n" % nonzero)  # Num nonzero field components
    for elementdata_str in elem_list:
        f.write(elementdata_str)

    f.write("$EndElementData\n")

    f.close()

    iflogger.info("Finished writing to %s" % out_file)
    return out_file
import numpy as np
from forward.mesh import read_mesh
n_electrodes = 42
elem_to_consider = [1000, 1002, 1003, 1004]
elem_to_consider.extend(range(5000, 5000+n_electrodes))
mesh_data, nodes, elem, labels = read_mesh('4shell_elec.msh', elem_to_consider)
np.savetxt('nodes.txt', nodes)
np.savetxt('elem.txt', elem)
np.savetxt('labels.txt', labels)
Ejemplo n.º 6
0
def cost_function_mapping(potential, leadfield, mesh_file, mesh_id):
    import os.path as op
    import numpy as np
    import h5py
    import shutil
    from forward.mesh import read_mesh
    from nipype.utils.filemanip import split_filename
    from nipype import logging
    iflogger = logging.getLogger('interface')

    data_name = "leadfield"
    lf_data_file = h5py.File(leadfield, "r")
    lf_data = lf_data_file.get(data_name)
    leadfield_matrix = lf_data.value
    _, lf_name, _ = split_filename(leadfield)
    V = np.load(potential)


    # ---- Resave the mesh with the cost function as element data ---- #
    mesh_data, _, _, _ = read_mesh(mesh_file, [mesh_id])

    # Create the output mesh file
    path, name, ext = split_filename(mesh_file)
    cost_mesh_file = op.abspath(name + "_cost.msh")

    iflogger.info('Copying current mesh file to %s' % cost_mesh_file)
    shutil.copyfile(mesh_file, cost_mesh_file)

    f = open(cost_mesh_file,'a') #Append to the end of the file
    iflogger.info('Appending cost function scalars to %s' % cost_mesh_file)

    # Write the tag information to the file:
    f.write('$ElementData\n')
    str_tag = '"Cost function %s"' % (leadfield)
    timestep = 0.0001

    f.write('1\n') #Num String tags
    f.write(str_tag + '\n')
    f.write('1\n') #Num Real tags
    f.write('%f\n' % timestep)

    #Three integer tags: timestep, num field components, num elements
    f.write('3\n') #Three int tags
    f.write('0\n') #Time step index
    f.write('1\n') #Num field components
    elem_list = []
    elem_idx_list = []
    cost_list = []

    assert(len(mesh_data)*3 == leadfield_matrix.shape[0])

    for lf_idx, poly in enumerate(mesh_data):
        L = np.transpose(leadfield_matrix[lf_idx * 3:lf_idx * 3 + 3])        
        I = np.eye(len(V))
        Linv = np.linalg.pinv(L)
        val = np.dot(V.T, I - np.dot(L,Linv))
        R = np.dot(val,V)
        cost = np.linalg.norm(R)
        #cost = np.sqrt(R / np.linalg.norm(V))
        cost_list.append(cost)

        elem_idx_list.append(poly["element_id"])

        elementdata_str = ('%d %e\n' % (poly["element_id"], cost))
        elem_list.append(elementdata_str)
        #iflogger.info("%3.3f%%" % (float(lf_idx)/num_polygons*100.0))

    import ipdb
    ipdb.set_trace()
    minidx = cost_list.index(np.min(cost_list))
    maxidx = cost_list.index(np.max(cost_list))
    print(elem_idx_list[minidx], elem_idx_list[maxidx])

    f.write('%d\n' % len(mesh_data)) #Num nonzero field components
    for elementdata_str in elem_list:
        f.write(elementdata_str)

    f.write('$EndElementData\n')
    f.close()

    iflogger.info("Finished writing to %s" % cost_mesh_file)
    cost_geo_file = ""
    return cost_mesh_file, cost_geo_file
Ejemplo n.º 7
0
def cost_function_mapping(potential, leadfield, mesh_file, mesh_id):
    import os.path as op
    import numpy as np
    import h5py
    import shutil
    from forward.mesh import read_mesh
    from nipype.utils.filemanip import split_filename
    from nipype import logging
    iflogger = logging.getLogger('interface')

    data_name = "leadfield"
    lf_data_file = h5py.File(leadfield, "r")
    lf_data = lf_data_file.get(data_name)
    leadfield_matrix = lf_data.value
    _, lf_name, _ = split_filename(leadfield)
    V = np.load(potential)

    # ---- Resave the mesh with the cost function as element data ---- #
    mesh_data, _, _, _ = read_mesh(mesh_file, [mesh_id])

    # Create the output mesh file
    path, name, ext = split_filename(mesh_file)
    cost_mesh_file = op.abspath(name + "_cost.msh")

    iflogger.info('Copying current mesh file to %s' % cost_mesh_file)
    shutil.copyfile(mesh_file, cost_mesh_file)

    f = open(cost_mesh_file, 'a')  #Append to the end of the file
    iflogger.info('Appending cost function scalars to %s' % cost_mesh_file)

    # Write the tag information to the file:
    f.write('$ElementData\n')
    str_tag = '"Cost function %s"' % (leadfield)
    timestep = 0.0001

    f.write('1\n')  #Num String tags
    f.write(str_tag + '\n')
    f.write('1\n')  #Num Real tags
    f.write('%f\n' % timestep)

    #Three integer tags: timestep, num field components, num elements
    f.write('3\n')  #Three int tags
    f.write('0\n')  #Time step index
    f.write('1\n')  #Num field components
    elem_list = []
    elem_idx_list = []
    cost_list = []

    assert (len(mesh_data) * 3 == leadfield_matrix.shape[0])

    for lf_idx, poly in enumerate(mesh_data):
        L = np.transpose(leadfield_matrix[lf_idx * 3:lf_idx * 3 + 3])
        I = np.eye(len(V))
        Linv = np.linalg.pinv(L)
        val = np.dot(V.T, I - np.dot(L, Linv))
        R = np.dot(val, V)
        cost = np.linalg.norm(R)
        #cost = np.sqrt(R / np.linalg.norm(V))
        cost_list.append(cost)

        elem_idx_list.append(poly["element_id"])

        elementdata_str = ('%d %e\n' % (poly["element_id"], cost))
        elem_list.append(elementdata_str)
        #iflogger.info("%3.3f%%" % (float(lf_idx)/num_polygons*100.0))

    import ipdb
    ipdb.set_trace()
    minidx = cost_list.index(np.min(cost_list))
    maxidx = cost_list.index(np.max(cost_list))
    print(elem_idx_list[minidx], elem_idx_list[maxidx])

    f.write('%d\n' % len(mesh_data))  #Num nonzero field components
    for elementdata_str in elem_list:
        f.write(elementdata_str)

    f.write('$EndElementData\n')
    f.close()

    iflogger.info("Finished writing to %s" % cost_mesh_file)
    cost_geo_file = ""
    return cost_mesh_file, cost_geo_file
Ejemplo n.º 8
0
import numpy as np
from forward.mesh import read_mesh
n_electrodes = 42
elem_to_consider = [1000, 1002, 1003, 1004]
elem_to_consider.extend(range(5000, 5000 + n_electrodes))
mesh_data, nodes, elem, labels = read_mesh('4shell_elec.msh', elem_to_consider)
np.savetxt('nodes.txt', nodes)
np.savetxt('elem.txt', elem)
np.savetxt('labels.txt', labels)
Ejemplo n.º 9
0
def compare_leadfields(leadfield1, leadfield2, mesh_file, write_mesh=True):
    '''
    Compares two leadfield matrices and outputs the difference as
    scalars attached to a mesh file. The mesh file must have the 
    same number of elements as the leadfield's second dimension

    FEM reciprocity leadfield is M x N where M is the number of sensors
    and N is the number of elements. Mesh file must have N elements.

    e.g. isotropic white matter conductivity
    vs. anisotropic conductivity from estimated diffusion tensors
    '''
    import os.path as op
    import h5py
    import numpy as np
    import shutil
    
    from forward.mesh import read_mesh

    from nipype.utils.filemanip import split_filename

    from nipype import logging    
    iflogger = logging.getLogger('interface')

    data_name = "leadfield"

    print("Reading leadfield 1: %s" % leadfield1)
    lf1_data_file = h5py.File(leadfield1, "r")
    lf1_data = lf1_data_file.get(data_name)
    leadfield_matrix1 = lf1_data.value

    print("Reading leadfield 2: %s" % leadfield2)
    lf2_data_file = h5py.File(leadfield2, "r")
    lf2_data = lf2_data_file.get(data_name)
    leadfield_matrix2 = lf2_data.value


    path, name, ext = split_filename(mesh_file)

    if write_mesh:
        # Electric field elements are only saved in the gray matter
        #elements_to_consider = [1001] #For Sphere
        elements_to_consider = [1002] #For head models
        mesh_data, _, _, _ = read_mesh(mesh_file, elements_to_consider)
        # Create the output mesh file
        rms_mesh_file = op.abspath(name + "_rmse.msh")
        iflogger.info('Copying current mesh file to %s' % rms_mesh_file)
        shutil.copyfile(mesh_file, rms_mesh_file)
        f = open(rms_mesh_file,'a') #Append to the end of the file
        iflogger.info('Appending root mean squared error scalars to %s' % rms_mesh_file)
    else:
        rms_mesh_file = None

    out_rms_hdf5_file_x = op.abspath(name + "_rmse_x.hdf5")
    out_rms_hdf5_file_y = op.abspath(name + "_rmse_y.hdf5")
    out_rms_hdf5_file_z = op.abspath(name + "_rmse_z.hdf5")
    out_rms_hdf5_file_avg = op.abspath(name + "_rmse_avg.hdf5")

    rms_hdf5_file_x = h5py.File(out_rms_hdf5_file_x, "w")
    rms_hdf5_file_y = h5py.File(out_rms_hdf5_file_y, "w")
    rms_hdf5_file_z = h5py.File(out_rms_hdf5_file_z, "w")
    rms_hdf5_file_avg = h5py.File(out_rms_hdf5_file_avg, "w")


    # Write the tag information to the file:
    if write_mesh:
        num_polygons = len(mesh_data)
    _, name1, _ = split_filename(leadfield1)
    _, name2, _ = split_filename(leadfield2)

    #For testing
    #noise = np.random.normal(0,1,leadfield_matrix2.shape)
    #leadfield_matrix2 = leadfield_matrix2 + noise

    # Reshape the leadfields so they are M x 3 x N vectors (x, y, z direction of electric field)
    leadfield_mesh1 = np.reshape(leadfield_matrix1, (leadfield_matrix1.shape[0]/3,3,leadfield_matrix1.shape[1]))
    leadfield_mesh2 = np.reshape(leadfield_matrix2, (leadfield_matrix2.shape[0]/3,3,leadfield_matrix2.shape[1]))

    #Check that the dimensions are appropriate
    try:
        if write_mesh:
            assert(len(mesh_data) == leadfield_mesh1.shape[0] == leadfield_mesh2.shape[0])
        else:
            assert(leadfield_mesh1.shape[0] == leadfield_mesh2.shape[0])
    except AssertionError:
        iflogger.error("Lead fields could not be compared because the " \
            "number of elements in the files do not match")
        if write_mesh:
            iflogger.error("Elements in %s: %d" % (mesh_file, len(mesh_data)))
        iflogger.error("Elements in leadfield 1 %s: %d" % (leadfield1, leadfield_mesh1.shape[0]))
        iflogger.error("Elements in leadfield 2 %s: %d" % (leadfield2, leadfield_mesh2.shape[0]))
        raise Exception

    # Get the mean squared difference between electric field vectors by sensor and element
    diff = leadfield_mesh2 - leadfield_mesh1

    # Gets the norm of the difference for X, Y, and Z directions
    norm_x_diff = np.linalg.norm(diff[:,0,:],axis=1)
    norm_y_diff = np.linalg.norm(diff[:,1,:],axis=1)
    norm_z_diff = np.linalg.norm(diff[:,2,:],axis=1)

    norm_lf1_x = np.linalg.norm(leadfield_mesh1[:,0,:], axis=1)
    norm_lf1_y = np.linalg.norm(leadfield_mesh1[:,1,:], axis=1)
    norm_lf1_z = np.linalg.norm(leadfield_mesh1[:,2,:], axis=1)

    rmse_x = norm_x_diff / norm_lf1_x
    rmse_y = norm_y_diff / norm_lf1_y
    rmse_z = norm_z_diff / norm_lf1_z

    rmse = (rmse_x + rmse_y + rmse_z) / 3.
    assert(leadfield_mesh2.shape[0] == rmse.shape[0])

    if write_mesh:
        rmse_avg_list = []
        rmse_x_list = []
        rmse_y_list = []
        rmse_z_list = []
        for idx, poly in enumerate(mesh_data):
            rmse_avg_str = ('%d %e \n' % (poly["element_id"], rmse[idx]))
            rmse_avg_list.append(rmse_avg_str)
            rmse_x_str = ('%d %e \n' % (poly["element_id"], rmse_x[idx]))
            rmse_x_list.append(rmse_x_str)
            rmse_y_str = ('%d %e \n' % (poly["element_id"], rmse_y[idx]))
            rmse_y_list.append(rmse_y_str)
            rmse_z_str  = ('%d %e \n' % (poly["element_id"], rmse_z[idx]))        
            rmse_z_list.append(rmse_z_str)
            iflogger.info("%3.3f%%" % (float(idx)/num_polygons*100.0))


        # ----- Average RMSE ----- #
        f.write('$ElementData\n')
        str_tag = '"Average Root Mean Squared Error"'
        timestep = 0.0001
        f.write('1\n') #Num String tags
        f.write(str_tag + '\n')
        f.write('1\n') #Num Real tags
        f.write('%f\n' % timestep)
        #Three integer tags: timestep, num field components, num elements
        f.write('3\n') #Three int tags
        f.write('0\n') #Time step index
        f.write('1\n') #Num field components
        f.write('%d\n' % len(mesh_data)) #Num nonzero field components
        for elementdata_str in rmse_avg_list:
            f.write(elementdata_str)
        f.write('$EndElementData\n')


        # ----- RMSE X ----- #
        f.write('$ElementData\n')
        str_tag = '"Root Mean Squared Error X-direction"'
        timestep = 0.0002
        f.write('1\n') #Num String tags
        f.write(str_tag + '\n')
        f.write('1\n') #Num Real tags
        f.write('%f\n' % timestep)
        #Three integer tags: timestep, num field components, num elements
        f.write('3\n') #Three int tags
        f.write('0\n') #Time step index
        f.write('1\n') #Num field components
        f.write('%d\n' % len(mesh_data)) #Num nonzero field components
        for elementdata_str in rmse_x_list:
            f.write(elementdata_str)
        f.write('$EndElementData\n')

        # ----- RMSE X ----- #
        f.write('$ElementData\n')
        str_tag = '"Root Mean Squared Error Y-direction"'
        timestep = 0.0003
        f.write('1\n') #Num String tags
        f.write(str_tag + '\n')
        f.write('1\n') #Num Real tags
        f.write('%f\n' % timestep)
        #Three integer tags: timestep, num field components, num elements
        f.write('3\n') #Three int tags
        f.write('0\n') #Time step index
        f.write('1\n') #Num field components
        f.write('%d\n' % len(mesh_data)) #Num nonzero field components
        for elementdata_str in rmse_y_list:
            f.write(elementdata_str)
        f.write('$EndElementData\n')

        # ----- RMSE X ----- #
        f.write('$ElementData\n')
        str_tag = '"Root Mean Squared Error Z-direction"'
        timestep = 0.0004
        f.write('1\n') #Num String tags
        f.write(str_tag + '\n')
        f.write('1\n') #Num Real tags
        f.write('%f\n' % timestep)
        #Three integer tags: timestep, num field components, num elements
        f.write('3\n') #Three int tags
        f.write('0\n') #Time step index
        f.write('1\n') #Num field components
        f.write('%d\n' % len(mesh_data)) #Num nonzero field components
        for elementdata_str in rmse_z_list:
            f.write(elementdata_str)
        f.write('$EndElementData\n')

        f.close()

        iflogger.info("Finished writing to %s" % rms_mesh_file)

    ## Save RMSE data to an HDF5 file
    dset_x = rms_hdf5_file_x.create_dataset("rmse_x", data=rmse_x)
    dset_x[...] = rmse_x
    dset_y = rms_hdf5_file_y.create_dataset("rmse_y", data=rmse_y)
    dset_y[...] = rmse_y
    dset_z = rms_hdf5_file_z.create_dataset("rmse_z", data=rmse_z)
    dset_z[...] = rmse_z
    dset = rms_hdf5_file_avg.create_dataset("rmse_avg", data=rmse)
    dset[...] = rmse

    rms_hdf5_file_x.close()
    rms_hdf5_file_y.close()
    rms_hdf5_file_z.close()
    rms_hdf5_file_avg.close()
    print("Saved RMSE-X matrix as %s" % out_rms_hdf5_file_x)
    print("Saved RMSE-Y matrix as %s" % out_rms_hdf5_file_y)
    print("Saved RMSE-Z matrix as %s" % out_rms_hdf5_file_z)
    print("Saved RMSE-Avg matrix as %s" % out_rms_hdf5_file_avg)
    ###
    return rms_mesh_file, out_rms_hdf5_file_avg, out_rms_hdf5_file_x, out_rms_hdf5_file_y, out_rms_hdf5_file_z
Ejemplo n.º 10
0
def compare_leadfields(leadfield1, leadfield2, mesh_file, write_mesh=True):
    """
    Compares two leadfield matrices and outputs the difference as
    scalars attached to a mesh file. The mesh file must have the 
    same number of elements as the leadfield's second dimension

    FEM reciprocity leadfield is M x N where M is the number of sensors
    and N is the number of elements. Mesh file must have N elements.

    e.g. isotropic white matter conductivity
    vs. anisotropic conductivity from estimated diffusion tensors
    """
    import os.path as op
    import h5py
    import numpy as np
    import shutil

    from forward.mesh import read_mesh

    from nipype.utils.filemanip import split_filename

    from nipype import logging

    iflogger = logging.getLogger("interface")

    data_name = "leadfield"

    print("Reading leadfield 1: %s" % leadfield1)
    lf1_data_file = h5py.File(leadfield1, "r")
    lf1_data = lf1_data_file.get(data_name)
    leadfield_matrix1 = lf1_data.value

    print("Reading leadfield 2: %s" % leadfield2)
    lf2_data_file = h5py.File(leadfield2, "r")
    lf2_data = lf2_data_file.get(data_name)
    leadfield_matrix2 = lf2_data.value

    path, name, ext = split_filename(mesh_file)

    if write_mesh:
        # Electric field elements are only saved in the gray matter
        # elements_to_consider = [1001] #For Sphere
        elements_to_consider = [1002]  # For head models
        mesh_data, _, _, _ = read_mesh(mesh_file, elements_to_consider)
        # Create the output mesh file
        rms_mesh_file = op.abspath(name + "_rmse.msh")
        iflogger.info("Copying current mesh file to %s" % rms_mesh_file)
        shutil.copyfile(mesh_file, rms_mesh_file)
        f = open(rms_mesh_file, "a")  # Append to the end of the file
        iflogger.info("Appending root mean squared error scalars to %s" % rms_mesh_file)
    else:
        rms_mesh_file = None

    out_rms_hdf5_file_x = op.abspath(name + "_rmse_x.hdf5")
    out_rms_hdf5_file_y = op.abspath(name + "_rmse_y.hdf5")
    out_rms_hdf5_file_z = op.abspath(name + "_rmse_z.hdf5")
    out_rms_hdf5_file_avg = op.abspath(name + "_rmse_avg.hdf5")

    rms_hdf5_file_x = h5py.File(out_rms_hdf5_file_x, "w")
    rms_hdf5_file_y = h5py.File(out_rms_hdf5_file_y, "w")
    rms_hdf5_file_z = h5py.File(out_rms_hdf5_file_z, "w")
    rms_hdf5_file_avg = h5py.File(out_rms_hdf5_file_avg, "w")

    # Write the tag information to the file:
    if write_mesh:
        num_polygons = len(mesh_data)
    _, name1, _ = split_filename(leadfield1)
    _, name2, _ = split_filename(leadfield2)

    # For testing
    # noise = np.random.normal(0,1,leadfield_matrix2.shape)
    # leadfield_matrix2 = leadfield_matrix2 + noise

    # Reshape the leadfields so they are M x 3 x N vectors (x, y, z direction of electric field)
    leadfield_mesh1 = np.reshape(leadfield_matrix1, (leadfield_matrix1.shape[0] / 3, 3, leadfield_matrix1.shape[1]))
    leadfield_mesh2 = np.reshape(leadfield_matrix2, (leadfield_matrix2.shape[0] / 3, 3, leadfield_matrix2.shape[1]))

    # Check that the dimensions are appropriate
    try:
        if write_mesh:
            assert len(mesh_data) == leadfield_mesh1.shape[0] == leadfield_mesh2.shape[0]
        else:
            assert leadfield_mesh1.shape[0] == leadfield_mesh2.shape[0]
    except AssertionError:
        iflogger.error("Lead fields could not be compared because the " "number of elements in the files do not match")
        if write_mesh:
            iflogger.error("Elements in %s: %d" % (mesh_file, len(mesh_data)))
        iflogger.error("Elements in leadfield 1 %s: %d" % (leadfield1, leadfield_mesh1.shape[0]))
        iflogger.error("Elements in leadfield 2 %s: %d" % (leadfield2, leadfield_mesh2.shape[0]))
        raise Exception

    # Get the mean squared difference between electric field vectors by sensor and element
    diff = leadfield_mesh2 - leadfield_mesh1

    # Gets the norm of the difference for X, Y, and Z directions
    norm_x_diff = np.linalg.norm(diff[:, 0, :], axis=1)
    norm_y_diff = np.linalg.norm(diff[:, 1, :], axis=1)
    norm_z_diff = np.linalg.norm(diff[:, 2, :], axis=1)

    norm_lf1_x = np.linalg.norm(leadfield_mesh1[:, 0, :], axis=1)
    norm_lf1_y = np.linalg.norm(leadfield_mesh1[:, 1, :], axis=1)
    norm_lf1_z = np.linalg.norm(leadfield_mesh1[:, 2, :], axis=1)

    rmse_x = norm_x_diff / norm_lf1_x
    rmse_y = norm_y_diff / norm_lf1_y
    rmse_z = norm_z_diff / norm_lf1_z

    rmse = (rmse_x + rmse_y + rmse_z) / 3.0
    assert leadfield_mesh2.shape[0] == rmse.shape[0]

    if write_mesh:
        rmse_avg_list = []
        rmse_x_list = []
        rmse_y_list = []
        rmse_z_list = []
        for idx, poly in enumerate(mesh_data):
            rmse_avg_str = "%d %e \n" % (poly["element_id"], rmse[idx])
            rmse_avg_list.append(rmse_avg_str)
            rmse_x_str = "%d %e \n" % (poly["element_id"], rmse_x[idx])
            rmse_x_list.append(rmse_x_str)
            rmse_y_str = "%d %e \n" % (poly["element_id"], rmse_y[idx])
            rmse_y_list.append(rmse_y_str)
            rmse_z_str = "%d %e \n" % (poly["element_id"], rmse_z[idx])
            rmse_z_list.append(rmse_z_str)
            iflogger.info("%3.3f%%" % (float(idx) / num_polygons * 100.0))

        # ----- Average RMSE ----- #
        f.write("$ElementData\n")
        str_tag = '"Average Root Mean Squared Error"'
        timestep = 0.0001
        f.write("1\n")  # Num String tags
        f.write(str_tag + "\n")
        f.write("1\n")  # Num Real tags
        f.write("%f\n" % timestep)
        # Three integer tags: timestep, num field components, num elements
        f.write("3\n")  # Three int tags
        f.write("0\n")  # Time step index
        f.write("1\n")  # Num field components
        f.write("%d\n" % len(mesh_data))  # Num nonzero field components
        for elementdata_str in rmse_avg_list:
            f.write(elementdata_str)
        f.write("$EndElementData\n")

        # ----- RMSE X ----- #
        f.write("$ElementData\n")
        str_tag = '"Root Mean Squared Error X-direction"'
        timestep = 0.0002
        f.write("1\n")  # Num String tags
        f.write(str_tag + "\n")
        f.write("1\n")  # Num Real tags
        f.write("%f\n" % timestep)
        # Three integer tags: timestep, num field components, num elements
        f.write("3\n")  # Three int tags
        f.write("0\n")  # Time step index
        f.write("1\n")  # Num field components
        f.write("%d\n" % len(mesh_data))  # Num nonzero field components
        for elementdata_str in rmse_x_list:
            f.write(elementdata_str)
        f.write("$EndElementData\n")

        # ----- RMSE X ----- #
        f.write("$ElementData\n")
        str_tag = '"Root Mean Squared Error Y-direction"'
        timestep = 0.0003
        f.write("1\n")  # Num String tags
        f.write(str_tag + "\n")
        f.write("1\n")  # Num Real tags
        f.write("%f\n" % timestep)
        # Three integer tags: timestep, num field components, num elements
        f.write("3\n")  # Three int tags
        f.write("0\n")  # Time step index
        f.write("1\n")  # Num field components
        f.write("%d\n" % len(mesh_data))  # Num nonzero field components
        for elementdata_str in rmse_y_list:
            f.write(elementdata_str)
        f.write("$EndElementData\n")

        # ----- RMSE X ----- #
        f.write("$ElementData\n")
        str_tag = '"Root Mean Squared Error Z-direction"'
        timestep = 0.0004
        f.write("1\n")  # Num String tags
        f.write(str_tag + "\n")
        f.write("1\n")  # Num Real tags
        f.write("%f\n" % timestep)
        # Three integer tags: timestep, num field components, num elements
        f.write("3\n")  # Three int tags
        f.write("0\n")  # Time step index
        f.write("1\n")  # Num field components
        f.write("%d\n" % len(mesh_data))  # Num nonzero field components
        for elementdata_str in rmse_z_list:
            f.write(elementdata_str)
        f.write("$EndElementData\n")

        f.close()

        iflogger.info("Finished writing to %s" % rms_mesh_file)

    ## Save RMSE data to an HDF5 file
    dset_x = rms_hdf5_file_x.create_dataset("rmse_x", data=rmse_x)
    dset_x[...] = rmse_x
    dset_y = rms_hdf5_file_y.create_dataset("rmse_y", data=rmse_y)
    dset_y[...] = rmse_y
    dset_z = rms_hdf5_file_z.create_dataset("rmse_z", data=rmse_z)
    dset_z[...] = rmse_z
    dset = rms_hdf5_file_avg.create_dataset("rmse_avg", data=rmse)
    dset[...] = rmse

    rms_hdf5_file_x.close()
    rms_hdf5_file_y.close()
    rms_hdf5_file_z.close()
    rms_hdf5_file_avg.close()
    print("Saved RMSE-X matrix as %s" % out_rms_hdf5_file_x)
    print("Saved RMSE-Y matrix as %s" % out_rms_hdf5_file_y)
    print("Saved RMSE-Z matrix as %s" % out_rms_hdf5_file_z)
    print("Saved RMSE-Avg matrix as %s" % out_rms_hdf5_file_avg)
    ###
    return rms_mesh_file, out_rms_hdf5_file_avg, out_rms_hdf5_file_x, out_rms_hdf5_file_y, out_rms_hdf5_file_z
Ejemplo n.º 11
0
def include_gmsh_tensor_elements(mesh_file,
                                 tensor_file,
                                 mask_file,
                                 mask_threshold=0.5,
                                 lower_triangular=True):
    import numpy as np
    import nibabel as nb
    from nipype.utils.filemanip import split_filename
    import os.path as op
    from forward.mesh import read_mesh
    from nipype import logging
    import shutil
    iflogger = logging.getLogger('interface')

    # Load 4D (6 volume upper or lower triangular) conductivity tensor image
    tensor_image = nb.load(tensor_file)
    tensor_data = np.flipud(tensor_image.get_data())

    # Correct the tensors after flipping in the X direction
    tensor_data[:, :, :, 1] *= -1
    if lower_triangular:
        tensor_data[:, :, :, 3] *= -1
    else:
        tensor_data[:, :, :, 2] *= -1

    # Load mask (usually fractional anisotropy) image
    mask_image = nb.load(mask_file)
    mask_data = np.flipud(mask_image.get_data())
    header = tensor_image.get_header()

    # Make sure the files share the same (3D) dimensions before continuing
    assert (np.shape(tensor_data)[0:3] == np.shape(mask_data)[0:3])

    # Define various constants
    elements_to_consider = [1001]  #Use only white matter
    vx, vy, vz = header.get_zooms()[0:3]
    max_x, max_y, max_z = np.shape(tensor_data)[0:3]
    halfx, halfy, halfz = np.array((vx * max_x, vy * max_y, vz * max_z)) / 2.0

    mesh_data, _, _, _ = read_mesh(mesh_file, elements_to_consider)

    # Create the output mesh file
    path, name, ext = split_filename(mesh_file)
    out_file = op.abspath(name + "_cond.msh")
    iflogger.info('Copying current mesh file to %s' % out_file)
    shutil.copyfile(mesh_file, out_file)

    f = open(out_file, 'a')  #Append to the end of the file
    iflogger.info('Appending Conductivity tensors to %s' % out_file)

    # Write the tag information to the file:
    num_polygons = len(mesh_data)
    f.write('$ElementData\n')
    str_tag = '"Conductivity"'
    timestep = 0.0001

    f.write('1\n')  #Num String tags
    f.write(str_tag + '\n')
    f.write('1\n')  #Num Real tags
    f.write('%f\n' % timestep)

    #Three integer tags: timestep, num field components, num elements
    f.write('3\n')  #Three int tags
    f.write('0\n')  #Time step index
    f.write('9\n')  #Num field components

    # Get the centroid of all white matter elements
    # Find out which voxel they lie inside
    iflogger.info("Getting tensor for each element")
    #ipdb.set_trace()
    nonzero = 0
    elem_list = []

    if lower_triangular:
        for idx, poly in enumerate(mesh_data):
            i = np.round((poly['centroid'][0] + halfx) / vx).astype(int)
            j = np.round((poly['centroid'][1] + halfy) / vy).astype(int)
            k = np.round((poly['centroid'][2] + halfz) / vz).astype(int)
            T = tensor_data[i, j, k]
            if not (all(T == 0) and mask_data[i, j, k] >= mask_threshold):
                elementdata_str = ('%d %e %e %e %e %e %e %e %e %e\n' %
                                   (poly["element_id"], T[0], T[1], T[3], T[1],
                                    T[2], T[4], T[3], T[4], T[5]))
                elem_list.append(elementdata_str)
                nonzero += 1
            #iflogger.info("%3.3f%%" % (float(idx)/num_polygons*100.0))
    else:
        for idx, poly in enumerate(mesh_data):
            i = np.round((poly['centroid'][0] + halfx) / vx).astype(int)
            j = np.round((poly['centroid'][1] + halfy) / vy).astype(int)
            k = np.round((poly['centroid'][2] + halfz) / vz).astype(int)
            T = tensor_data[i, j, k]
            if not (all(T == 0) and mask_data[i, j, k] >= mask_threshold):
                elementdata_str = ('%d %e %e %e %e %e %e %e %e %e\n' %
                                   (poly["element_id"], T[0], T[1], T[2], T[1],
                                    T[3], T[4], T[2], T[4], T[5]))
                elem_list.append(elementdata_str)
                nonzero += 1
            #iflogger.info("%3.3f%%" % (float(idx)/num_polygons*100.0))

    f.write('%d\n' % nonzero)  #Num nonzero field components
    for elementdata_str in elem_list:
        f.write(elementdata_str)

    f.write('$EndElementData\n')

    f.write('$ElementData\n')
    str_tag = '"FA"'
    timestep = 0.0002

    f.write('1\n')  #Num String tags
    f.write(str_tag + '\n')
    f.write('1\n')  #Num Real tags
    f.write('%f\n' % timestep)

    #Three integer tags: timestep, num field components, num elements
    f.write('3\n')  #Three int tags
    f.write('1\n')  #Time step index
    f.write('1\n')  #Num field components

    # Get the centroid of all white matter elements
    # Find out which voxel they lie inside
    iflogger.info("Writing FA for each element")
    #ipdb.set_trace()
    nonzero = 0
    elem_list = []
    for idx, poly in enumerate(mesh_data):
        i = np.round((poly['centroid'][0] + halfx) / vx).astype(int)
        j = np.round((poly['centroid'][1] + halfy) / vy).astype(int)
        k = np.round((poly['centroid'][2] + halfz) / vz).astype(int)
        if mask_data[i, j, k] > 0:
            elementdata_str = ('%d %e\n' %
                               (poly["element_id"], mask_data[i, j, k]))
            elem_list.append(elementdata_str)
            nonzero += 1
        #iflogger.info("%3.3f%%" % (float(idx)/num_polygons*100.0))

    f.write('%d\n' % nonzero)  #Num nonzero field components
    for elementdata_str in elem_list:
        f.write(elementdata_str)

    f.write('$EndElementData\n')

    f.close()

    iflogger.info("Finished writing to %s" % out_file)
    return out_file