Point analysis

Point analysis evaluates the FEM solution at selected locations after the volume conductor problem has been solved. This is the bridge between the raw field solution and downstream analyses such as VTA-like thresholding or pathway-based activation studies.

Available point models

OSS-DBSv2 includes multiple ways to sample the field:

  • Lattice for regular point grids around the electrode

  • VoxelLattice for image-like outputs aligned with voxel space

  • Pathway for points that lie on fiber trajectories or axon pathways

These models are especially important when the primary output is not just the potential field itself, but a derived spatial analysis.

Typical use cases

  • estimate VTA-like regions from electric field thresholds

  • export pointwise potentials or field magnitudes for post-processing

  • evaluate pathway trajectories for later axon activation modeling

Practical guidance

  • Disable point models during the very first setup run if you want to validate the core FEM workflow first.

  • Enable lattices when exploring field spread around the electrode.

  • Enable pathway models when tract data and axon activation workflows are part of the study design.

API reference

class ossdbs.point_analysis.point_model.PointModel[source]

Bases: ABC

Class to support evaluation of VCM at points.

property axon_index: ndarray

Mapping between axons and points.

close_output_file()[source]

Close out-of-core file.

property collapse_VTA: bool

Remove electrode from VTA.

compute_solutions_in_time_domain(signal_length: int, convert_field: bool = False) tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray][source]

Compute time-domain solution for all properties.

Parameters:
  • signal_length (int) – Number of frequencies of input time vector. This value must be set correctly, otherwise the inverse FFT does not contain correct information.

  • convert_field (bool) – Whether to FFT-transform also the electric field.

property coordinates: ndarray

Point coordinates.

copy_frequency_domain_solution_from_vcm(freq_idx: int, potentials: ndarray, fields: ndarray | None = None) None[source]

Copy potentials and fields from volume conductor model.

create_time_result(timesteps: ndarray, potential_in_time: ndarray, Ex_in_time: ndarray | None = None, Ey_in_time: ndarray | None = None, Ez_in_time: ndarray | None = None, truncation_index: int | None = None) TimeResult[source]

Prepare time result and save it to file.

Parameters:
  • timesteps (np.ndarray) – Array with timesteps related to solution

  • potential_in_time (np.ndarray) – Solution array with electric potential

  • Ex_in_time (np.ndarray) – Solution array with x-component of field

  • Ey_in_time (np.ndarray) – Solution array with y-component of field

  • Ez_in_time (np.ndarray) – Solution array with z-component of field

  • truncation_index (int) – Index to truncate solution

property export_field: str

Export electric field in time domain.

export_field_at_frequency(frequency: float, frequency_index: int, electrode=None, activation_threshold: float | None = None)[source]

Write field values to CSV and Nifti (if defined).

Parameters:
  • frequency (float) – Frequency of exported solution

  • frequency_index (int) – Index at which frequency is stored

  • activation_threshold (float) – Threshold to define VTA

  • electrode – Electrode object with geometry details

export_point_model_information(filename: str) None[source]

Export all relevant information about the model to JSON.

export_potential_at_frequency(frequency: float, frequency_index: float) None[source]

Export potential at frequency to CSV.

Parameters:
  • frequency (float) – Frequency of exported solution

  • frequency_index (int) – Index at which frequency is stored

filter_csf_encap(inside_csf: ndarray, inside_encap: ndarray)[source]

Remove points in CSF or encapsulation layer.

Parameters:
  • inside_csf (np.ndarray) – list of points in csf

  • inside_encap (np.ndarray) – list of points in encapsulation layer

filter_for_geometry(grid_pts: MaskedArray) ndarray[source]

Return a lattice that NGSolve can process.

Notes

The masked array is expected to be constructed by points_in_mesh()

get_points_in_csf(mesh: Mesh, conductivity_cf) ndarray[source]

Return mask for points in CSF.

Parameters:
  • mesh (Mesh) – Mesh object on which VCM is defined

  • conductivity_cf (ConductivityCF) – Conductivity function that hold material info

Notes

TODO Type hint

get_points_in_encapsulation_layer(mesh: Mesh) ndarray[source]

Return mask for points in encapsulation layer.

Parameters:

mesh (Mesh) – Mesh object on which VCM is defined

property inside_csf

Points inside csf.

property inside_encap

Points inside encapsulation layer.

property lattice

Lattice of points inside geometry.

property lattice_mask

Mask of points inside geometry.

property name: str

Name to distinguish model type.

property output_path

Path where to save results.

points_in_mesh(mesh: Mesh)[source]

Create a masked array of the points that are in the mesh.

prepare_VCM_specific_evaluation(mesh: Mesh, conductivity_cf)[source]

Prepare data structure according to mesh.

Parameters:
  • mesh (Mesh) – Mesh object on which VCM is defined

  • conductivity_cf (ConductivityCF) – Conductivity function that hold material info

Notes

Mask all points outside domain, filter CSF and encapsulation layer etc.

Prepares data storage for all frequencies at all points. TODO type hints

prepare_frequency_domain_data_structure(signal_length: int, out_of_core: bool = False) None[source]

Allocate arrays that hold frequency domain data.

Parameters:
  • signal_length (int) – Number of frequencies of FFT / input time vector

  • out_of_core (bool) – If arrays should be stored on the hard drive

save(data: TimeResult, file_name: str) None[source]

Save time-domain result to HDF5 file.

abstract save_as_nifti(scalar_field: ndarray, filename: str, binarize: bool = False, activation_threshold: float | None = None)[source]

Save scalar field in abstract orthogonal space in nifti format.

Parameters:
  • scalar_field (numpy.ndarray) – Nx1 array of scalar values on the lattice

  • filename (str) – Name for the nifti file that should contain full path

  • binarize (bool) – Choose to threshold the scalar field and save the binarized result

  • activation_threshold (float) – Activation threshold for VTA estimate

property time_domain_conversion: bool

If time-domain signal shall be computed.

write_netgen_meshsize_file(meshsize: float, filename: str) None[source]

Write a Netgen mesh-size file from the point model coordinates.

This generates a file that can be passed to Netgen via the MeshSizeFilename parameter in MeshingHypothesis to refine the mesh around pathway or lattice points. This is particularly useful in convergence studies where the mesh needs to be fine near neuron trajectories.

Parameters:
  • meshsize (float) – Target element size (in mm) at each point. A common choice is the minimum MRI voxel size.

  • filename (str) – Output file path (e.g. "meshsizes.txt").

Notes

The file follows the Netgen mesh-size format:

nr_points

x1 y1 z1 meshsize
x2 y2 z2 meshsize
...

0

The trailing 0 indicates that no edge-based size constraints are written.

class ossdbs.point_analysis.lattice.Lattice(shape: tuple, center: tuple, distance: float, direction: tuple, collapse_vta: bool = False, export_field: bool = True)[source]

Bases: PointModel

Matrix of point coordinates.

shape

Number of points in each direction (x, y, z).

Type:

tuple

center

Center position of cuboid matrix.

Type:

tuple

distance

Distance between adjacent points.

Type:

float

direction

Orientation of cuboid in 3d space.

Type:

tuple

property VTA_volume: float | None

Return VTA volume in mm^3.

export_point_model_information(filename: str) None[source]

Export all relevant information about the model to JSON.

save_as_nifti(scalar_field: ndarray, filename: str, binarize: bool = False, activation_threshold: float | None = None)[source]

Save scalar field in abstract orthogonal space in nifti format.

Parameters:
  • scalar_field (numpy.ndarray) – Nx1 array of scalar values on the lattice

  • filename (str) – Name for the nifti file that should contain full path

  • binarize (bool) – Choose to threshold the scalar field and save the binarized result

  • activation_threshold (float) – Activation threshold for VTA estimate

class ossdbs.point_analysis.pathway.Pathway(input_path: str, export_field: bool = False)[source]

Bases: PointModel

Pathways comprise populations of axons.

class Axon(name: str, points: ndarray, status: int, orig_inx: int)[source]

Bases: object

name

Naming of axons needs to be axon0, axon1, axon2, … to be processed in the correct order.

Type:

str

points

Contains 3D coordinates of each point within one axon.

Type:

np.ndarray

name: str
orig_inx: int
points: ndarray
status: int
class Population(name: str, axons: list['Pathway.Axon'])[source]

Bases: object

name

Name of neuronal population, e.g. a pathway.

Type:

str

axons

List that contains all axons within one population.

Type:

list[“Pathway.Axon”]

axons: list['Pathway.Axon']
name: str
create_index(lattice: ndarray) ndarray[source]

Create index for each point to the matching axon.

Returns:

index

Return type:

np.ndarray.

export_field_at_frequency(frequency: float, frequency_index: int, electrode=None, activation_threshold: float | None = None)[source]

Write field values to CSV.

Parameters:
  • frequency (float) – Frequency of exported solution

  • frequency_index (int) – Index at which frequency is stored

  • activation_threshold (float) – Threshold to define VTA

  • electrode (ElectrodeModel) – electrode model that holds geometry information

Notes

No Nifti file is exported for a Pathway model.

filter_csf_encap(inside_csf: ndarray, inside_encap: ndarray) None[source]

Change axon status if a single point of the axon is within the CSF or encapsulation layer.

Parameters:
  • inside_csf (np.ndarray) – The array contains 1 if the corresponding point is inside the CSF, 0 otherwise.

  • inside_encap (np.ndarray) – The array contains 1 if the corresponding point is inside the encapsulation layer, 0 otherwise.

filter_for_geometry(grid_pts: MaskedArray) ndarray[source]

Check if any point of an axon is outside the geometry. If this is the case, the entire axon will be marked, and its points will be removed from further processing.

Parameters:

grid_pts (np.ma.MaskedArray) – Array containing points inside the mesh.

Returns:

filtered_points – Returns filtered_points after removing axons that are (partially) outside the geometry.

Return type:

np.ndarray

get_axon_length() int[source]
Returns:

axon_length – Number of points per axon

Return type:

int

Notes

Assume the same length for all axons.

get_axon_names() list[source]
Returns:

axon_names – Names of axons in each population

Return type:

list[list,list,…]

get_axon_numbers() list[source]

Get list of number of axons per population.

Returns:

axon_number – Number of axons per population

Return type:

list[int]

get_population_names() list[source]
Returns:

population_names – Names of all populations defined

Return type:

list[str]

prepare_VCM_specific_evaluation(mesh: Mesh, conductivity_cf)[source]

Prepare data structure according to mesh.

Parameters:
  • mesh (Mesh) – Mesh object on which VCM is defined

  • conductivity_cf (ConductivityCF) – Conductivity function that holds material info

Notes

Mask all points outside domain, filter CSF and encapsulation layer etc.

Prepares data storage for all frequencies at all points.

save_as_nifti(scalar_field, filename, binarize=False, activation_threshold=None)[source]

Save scalar field in abstract orthogonal space in nifti format.

Parameters:
  • scalar_field (numpy.ndarray) – Nx1 array of scalar values on the lattice

  • filename (str) – Name for the nifti file that should contain full path

  • binarize (bool) – Choose to threshold the scalar field and save the binarized result

  • activation_threshold (float) – Activation threshold for VTA estimate

class ossdbs.point_analysis.voxel_lattice.VoxelLattice(imp_coord: ndarray, affine: ndarray, shape: ndarray, header: nibabel.Nifti1Header, export_field: bool = True)[source]

Bases: PointModel

Matrix of grid points in the centers of MRI voxels.

imp_coord

Implantation coordinates in mm space, this will be the center of the grid

Type:

np.ndarray

affine

Affine transformation of the MRI image.

Type:

np.ndarray

shape

Number of points in each direction (x, y, z).

Type:

np.ndarray

Notes

Each dimension of shape must be odd to ensure the grid is centered.

property affine

Affine transformation.

property imp_coord

Implantation coordinates.

save_as_nifti(scalar_field: ndarray, filename: str, binarize: bool = False, activation_threshold: float | None = None)[source]

Save scalar field in abstract orthogonal space in nifti format.

Parameters:
  • scalar_field (numpy.ndarray) – Nx1 array of scalar values on the lattice

  • filename (str) – Name for the nifti file that should contain full path

  • binarize (bool) – Choose to threshold the scalar field and save the binarized result

  • activation_threshold (float) – Activation threshold for VTA estimate

Notes

TODO add support for upsampled lattice

property shape

Shape of MRI data.

class ossdbs.point_analysis.time_results.TimeResult(time_steps: ndarray, points: ndarray, inside_csf: ndarray, inside_encap: ndarray, potential: ndarray, electric_field_magnitude: ndarray | None = None, electric_field_vector_x: ndarray | None = None, electric_field_vector_y: ndarray | None = None, electric_field_vector_z: ndarray | None = None)[source]

Compile time-domain solution.

Notes

The electric field is not always required and is not added by default.

electric_field_magnitude: ndarray = None
electric_field_vector_x: ndarray = None
electric_field_vector_y: ndarray = None
electric_field_vector_z: ndarray = None
inside_csf: ndarray
inside_encap: ndarray
points: ndarray
potential: ndarray
time_steps: ndarray