1 #include "WriteGmsh.hpp"
2 #include "moab/CN.hpp"
3 #include "MBTagConventions.hpp"
4 #include "MBParallelConventions.h"
5 #include "moab/Interface.hpp"
6 #include "moab/Range.hpp"
7 #include "moab/WriteUtilIface.hpp"
8 #include "moab/FileOptions.hpp"
9 #include "GmshUtil.hpp"
10
11 #include <fstream>
12 #include <map>
13 #include <set>
14
15 namespace moab
16 {
17
18 const int DEFAULT_PRECISION = 10;
19
20 WriterIface* WriteGmsh::factory( Interface* iface )
21 {
22 return new WriteGmsh( iface );
23 }
24
25 WriteGmsh::WriteGmsh( Interface* impl ) : mbImpl( impl )
26 {
27 impl->query_interface( mWriteIface );
28 }
29
30 WriteGmsh::~WriteGmsh()
31 {
32 mbImpl->release_interface( mWriteIface );
33 }
34
35
36 struct ElemInfo
37 {
38 void set( int st, int idt )
39 {
40 while( count < st )
41 sets[count++] = 0;
42 sets[count++] = idt;
43 }
44 int count;
45 int sets[3];
46 int id;
47 int type;
48 };
49
50
51 ErrorCode WriteGmsh::write_file( const char* file_name,
52 const bool overwrite,
53 const FileOptions& options,
54 const EntityHandle* output_list,
55 const int num_sets,
56 const std::vector< std::string >& ,
57 const Tag* ,
58 int ,
59 int )
60 {
61 ErrorCode rval;
62 Tag global_id = 0, block_tag = 0, geom_tag = 0, prtn_tag = 0;
63
64 if( !overwrite )
65 {
66 rval = mWriteIface->check_doesnt_exist( file_name );
67 if( MB_SUCCESS != rval ) return rval;
68 }
69
70
71 global_id = mbImpl->globalId_tag();
72 mbImpl->tag_get_handle( MATERIAL_SET_TAG_NAME, 1, MB_TYPE_INTEGER, block_tag );
73 if( global_id ) mbImpl->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, geom_tag );
74 mbImpl->tag_get_handle( PARALLEL_PARTITION_TAG_NAME, 1, MB_TYPE_INTEGER, prtn_tag );
75
76
77 Range sets[3];
78 Tag set_tags[] = { block_tag, geom_tag, prtn_tag };
79 Tag set_ids[] = { block_tag, 0 , prtn_tag };
80
81
82 Range elements, nodes;
83 if( !output_list )
84 {
85 rval = mbImpl->get_entities_by_dimension( 0, 0, nodes, false );
86 if( MB_SUCCESS != rval ) return rval;
87 for( int d = 1; d <= 3; ++d )
88 {
89 Range tmp_range;
90 rval = mbImpl->get_entities_by_dimension( 0, d, tmp_range, false );
91 if( MB_SUCCESS != rval ) return rval;
92 elements.merge( tmp_range );
93 }
94
95 for( int s = 0; s < 3; ++s )
96 {
97 if( set_tags[s] )
98 {
99 rval = mbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, set_tags + s, 0, 1, sets[s] );
100 if( MB_SUCCESS != rval ) return rval;
101 }
102 }
103 }
104 else
105 {
106 for( int i = 0; i < num_sets; ++i )
107 {
108 EntityHandle set = output_list[i];
109 for( int d = 1; d < 3; ++d )
110 {
111 Range tmp_range, tmp_nodes;
112 rval = mbImpl->get_entities_by_dimension( set, d, tmp_range, true );
113 if( rval != MB_SUCCESS ) return rval;
114 elements.merge( tmp_range );
115 rval = mbImpl->get_adjacencies( tmp_range, set, false, tmp_nodes );
116 if( rval != MB_SUCCESS ) return rval;
117 nodes.merge( tmp_nodes );
118 }
119
120 for( int s = 0; s < 3; ++s )
121 {
122 if( set_tags[s] )
123 {
124 Range tmp_range;
125 rval = mbImpl->get_entities_by_type_and_tag( set, MBENTITYSET, set_tags + s, 0, 1, tmp_range );
126 if( MB_SUCCESS != rval ) return rval;
127 sets[s].merge( tmp_range );
128 int junk;
129 rval = mbImpl->tag_get_data( set_tags[s], &set, 1, &junk );
130 if( MB_SUCCESS == rval ) sets[s].insert( set );
131 }
132 }
133 }
134 }
135
136 if( elements.empty() )
137 {
138 MB_SET_ERR( MB_ENTITY_NOT_FOUND, "Nothing to write" );
139 }
140
141
142
143
144 std::vector< int > global_id_array( elements.size() );
145 std::vector< int >::iterator id_iter;
146 if( !global_id || MB_SUCCESS != mbImpl->tag_get_data( global_id, elements, &global_id_array[0] ) )
147 {
148 id_iter = global_id_array.begin();
149 for( Range::iterator i = elements.begin(); i != elements.end(); ++i, ++id_iter )
150 *id_iter = mbImpl->id_from_handle( *i );
151 }
152
153
154
155 int max_id = 0;
156 for( id_iter = global_id_array.begin(); id_iter != global_id_array.end(); ++id_iter )
157 if( *id_iter > max_id ) max_id = *id_iter;
158
159
160 std::map< EntityHandle, ElemInfo > elem_sets;
161 std::set< int > elem_global_ids;
162 id_iter = global_id_array.begin();
163
164
165 for( Range::reverse_iterator i = elements.rbegin(); i != elements.rend(); ++i )
166 {
167 int id = *id_iter;
168 ++id_iter;
169 if( !elem_global_ids.insert( id ).second ) id = ++max_id;
170
171 ElemInfo& ei = elem_sets[*i];
172 ei.count = 0;
173 ei.id = id;
174
175 EntityType type = mbImpl->type_from_handle( *i );
176 int num_vtx;
177 const EntityHandle* conn;
178 rval = mbImpl->get_connectivity( *i, conn, num_vtx );
179 if( MB_SUCCESS != rval ) return rval;
180
181 ei.type = GmshUtil::get_gmsh_type( type, num_vtx );
182 if( ei.type < 0 )
183 {
184 MB_SET_ERR( MB_FILE_WRITE_ERROR, "Gmem file format does not support element of type "
185 << CN::EntityTypeName( type ) << " with " << num_vtx << " vertices" );
186 }
187 }
188
189 elem_global_ids.clear();
190 global_id_array.clear();
191
192
193
194 for( int s = 0; s < 3; ++s )
195 {
196 if( !set_tags[s] ) continue;
197
198 for( Range::iterator i = sets[s].begin(); i != sets[s].end(); ++i )
199 {
200 int id;
201 if( set_ids[s] )
202 {
203 rval = mbImpl->tag_get_data( set_ids[s], &*i, 1, &id );
204 if( MB_SUCCESS != rval ) return rval;
205 }
206 else
207 id = mbImpl->id_from_handle( *i );
208
209 Range elems;
210 rval = mbImpl->get_entities_by_handle( *i, elems );
211 if( MB_SUCCESS != rval ) return rval;
212
213 elems = intersect( elems, elements );
214 for( Range::iterator j = elems.begin(); j != elems.end(); ++j )
215 elem_sets[*j].set( s, id );
216 }
217 }
218
219
220 std::ofstream out( file_name );
221 if( !out ) return MB_FILE_DOES_NOT_EXIST;
222
223
224 out << "$MeshFormat" << std::endl;
225 out << "2.0 0 " << sizeof( double ) << std::endl;
226 out << "$EndMeshFormat" << std::endl;
227
228
229 int precision;
230 if( MB_SUCCESS != options.get_int_option( "PRECISION", precision ) ) precision = DEFAULT_PRECISION;
231 const int old_precision = out.precision();
232 out.precision( precision );
233
234
235 out << "$Nodes" << std::endl;
236 out << nodes.size() << std::endl;
237 std::vector< double > coords( 3 * nodes.size() );
238 rval = mbImpl->get_coords( nodes, &coords[0] );
239 if( MB_SUCCESS != rval ) return rval;
240 std::vector< double >::iterator c = coords.begin();
241 for( Range::iterator i = nodes.begin(); i != nodes.end(); ++i )
242 {
243 out << mbImpl->id_from_handle( *i );
244 out << " " << *c;
245 ++c;
246 out << " " << *c;
247 ++c;
248 out << " " << *c;
249 ++c;
250 out << std::endl;
251 }
252 out << "$EndNodes" << std::endl;
253 coords.clear();
254
255
256 out.precision( old_precision );
257
258
259 out << "$Elements" << std::endl;
260 out << elem_sets.size() << std::endl;
261 for( std::map< EntityHandle, ElemInfo >::iterator i = elem_sets.begin(); i != elem_sets.end(); ++i )
262 {
263 int num_vtx;
264 const EntityHandle* conn;
265 rval = mbImpl->get_connectivity( i->first, conn, num_vtx );
266 if( MB_SUCCESS != rval ) return rval;
267 out << i->second.id << ' ' << i->second.type << ' ' << i->second.count;
268 for( int j = 0; j < i->second.count; ++j )
269 out << ' ' << i->second.sets[j];
270
271 const int* order = GmshUtil::gmshElemTypes[i->second.type].node_order;
272
273
274 if( order )
275 {
276 for( int j = 0; j < num_vtx; ++j )
277 out << ' ' << mbImpl->id_from_handle( conn[order[j]] );
278 }
279 else
280 {
281 for( int j = 0; j < num_vtx; ++j )
282 out << ' ' << mbImpl->id_from_handle( conn[j] );
283 }
284 out << std::endl;
285 }
286 out << "$EndElements" << std::endl;
287
288
289 return MB_SUCCESS;
290 }
291
292 }