Skip to content

Commit

Permalink
Improved comments in EIDORS example, fixed typos and links in other r…
Browse files Browse the repository at this point in the history
…eadmes
  • Loading branch information
Jimbles committed May 4, 2020
1 parent ff1d5e4 commit d17b217
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 35 deletions.
2 changes: 1 addition & 1 deletion examples/neonatescalp/readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Neonate scalp from CAD to Mesh

This example shows how to use the MESHER using a surface model `.stl` from a CAD application. This method was used to mesh the tanks in [this paper](https://doi.org/10.1088/1361-6579/aa6586). This requires MATLAB and `iso2mesh` to be installed. The script `example_neonate.m` walks through the process of converting to inr and calling the mesher all through MATLAB.
This example shows how to use the MESHER using a surface model `.stl` from a CAD application. This method was used to mesh the tanks in [this paper](https://doi.org/10.1088/1361-6579/aa6586), see [Head Tanks](https://github.com/EIT-team/Tanks) for 3D printable versions. This requires MATLAB and `iso2mesh` to be installed. The script `example_neonate.m` walks through the process of converting to inr and calling the mesher all through MATLAB.

## STL to INR

Expand Down
2 changes: 1 addition & 1 deletion examples/runexamples.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

% Example usage of the MATLAB wrapper
%% Neonate brain

runmesher('neonatescalp/NNscalp.inr','neonatescalp/NNscalp_elecINRpos.txt',...
Expand Down
97 changes: 69 additions & 28 deletions examples/solvers/EIDORS/eidors_example.m
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
%% EIDORS example

% Make sure you have added Mesher/MATLAB to the path, and ran EIDORS
% startup.m
% startup.m - Tested with EIDORS 3.10

% Mesher outputs ground node and electrode *coordinates* but EIDORS
% requires node references. So this code finds the required nodes.
% EIDORS also requires the measurement protocol in a stim structure, so
% this is converted from the txt file that PEITS uses.

%% Run mesher
% Settings for a lower resolution (~100k elem) output mesh for demonstration
Expand Down Expand Up @@ -43,7 +47,9 @@
% Check electrodes are aligned correctly, and output is sensible before
% running computationally expensive output

% load Mesher output - either existing in the repo or the one just made
Mesh=loadmesh('output/NNEIDORS');
% load('NNEIDORS_ex'); % example output if MESHER not run

figure
hold on;
Expand All @@ -60,78 +66,107 @@
view(3)
title('Neonate Mesh Low Res')

% Here you would now want to rerun the mesher with optimisations on, and
% higher density if you wish especially around the electrodes

%% Load into EIDORS

%remember to run eidors startup
% remember to run eidors startup!

%based on mk_fmdl_from_nodes
MDL=eidors_obj('fwd_model','test');
% this is largely based on mk_fmdl_from_nodes

% create blank fwd object
MDL=eidors_obj('fwd_model','NeonateHead');

% specify nodes and triangulation
MDL.nodes = Mesh.Nodes;
MDL.elems = Mesh.Tetra;

% specify boundary elements
[srf, idx] = find_boundary(Mesh.Tetra);

MDL.boundary = srf;

%find ground node
% find ground node - Mesher saves XYZ coordinates so find closest node
gnd_dist=sqrt(sum((Mesh.Nodes - Mesh.gnd_pos).^2,2));
[~, gnd_node] = min(gnd_dist);
MDL.gnd_node = gnd_node;

% Electrodes
%% Electrodes
% Mesher saves electrodes as position, whereras EIDORS requires the nodes
% and contact impedance to be given within a structure. So here we find
% nodes on the suface within electrode radius

% find nodes on the suface within electrode radius
z_contact = 100;
z_contact = 100; % ohms
elec_radius = .008; %in meters

srf_idx=unique(srf(:));
srf_nodes=Mesh.Nodes(srf_idx,:);
% unique surface node references
srf_tri=unique(srf(:));
srf_nodes=Mesh.Nodes(srf_tri,:);

% loop through each electrode
for iElec = 1:size(Mesh.elec_pos,1)

%assign conductivity to structure
electrodes(iElec).z_contact= z_contact;

% find surface nodes within electrode radius
edist = sqrt(sum((srf_nodes - Mesh.elec_pos(iElec,:)).^2,2));
enodes = srf_idx(edist <= elec_radius);
enodes = srf_tri(edist <= elec_radius);

curNodes=enodes';
curNodes = unique(curNodes);

% only use nodes which can be used in triangulation as this confuses
% find_electrode_bdy.m, as it thinks any unused node is a point electrode.
% This is adapted from find_electrode_bdy
% This is adapted from find_electrode_bdy to find surface nodes that
% form a complete surface triangle (in srf) i.e. form a complete triangulation

% count how many times each node is used in the surface
bdy_els = zeros(size(srf,1),1);
% count how many times each node ref is used in the surface
% triangulation
boundary_els = zeros(size(srf,1),1);
for nd= curNodes(:)'
bdy_els = bdy_els + any(srf==nd,2);
boundary_els = boundary_els + any(srf==nd,2);
end
% Nodes used three times are part of a triangulation
ffb = find(bdy_els == size(srf,2));
% only use nodes which appear 3 times
curNodes=intersect(curNodes,unique(srf(ffb,:)));
% Complete surface triangles are ones where each node is within radius
% i.e. curNodes contains each column in srf
elec_tri = find(boundary_els == size(srf,2));
% remove references to nodes that were not part of a full triangle
curNodes=intersect(curNodes,unique(srf(elec_tri,:)));
electrodes(iElec).nodes = curNodes;
end

% add electrode strucutre to model struct
MDL.electrode = electrodes;
MDL.solve= @fwd_solve_1st_order;
MDL.jacobian= @jacobian_adjoint;
MDL.system_mat= @system_mat_1st_order;
MDL.normalize_measurements = 0;

figure
show_fem(MDL)
title('Mesher output in EIDORS');
saveas(gcf,'figures/EIDORS_FEM.png');
% saveas(gcf,'figures/EIDORS_FEM.png');
%% Forward model settings

% set some default solver parameters
MDL.solve= @fwd_solve_1st_order;
MDL.jacobian= @jacobian_adjoint;
MDL.system_mat= @system_mat_1st_order;
MDL.normalize_measurements = 0;

% Convert protocol file to EIDORS stim patterns

Amp=240e-6;
Amp=240e-6; % Current amplitude in Amps

N_elec=size(Mesh.elec_pos,1);

% PEITS and Supersolver use text file with following columns:
% CS+ CS- V+ V-
% 16,2,1,33
% 16,2,2,33
% 16,2,3,33
% ...
% i.e. inject between 16 and 2, measure 1:32 referenced to 33 etc.
prt=dlmread('NN2016_Prt_full.txt');

% create stimulation structure
[stim]= stim_meas_list( prt,N_elec,Amp);

MDL.stimulation=stim;
Expand All @@ -141,7 +176,11 @@
disp('Forward model is ok!');
end

%% Add conductivity and solve
%% Add conductivity

% Mesher specifies layer index for each element within mat_ref. This mesh
% has two layers : 1 for scalp and brain (saline), 2 for skull, as it is based on
% the head tank https://doi.org/10.1088/1361-6579/aa6586

cond_scalp=0.2;
cond_skull=0.03;
Expand All @@ -152,10 +191,12 @@
cond(Mesh.mat_ref == 1) = cond_scalp;
cond(Mesh.mat_ref == 2) = cond_skull;

% create image object using mesh and conductivity vector
img = mk_image(MDL,cond);
%% Solve

% solve fwd for this conductivity
data=fwd_solve( img);
% solve forward model for this conductivity to get boundary voltages
data=fwd_solve(img);

figure
plot(data.meas)
Expand Down
2 changes: 1 addition & 1 deletion examples/solvers/EIDORS/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## Loading mesh

First call MESHER to create a low resolution neonatal head mesh. If you are using >1 mln elements then [PEITS](https://github.com/EIT-team/PEITS) probably better suited.
First call MESHER to create a low resolution neonatal head mesh (from [this paper](https://doi.org/10.1088/1361-6579/aa6586)). If you are using >1 mln elements then [PEITS](https://github.com/EIT-team/PEITS) probably better suited.

```bash
../../../bin/mesher -i ../../neonatescalp/NNscalp.inr -e ../../neonatescalp/NNscalp_elecINRpos.txt -p NNEIDORS_param.txt -d output/ -o NNEIDORS
Expand Down
8 changes: 4 additions & 4 deletions examples/solvers/readme.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Using the MESHER output

- [PEITS](PEITS/readme) a fast parallel EIT solver
- [EIDORS](EIDORS/readme) the most common EIT MATLAB software suite
- [SuperSolver](SuperSolver/readme) simplified EIDORS with only core functions
- [Toast++](toast/readme) Software suite for DOT
- [PEITS](PEITS/readme.md) a fast parallel EIT solver
- [EIDORS](EIDORS/readme.md) the most common EIT MATLAB software suite
- [SuperSolver](SuperSolver/readme.md) simplified EIDORS with only core functions
- [Toast++](toast/readme.md) Software suite for DOT

Example EIT voltages from the three different forward model calculations
![PEITS Volts](PEITS/figures/PEITS_Volts.png)
Expand Down

0 comments on commit d17b217

Please sign in to comment.