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
0028 if ischar(filename) && strcmp(filename,'UNIT_TEST'); do_unit_test; return; end
0029
0030 fid = fopen(filename,'r');
0031 content = textscan(fid,'%s','Delimiter','\n');
0032 content = content{:};
0033 fclose(fid);
0034 phys_names = [];
0035 entities = [];
0036 idx = find(startsWith(content,'$'));
0037 for i = 1:2:numel(idx)
0038 block = content( (idx(i)+1) : idx(i+1)-1 );
0039 switch content{idx(i)}
0040 case '$MeshFormat'
0041 gmshformat = parse_format(block);
0042 case '$Entities'
0043 entities= parse_entities( block, gmshformat );
0044 case '$Elements'
0045 elements= parse_elements( block, gmshformat );
0046 case '$Nodes'
0047 nodes= get_lines_with_nodes( block, gmshformat );
0048 case '$PhysicalNames'
0049 phys_names= parse_names( block, gmshformat );
0050 end
0051 end
0052
0053
0054 if ~isempty(phys_names)
0055 if (gmshformat >= 4.0)
0056 assert(~isempty(entities), 'expected $Entities section (GMSH format 4)');
0057 for i = 1:length(phys_names)
0058 phys_tag = phys_names(i).tag;
0059 dim = phys_names(i).dim;
0060 tmpentities = find(arrayfun(@(x) any(x.phys_tag == phys_tag), entities));
0061 tags = cat(1,entities(tmpentities).entity_tag);
0062 idx = ismember(elements.entity_tag, tags) & elements.dim == dim;
0063 phys_names(i).nodes = elements.simp(idx,1:dim+1);
0064 elements.phys_tag(idx) = phys_tag;
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 idx = elements.phys_tag == tag & elements.dim == dim;
0072 phys_names(i).nodes = elements.simp(idx,1:dim+1);
0073 end
0074 end
0075 end
0076
0077 edg = [];
0078 bc = [];
0079
0080
0081 tri = elements.type==2;
0082
0083 tet = elements.type==4;
0084
0085
0086 if any(nodes(:,4) ~= nodes(1,4))
0087 vtx = nodes(:,2:4);
0088 simp = elements.simp(tet,:);
0089 srf = elements.simp(tri,1:3);
0090 mat_ind = elements.phys_tag(tet);
0091 else
0092 vtx = nodes(:,2:3);
0093 simp = elements.simp(tri,1:3);
0094 srf = [];
0095 mat_ind = elements.phys_tag(tri);
0096 end
0097
0098 fc = elements.phys_tag(tri);
0099 end
0100
0101 function mat = get_lines_with_nodes( lines, gmshformat )
0102
0103
0104 switch floor(gmshformat)
0105
0106
0107
0108
0109
0110 case 2
0111 n_rows = parse_rows(lines{1},gmshformat);
0112
0113 mat= textscan(sprintf('%s ',lines{2:end}),'%f');
0114 mat = reshape(mat{1},[4,n_rows])';
0115 case 4;
0116 n = sscanf(lines{1}, '%d')';
0117 n_block = n(1);
0118 n_nodes = n(2);
0119 mat = zeros(n_nodes,4);
0120 count = 2;
0121 while n_block > 0
0122 n_block = n_block - 1;
0123 tline = lines{count}; count = count + 1;
0124 blk = sscanf(tline, '%d')';
0125 blk_nodes = blk(end);
0126 if blk_nodes == 0, continue, end
0127 if gmshformat == 4.1
0128 node_tag = textscan(sprintf('%s ',lines{count:count+blk_nodes-1}),'%f');
0129 node_tag = node_tag{1};
0130 count = count + blk_nodes;
0131
0132 el = textscan(sprintf('%s ',lines{count:count+blk_nodes-1}),'%f');
0133 el = reshape(el{1},[3 blk_nodes])';
0134 count = count + blk_nodes;
0135 mat(node_tag,:) = [node_tag(:), el(:,1:end)];
0136 else
0137
0138 data = textscan(sprintf('%s ',lines{count:count+blk_nodes-1}),'%f');
0139 data = reshape(data{1},[4 blk_nodes])';
0140 mat(data(:,1),:) = data;
0141 count = count + blk_nodes;
0142 end
0143
0144 end
0145 assert(n_block == 0, 'failed to consume all $Nodes blocks');
0146 otherwise; error('cant parse gmsh file of this format');
0147 end
0148 end
0149
0150 function gmshformat = parse_format(lines)
0151 rawformat = sscanf(lines{1},'%f');
0152 gmshformat = rawformat(1);
0153 end
0154
0155 function n_rows = parse_rows(tline, gmshformat)
0156 n_rows = sscanf(tline,'%d');
0157 switch floor(gmshformat)
0158 case 2; n_rows = n_rows(1);
0159 case 4; n_rows = n_rows(2);
0160 otherwise; error('cant parse gmsh file of this format');
0161 end
0162 end
0163
0164 function names = parse_names( lines, version )
0165
0166
0167 n_rows = sscanf(lines{1},'%d');
0168 names = struct('tag',{},'dim',{},'name',{});
0169 for i = 1:n_rows
0170 tline = lines{1+i};
0171 parts = regexp(tline,' ','split');
0172 nsz = size(names,2)+1;
0173 names(nsz).dim = str2double( parts(1) );
0174 names(nsz).tag = str2double( parts(2) );
0175 tname = parts(3);
0176 names(nsz).name = strrep(tname{1},'"','');
0177 end
0178 end
0179
0180 function elements = parse_entities( lines, gmshformat )
0181 elements = [];
0182 switch floor(gmshformat)
0183 case 2; warning('ignoring $Entities$ for GMSH v2 file');
0184 case 4;
0185 elements = parse_v4_entities(lines, gmshformat);
0186 otherwise error('cant parse this file type');
0187 end
0188 end
0189
0190 function entities = parse_v4_entities(lines, gmshformat)
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219 entities = struct('phys_tag',{},'dim',{},'entity_tag',{});
0220
0221 bl = sscanf(lines{1}, '%d')';
0222 n_points = bl(1);
0223 n_curves = bl(2);
0224 n_surf = bl(3);
0225 n_vol = bl(4);
0226
0227 for i = 2:numel(lines)
0228 tline = lines{i};
0229 bl = sscanf(tline, '%f')';
0230 off = 8;
0231 if n_points > 0
0232 n_points = n_points - 1;
0233 dim = 0;
0234 off = 5;
0235 elseif n_curves > 0
0236 n_curves = n_curves - 1;
0237 dim = 1;
0238 elseif n_surf > 0
0239 n_surf = n_surf - 1;
0240 dim = 2;
0241 elseif n_vol > 0
0242 n_vol = n_vol - 1;
0243 dim = 3;
0244 else
0245 error('extra $Entities found in v4.1 GMSH file');
0246 end
0247 if bl(off) > 0
0248 entities(end+1).phys_tag = bl((off+1):uint32(off+bl(off)));
0249 entities(end).entity_tag = uint32(bl(1));
0250 entities(end).dim = dim;
0251 end
0252 end
0253 assert(n_points == 0, 'missing Entity/points from GMSH 4.1 file');
0254 assert(n_curves == 0, 'missing Entity/curves from GMSH 4.1 file');
0255 assert(n_surf == 0, 'missing Entity/surfaces from GMSH 4.1 file');
0256 assert(n_vol == 0, 'missing Entity/volumes from GMSH 4.1 file');
0257 end
0258
0259
0260 function elements = parse_elements( lines, gmshformat )
0261 n_rows = parse_rows(lines{1},gmshformat);
0262 switch floor(gmshformat)
0263 case 2; elements = parse_v2_elements(lines(2:end),n_rows);
0264 case 4; elements = parse_v4_elements(lines,gmshformat);
0265 otherwise error('cant parse this file type');
0266 end
0267 end
0268
0269 function elements = parse_v4_elements(lines,gmshformat)
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285 bl = sscanf(lines{1}, '%d')';
0286 n_blocks = bl(1);
0287 n_elems = bl(2);
0288 e_block = 0;
0289 simp = zeros([n_elems,4],'uint32');
0290 type = zeros([n_elems,1],'uint8');
0291 entity_tag = zeros([n_elems,1],'uint32');
0292 type = zeros([n_elems,1], 'uint8');
0293 dim = zeros([n_elems,1], 'uint8');
0294 phys_tag = zeros([n_elems,1], 'uint32');
0295 count = 2;
0296 for i = 1:n_blocks
0297 bl = sscanf(lines{count}, '%d')';
0298 count = count + 1;
0299 if gmshformat >= 4.1
0300 e_dim = bl(1);
0301 e_tag = bl(2);
0302 else
0303 e_tag = bl(1);
0304 e_dim = bl(2);
0305 end
0306 e_type = bl(3);
0307 e_block = bl(4);
0308
0309 data = textscan(sprintf('%s ',lines{count:count+e_block-1}),'%d');
0310 data = reshape(data{1},[e_dim+2 e_block])';
0311 count = count + e_block;
0312 n_elems = n_elems - size(data,1);
0313 idx = data(:,1);
0314 simp(idx,1:e_dim+1) = data(:,2:end);
0315 type(idx) = e_type;
0316 entity_tag(idx) = e_tag;
0317 dim(idx) = e_dim;
0318 end
0319 assert(n_elems == 0, 'missing Elements from GMSH 4 file');
0320
0321 elements = struct('simp',simp,'type',type,'entity_tag',entity_tag,...
0322 'dim',dim,'phys_tag',phys_tag);
0323
0324
0325
0326
0327
0328 end
0329
0330 function elements = parse_v2_elements(lines,n_rows)
0331
0332
0333 elements.simp = zeros([n_rows,4],'uint32');;
0334 elements.phys_tag = zeros([n_rows,1], 'uint32');
0335 elements.geom_tag = zeros([n_rows,1],'uint32');;
0336 elements.type = zeros([n_rows,1],'uint8');
0337 elements.dim = zeros([n_rows,1], 'uint8');
0338
0339 for i = 1:n_rows
0340 tline = lines{i};
0341 n = sscanf(tline, '%d')';
0342 ndim = numel(n) - n(3) - 4;
0343 elements.simp(i,1:ndim+1) = n(n(3) + 4:end);
0344 elements.type(i) = n(2);
0345 elements.dim(i) = ndim;
0346 if n(3) > 0
0347
0348
0349
0350
0351 tags = n(4:3+n(3));
0352 if length(tags) >= 1
0353 elements.phys_tag(i) = tags(1);
0354 if length(tags) >= 2
0355 elements.geom_tag(i) = tags(2);
0356 end
0357 end
0358 end
0359 end
0360 end
0361
0362 function do_unit_test
0363 selfdir = fileparts(which('gmsh_read_mesh'));
0364 [srf,vtx,fc,bc,simp,edg,mat_ind,phys_names] = gmsh_read_mesh(fullfile(selfdir, 'tests/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, 'tests/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, ['tests/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, ['tests/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