Source code for cortex.polyutils.exact_geodesic
import os
import subprocess
import tempfile
import numpy as np
from ..options import config
from .. import formats
class ExactGeodesicException(Exception):
"""Raised when exact_geodesic_distance() is unavailable or used improperly
- to create a fallback to geodesic_distance()
"""
pass
class ExactGeodesicMixin(object):
"""Mixin for computing exact geodesic distance along surface"""
def exact_geodesic_distance(self, vertex):
"""Compute exact geodesic distance along surface
- uses VTP geodesic algorithm
Parameters
----------
- vertex : int or list of int
index of vertex or vertices to compute geodesic distance from
"""
if isinstance(vertex, list):
return np.vstack(self.exact_geodesic_distance(v) for v in vertex).min(0)
else:
return self.call_vtp_geodesic(vertex)
def call_vtp_geodesic(self, vertex):
"""Compute geodesic distance using VTP method
VTP Code
--------
- uses external authors' implementation of [Qin el al 2016]
- https://github.com/YipengQin/VTP_source_code
- vtp code must be compiled separately to produce VTP executable
- once compiled, place path to VTP executable in pycortex config
- i.e. in config put:
[geodesic]
vtp_path = /path/to/compiled/VTP
Parameters
----------
- vertex : int
index of vertex to compute geodesic distance from
"""
if config.has_option('geodesic', 'vtp_path'):
vtp_path = config.get('geodesic', 'vtp_path')
else:
raise ExactGeodesicException('must set config["geodesic"]["vtp_path"]')
if not os.path.exists(vtp_path):
raise ExactGeodesicException('vtp_path does not exist: ' + str(vtp_path))
# initialize temporary files
f_obj, tmp_obj_path = tempfile.mkstemp()
f_output, tmp_output_path = tempfile.mkstemp()
# create object file
formats.write_obj(tmp_obj_path, self.pts, self.polys)
# run algorithm
cmd = [vtp_path, '-m', tmp_obj_path, '-s', str(vertex), '-o', tmp_output_path]
subprocess.call(cmd)
# read output
with open(tmp_output_path) as f:
output = f.read()
distances = np.array(output.split('\n')[:-2], dtype=float)
if distances.shape[0] == 0:
raise ExactGeodesicException('VTP error')
os.close(f_obj)
os.close(f_output)
return distances