Exemple #1
0
def main():

    args = docopt(__doc__)

    vol_file = args['<vol>']
    fem_file = args['<FEM>']
    out = args['<out>']

    # First load in the image file
    img = nib.load(vol_file)

    tet_entity = guess_entity(fem_file, 3, 2)
    gm_entity = guess_entity(fem_file, 2, 2)
    wm_entity = guess_entity(fem_file, 2, 1)

    tn_tag, tn_coord, _ = gl.load_gmsh_nodes(fem_file, tet_entity)
    te_tag, _, te_param = gl.load_gmsh_elems(fem_file, tet_entity)
    gmn_tag, gmn_coord, _ = gl.load_gmsh_nodes(fem_file, gm_entity)
    wmn_tag, wmn_coord, _ = gl.load_gmsh_nodes(fem_file, wm_entity)

    #Pull ribbon data
    ribbon = img.get_data()
    affine = img.affine
    x, y, z = np.where(ribbon > 0)

    #Formulate lists as arrays
    tn_tag = np.array(tn_tag)
    gmn_tag = np.array(gmn_tag)
    wmn_tag = np.array(wmn_tag)

    #Set up inputs
    tn_list = te_param[0].reshape((-1, 4))

    #First concatenate nodes
    min_t, max_t, len_t = np.min(tn_tag), np.max(tn_tag), np.size(tn_tag)
    min_g, max_g, len_g = np.min(gmn_tag), np.max(gmn_tag), np.size(gmn_tag)
    min_w, max_w, len_w = np.min(wmn_tag), np.max(wmn_tag), np.size(wmn_tag)

    #Wrap up features
    prop_arr = np.array([[min_t, max_t, len_t], [min_g, max_g, len_g],
                         [min_w, max_w, len_w]])

    #Map nodes to contiguous indexing
    node_list = tp.map_nodes(tn_list, prop_arr)

    #Coordinate array matching indexing
    coord_arr = np.concatenate((tn_coord, gmn_coord, wmn_coord))
    coords = coord_arr.reshape((-1, 3))

    #Determine whether the file is parcellation-based (integer encoded) or weight-based
    float_encoding = np.any(np.mod(ribbon, 1))

    #Project
    if not float_encoding:
        n_out_arr = tp.tetrahedral_parcel_projection(node_list, coord_arr,
                                                     ribbon, affine)
    else:
        n_out_arr = tp.tetrahedral_weight_projection(node_list, coord_arr,
                                                     ribbon, affine)
    np.save(out, n_out_arr)
Exemple #2
0
def load_surf_trigs(f_msh, entities):
    '''
    surf:       Path to gmsh MSH file
    entities:   List of entities to attempt of form (dim, tag)
    '''

    for dim, tag in entities:

        try:
            _, _, trigs = gl.load_gmsh_elems(f_msh, (dim, tag))
        except ValueError:
            continue
        else:
            return trigs.reshape(-1, 3)

    logging.error("Could not properly load Mesh! Check entity tags!")
    raise ValueError
Exemple #3
0
def main():

    arguments = docopt(__doc__)

    msh_file = arguments['<msh>']
    centroid_file = arguments['<centroid>']
    out = arguments['<out_prefix>']
    radius = arguments['--radius'] or 25
    distance = arguments['--distance'] or 1

    #Try every alternative of SURF_HEAD
    n_tag, n_coord, tri = None, None, None
    for i, s in enumerate(SURF_HEAD):
        try:
            n_tag, n_coord, _ = gl.load_gmsh_nodes(msh_file, s)
            _, _, tri = gl.load_gmsh_elems(msh_file, s)
        except ValueError:
            if i == len(SURF_HEAD):
                raise
            else:
                continue
        else:
            break

    tri = tri[0]
    tri = tri.reshape((len(tri) // 3, -1))

    #Load in centroid voxel
    centroid = np.genfromtxt(centroid_file)

    #Get minimum euclidean distance
    eudist = np.linalg.norm(n_coord - centroid, axis=1)
    min_ind = np.argmin(eudist)

    #Capture nodes within spherical ROI
    head_centroid_to_all = np.linalg.norm(n_coord - n_coord[min_ind], axis=1)
    search_inds = np.where(head_centroid_to_all < radius)

    #Get relevant triangles to vertices
    vert_list = n_tag[search_inds]
    vert_coords = n_coord[search_inds]
    t_arr = gl.get_relevant_triangles(vert_list, tri)
    rel_ind = np.where(t_arr > 0)
    t_rel = tri[rel_ind[0], :]

    #Get triangle to index mapping
    u_val = np.unique(t_rel)
    u_ind = np.arange(0, u_val.shape[0])

    #Map each triangle to its index
    sort_map = {v: i for v, i in zip(u_val, u_ind)}
    map_func = np.vectorize(lambda x: sort_map[x])
    mapped_trigs = map_func(t_rel)
    rel_verts = np.where(np.isin(n_tag, u_val))
    rel_verts_coords = n_coord[rel_verts, :][0]

    #Compute vertex normals
    norm_arr = gl.get_vert_norms(mapped_trigs, rel_verts_coords)

    #Dilate
    v_norm = np.mean(norm_arr, axis=0)
    dil_coords = vert_coords + distance * v_norm

    #Write dilated vertices and mean normal to file
    np.save(out + "_dilated_coords.npy", dil_coords)
    np.save(out + "_mean_norm.npy", v_norm)

    #Generate param surf
    dil_faces_ind = gl.get_subset_triangles(vert_list, t_rel)
    dil_faces = t_rel[np.where(dil_faces_ind)].flatten(
        order='C') + vert_list.max()
    dil_faces = list(dil_faces)
    dil_verts = vert_list + vert_list.max()
    dil_coords = dil_coords.flatten()
    gmsh.initialize()
    gmsh.model.add('param_surf')
    tag = gmsh.model.addDiscreteEntity(2, 2001)
    gmsh.model.mesh.setNodes(2, tag, nodeTags=dil_verts, coord=dil_coords)
    gmsh.model.mesh.setElements(
        2,
        tag, [2],
        elementTags=[range(1,
                           len(dil_faces) // 3 + 1)],
        nodeTags=[dil_faces])
    gmsh.write(out + "_param_surf.msh")
    gmsh.finalize()
Exemple #4
0
    def __init__(self,
                 mesh_file,
                 initial_centroid,
                 tet_weights,
                 field_dir,
                 coil,
                 span=35,
                 local_span=8,
                 distance=1,
                 didt=1e6,
                 cpus=1,
                 solver_options=None):
        '''
        Standard constructor
        Arguments:
            mesh_file                   Path to FEM model
            initial_centroid            Initial point to grow sampling region
            tet_weights                 Weighting scores for each tetrahedron
                                        (1D array ordered by node ID)
            field_dir                   Directory to perform simulation
                                        experiments in
            coil                        TMS coil file (either dA/dt volume or
                                        coil geometry)
            span                        Radius of points to include in
                                        sampling surface
            local_span                  Radius of points to include in
                                        construction of local geometry
                                        for normal and curvature estimation
            distance                    Distance from coil to head surface
            didt                        Intensity of stimulation
            cpus                        Number of cpus to use for simulation
        '''

        self.mesh = mesh_file
        self.tw = tet_weights
        self.field_dir = field_dir
        self.coil = coil
        self.didt = didt

        logger.info(f"Configured to use {cpus} cpus...")
        self.cpus = cpus
        self.geo_radius = local_span
        self.distance = distance
        self.solver_opt = solver_options

        logger.info('Loading in coordinate data from mesh file...')
        self.nodes, self.coords, _ = geolib.load_gmsh_nodes(self.mesh, (2, 5))
        _, _, trigs = geolib.load_gmsh_elems(self.mesh, (2, 5))
        self.trigs = np.array(trigs).reshape(-1, 3)
        logger.info('Successfully pulled in node and element data!')

        # Construct basis of sampling space using centroid
        logger.info('Constructing initial sampling surface...')
        C, iR, bounds = self._initialize(initial_centroid, span)
        self.C = C
        self.iR = iR
        self.bounds = bounds
        logger.info('Successfully constructed initial sampling surface')

        # Store single read in memory, this will prevent GC issues
        logger.info('Caching mesh file on instance construction...')
        self.cached_mesh = mesh_io.read_msh(mesh_file)
        self.cached_mesh.fix_surface_labels()
        logger.info('Successfully cached mesh file')

        logger.info('Storing standard conductivity values...')
        condlist = [c.value for c in cond.standard_cond()]
        self.cond = cond.cond2elmdata(self.cached_mesh, condlist)
        logger.info('Successfully stored conductivity values...')

        # Control for coil file-type and SimNIBS changing convention
        if self.coil.endswith('.ccd'):
            self.normflip = 1
        else:
            self.normflip = -1