0001 function [srf,vtx,fc,bc,simp,edg,mat_ind,phys_names,entities] = gmsh_read_mesh(filename)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 if ischar(filename) && strcmp(filename,'UNIT_TEST'); do_unit_test; return; end
0028
0029 fid = fopen(filename,'r');
0030 phys_names = [];
0031 entities = [];
0032 while 1
0033 tline = fgetl(fid);
0034 if ~ischar(tline); fclose(fid); break; end
0035
0036 if strcmp(tline,'$MeshFormat')
0037 gmshformat = parse_format( fid );
0038 elseif strcmp(tline, '$Entities')
0039 entities= parse_entities( fid, gmshformat );
0040 elseif strcmp(tline,'$Elements')
0041 elements= parse_elements( fid, gmshformat );
0042 elseif strcmp(tline,'$Nodes')
0043 nodes= get_lines_with_nodes( fid, gmshformat );
0044 elseif strcmp(tline,'$PhysicalNames')
0045 phys_names= parse_names( fid, gmshformat );
0046 end
0047 end
0048
0049
0050 if ~isempty(phys_names)
0051 if (gmshformat >= 4.0)
0052 assert(~isempty(entities), 'expected $Entities section (GMSH format 4)');
0053 for i = 1:length(phys_names)
0054 phys_tag = phys_names(i).tag;
0055 dim = phys_names(i).dim;
0056 tmpentities = find(arrayfun(@(x) any(x.phys_tag == phys_tag), entities));
0057 tags = cat(1,entities(tmpentities).entity_tag);
0058 tmpelements = find(arrayfun(@(x) and(any(x.entity_tag == tags), (x.dim == dim)), elements));
0059 phys_names(i).nodes = cat(1,elements(tmpelements).simp);
0060 for j = tmpelements(:)'
0061 assert(length(elements(j).phys_tag) > 0, ...
0062 'GMSH format v4 mesh volume elements can only have one $PhysicalName when imported into EIDORS');
0063 elements(j).phys_tag = phys_tag;
0064 end
0065 end
0066 else
0067 assert(isempty(entities), 'unexpected $Entities section (GMSH format 2)');
0068 for i = 1:length(phys_names)
0069 dim = phys_names(i).dim;
0070 tag = phys_names(i).tag;
0071 tmpelements = find(arrayfun(@(x) and(any(x.phys_tag == tag), (x.dim == dim)), elements));
0072 phys_names(i).nodes = cat(1,elements(tmpelements).simp);
0073 end
0074 end
0075 end
0076
0077 edg = [];
0078 bc = [];
0079 mat_ind = [];
0080
0081
0082 if length( unique( nodes(:,4) ) ) > 1
0083 vtx = nodes(:,2:4);
0084
0085 tri = find(arrayfun(@(x)x.type==2,elements));
0086
0087 tet = find(arrayfun(@(x)x.type==4,elements));
0088 simp = cat(1,elements(tet).simp);
0089 srf = cat(1,elements(tri).simp);
0090 mat_ind = cat(1,elements(tet).phys_tag);
0091 else
0092 vtx = nodes(:,2:3);
0093 tri = find(arrayfun(@(x)x.type==2,elements));
0094 simp = cat(1,elements(tri).simp);
0095 srf = [];
0096 mat_ind = cat(1,elements(tri).phys_tag);
0097 end
0098
0099 elemtags = cat(1,elements.phys_tag);
0100 fc = elemtags(tri,1);
0101 end
0102
0103 function mat = get_lines_with_nodes( fid, gmshformat )
0104 tline = fgetl(fid);
0105 n_rows = parse_rows(tline,gmshformat);
0106 switch floor(gmshformat)
0107
0108
0109
0110
0111
0112 case 2; mat= fscanf(fid,'%f',[4,n_rows])';
0113 case 4;
0114 n = sscanf(tline, '%d')';
0115 n_block = n(1);
0116 n_nodes = n(2);
0117 mat = zeros(n_nodes,4);
0118 while n_block > 0
0119 n_block = n_block - 1;
0120 tline = fgetl(fid);
0121 blk = sscanf(tline, '%d')';
0122 blk_nodes = blk(end);
0123 node_tag = zeros(1, blk_nodes);
0124 el = zeros(blk_nodes,3);
0125 if gmshformat == 4.1
0126 for i = 1:blk_nodes
0127 tline = fgetl(fid);
0128 node_tag(i) = sscanf(tline, '%d')';
0129 end
0130 for i = 1:blk_nodes
0131 tline = fgetl(fid);
0132 el(i,:) = sscanf(tline, '%f')';
0133 end
0134 else
0135 for i = 1:blk_nodes
0136 tline = fgetl(fid);
0137 data = sscanf(tline, '%f')';
0138 node_tag(i) = data(1);
0139 el(i,:) = data(2:end);
0140 end
0141
0142
0143
0144 end
0145 mat(node_tag,:) = [node_tag(:), el(:,1:end)];
0146 end
0147 assert(n_block == 0, 'failed to consume all $Nodes blocks');
0148 otherwise; error('cant parse gmsh file of this format');
0149 end
0150 end
0151
0152 function gmshformat = parse_format(fid)
0153 tline = fgetl(fid);
0154 rawformat = sscanf(tline,'%f');
0155 tline = fgetl(fid);
0156 gmshformat = rawformat(1);
0157 end
0158
0159 function n_rows = parse_rows(tline, gmshformat)
0160 n_rows = sscanf(tline,'%d');
0161 switch floor(gmshformat)
0162 case 2; n_rows = n_rows(1);
0163 case 4; n_rows = n_rows(2);
0164 otherwise; error('cant parse gmsh file of this format');
0165 end
0166 end
0167
0168 function names = parse_names( fid, version )
0169
0170
0171 tline = fgetl(fid);
0172 n_rows = sscanf(tline,'%d');
0173 names = struct('tag',{},'dim',{},'name',{});
0174 for i = 1:n_rows
0175 tline = fgetl(fid);
0176 if exist('OCTAVE_VERSION')
0177 parts = strsplit(tline,' ');
0178 else
0179 parts = regexp(tline,' ','split');
0180 end
0181 nsz = size(names,2)+1;
0182 names(nsz).dim = str2double( parts(1) );
0183 names(nsz).tag = str2double( parts(2) );
0184 tname = parts(3);
0185 names(nsz).name = strrep(tname{1},'"','');
0186 end
0187 end
0188
0189 function elements = parse_entities( fid, gmshformat )
0190 elements = [];
0191 switch floor(gmshformat)
0192 case 2; warning('ignoring $Entities$ for GMSH v2 file');
0193 case 4;
0194 elements = parse_v4_entities(fid, gmshformat);
0195 otherwise error('cant parse this file type');
0196 end
0197 end
0198
0199 function entities = parse_v4_entities(fid, gmshformat)
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228 entities = struct('phys_tag',{},'dim',{},'entity_tag',{});
0229 tline = fgetl(fid);
0230 bl = sscanf(tline, '%d')';
0231 n_points = bl(1);
0232 n_curves = bl(2);
0233 n_surf = bl(3);
0234 n_vol = bl(4);
0235
0236 tline = fgetl(fid);
0237 while ~strcmp(tline, '$EndEntities')
0238 bl = sscanf(tline, '%f')';
0239 off = 8;
0240 if n_points > 0
0241 n_points = n_points - 1;
0242 dim = 0;
0243 off = 5;
0244 elseif n_curves > 0
0245 n_curves = n_curves - 1;
0246 dim = 1;
0247 elseif n_surf > 0
0248 n_surf = n_surf - 1;
0249 dim = 2;
0250 elseif n_vol > 0
0251 n_vol = n_vol - 1;
0252 dim = 3;
0253 else
0254 error('extra $Entities found in v4.1 GMSH file');
0255 end
0256 if bl(off) > 0
0257 entities(end+1).phys_tag = bl((off+1):int64(off+bl(off)));
0258 entities(end).entity_tag = int64(bl(1));
0259 entities(end).dim = dim;
0260 end
0261 tline = fgetl(fid);
0262 end
0263 assert(n_points == 0, 'missing Entity/points from GMSH 4.1 file');
0264 assert(n_curves == 0, 'missing Entity/curves from GMSH 4.1 file');
0265 assert(n_surf == 0, 'missing Entity/surfaces from GMSH 4.1 file');
0266 assert(n_vol == 0, 'missing Entity/volumes from GMSH 4.1 file');
0267 end
0268
0269
0270 function elements = parse_elements( fid, gmshformat )
0271 tline = fgetl(fid);
0272 n_rows = parse_rows(tline,gmshformat);
0273 switch floor(gmshformat)
0274 case 2; elements = parse_v2_elements(fid,n_rows);
0275 case 4; elements = parse_v4_elements(fid,tline,gmshformat);
0276 otherwise error('cant parse this file type');
0277 end
0278 end
0279
0280 function elements = parse_v4_elements(fid,tline,gmshformat)
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295 elements = struct('simp',{},'type',{},'entity_tag',{},'dim',{},'phys_tag',{});
0296 bl = sscanf(tline, '%d')';
0297 n_blocks = bl(1);
0298 n_elems = bl(2);
0299 e_block = 0;
0300 tline = fgetl(fid);
0301 while ~strcmp(tline, '$EndElements')
0302 bl = sscanf(tline, '%d')';
0303 if e_block == 0
0304 n_blocks = n_blocks - 1;
0305 if gmshformat >= 4.1
0306 e_dim = bl(1);
0307 e_tag = bl(2);
0308 else
0309 e_tag = bl(1);
0310 e_dim = bl(2);
0311 end
0312 e_type = bl(3);
0313 e_block = bl(4);
0314 else
0315 n_elems = n_elems - 1;
0316 e_block = e_block - 1;
0317 elements(bl(1)).type = e_type;
0318 elements(bl(1)).entity_tag = e_tag;
0319 elements(bl(1)).dim = e_dim;
0320 elements(bl(1)).phys_tag = 0;
0321 elements(bl(1)).simp = bl(2:end);
0322 end
0323 tline = fgetl(fid);
0324 end
0325 tline = fgetl(fid);
0326 assert(n_elems == 0, 'missing Elements from GMSH 4 file');
0327 assert(n_blocks == 0, 'missing Element/blocks from GMSH 4 file');
0328 end
0329
0330 function elements = parse_v2_elements(fid,n_rows)
0331
0332
0333 elements(n_rows).simp = [];
0334 elements(n_rows).phys_tag = [];
0335 elements(n_rows).geom_tag = [];
0336 elements(n_rows).type = [];
0337 elements(n_rows).dim = [];
0338
0339 for i = 1:n_rows
0340 tline = fgetl(fid);
0341 n = sscanf(tline, '%d')';
0342 elements(i).simp = n(n(3) + 4:end);
0343 elements(i).type = n(2);
0344 if n(3) > 0
0345
0346
0347
0348
0349 tags = n(4:3+n(3));
0350 if length(tags) >= 1
0351 elements(i).phys_tag = tags(1);
0352 elements(i).dim = length(elements(i).simp) - 1;
0353 if length(tags) >= 2
0354 elements(i).geom_tag = tags(2);
0355 end
0356 end
0357 end
0358 end
0359 end
0360
0361 function do_unit_test
0362 selfdir = fileparts(which('gmsh_read_mesh'));
0363
0364 [srf,vtx,fc,bc,simp,edg,mat_ind,phys_names] = gmsh_read_mesh(fullfile(selfdir, 'test-4.0.msh'));
0365 unit_test_cmp('v4 vtx ',vtx(2:3,:),[1,0;-1,0])
0366 unit_test_cmp('v4 simp',simp(2:3,:),[3,7,12; 12, 7,14]);
0367
0368 [srf,vtx,fc,bc,simp,edg,mat_ind,phys_names] = gmsh_read_mesh(fullfile(selfdir, 'test-2.2.msh'));
0369 unit_test_cmp('v2 vtx ',vtx(2:3,:),[1,0;-1,0])
0370 unit_test_cmp('v2 simp',simp(2:3,:),[2,4,15; 14,17,19]);
0371
0372 vers = {'2.2', '4.0', '4.1'};
0373 for ver = vers(:)'
0374 ver = ver{1};
0375 [srf,vtx,fc,bc,simp,edg,mat_ind,phys_names] = ...
0376 gmsh_read_mesh( fullfile(selfdir, ['box-' ver '.msh']) );
0377 unit_test_cmp(['2d v' ver ' vtx '],vtx,[0,0;1,0;1,1;0,1;0.5,0.5])
0378 unit_test_cmp(['2d v' ver ' simp'],simp,[2,5,1;1,5,4;3,5,2;,4,5,3]);
0379 unit_test_cmp(['2d v' ver ' phys'],{phys_names(:).name},{'elec#1','elec#2','main'});
0380
0381 [srf,vtx,fc,bc,simp,edg,mat_ind,phys_names] = ...
0382 gmsh_read_mesh( fullfile(selfdir, ['cube-' ver '.msh']) );
0383 unit_test_cmp(['3d v' ver ' vtx '],vtx([1,2,13,end],:),[0,0,1;0,0,0;,0.5,0.5,0;0.5,0.5,1])
0384 unit_test_cmp(['3d v' ver ' simp'],simp([1,2,23,end],:), ...
0385 [10,11,12,13;9,12,14,11;12,14,10,7;13,10,11,6]);
0386 unit_test_cmp(['3d v' ver ' phys'],{phys_names(:).name},{'elec#1','elec#2','main'});
0387 end
0388
0389 end