1 /*******************************************************************/
2 /* XDMF */
3 /* eXtensible Data Model and Format */
4 /* */
5 /* Id : Id */
6 /* Date : $Date$ */
7 /* Version : $Revision$ */
8 /* */
9 /* Author: */
10 /* Kenneth Leiter */
11 /* kenneth.leiter@arl.army.mil */
12 /* US Army Research Laboratory */
13 /* Aberdeen Proving Ground, MD */
14 /* */
15 /* Copyright @ 2009 US Army Research Laboratory */
16 /* All Rights Reserved */
17 /* See Copyright.txt or http://www.arl.hpc.mil/ice for details */
18 /* */
19 /* This software is distributed WITHOUT ANY WARRANTY; without */
20 /* even the implied warranty of MERCHANTABILITY or FITNESS */
21 /* FOR A PARTICULAR PURPOSE. See the above copyright notice */
22 /* for more information. */
23 /* */
24 /*******************************************************************/
25
26 #include "XdmfExodusWriter.h"
27
28 #include <exodusII.h>
29 #include <sstream>
30 #include <string>
31 #include <vector>
32
33 class XdmfExodusWriterNameHandler
34 {
35 public:
36 // Helper function to construct attribute names for attributes with > 1 component since exodus
37 // cannot store vectors. Also deals with MAX_STR_LENGTH limitation in exodus.
ConstructAttributeName(const char * attributeName,std::vector<std::string> & names,int numComponents)38 void ConstructAttributeName(const char * attributeName, std::vector<std::string>& names, int numComponents)
39 {
40 std::string name = attributeName;
41 if(numComponents == 1)
42 {
43 if(name.length() > MAX_STR_LENGTH)
44 {
45 name = name.substr(0, MAX_STR_LENGTH);
46 }
47 names.push_back(name);
48 }
49 else if(numComponents > 1)
50 {
51 int numComponentDigits = int(numComponents / 10);
52 if(name.length() + numComponentDigits > MAX_STR_LENGTH)
53 {
54 name = name.substr(0, MAX_STR_LENGTH - numComponentDigits);
55 }
56 for(int j=0; j<numComponents; ++j)
57 {
58 std::stringstream toAdd;
59 toAdd << name << "-" << j+1;
60 names.push_back(toAdd.str());
61 }
62 }
63 }
64 };
65
66 //
67 // Construct XdmfExodusWriter.
68 //
XdmfExodusWriter()69 XdmfExodusWriter::XdmfExodusWriter()
70 {
71 nameHandler = new XdmfExodusWriterNameHandler();
72 return;
73 }
74
75 //
76 // Destroy XdmfExodusWriter
77 //
~XdmfExodusWriter()78 XdmfExodusWriter::~XdmfExodusWriter()
79 {
80 delete nameHandler;
81 return;
82 }
83
84 // Take Xdmf TopologyType and return Exodus Topology Type
DetermineExodusCellType(XdmfInt32 xdmfElementType)85 std::string XdmfExodusWriter::DetermineExodusCellType(XdmfInt32 xdmfElementType)
86 {
87 switch(xdmfElementType)
88 {
89 case(XDMF_POLYVERTEX):
90 {
91 return "SUP";
92 }
93 case(XDMF_TRI):
94 {
95 return "TRIANGLE";
96 }
97 case(XDMF_QUAD):
98 {
99 return "QUAD";
100 }
101 case(XDMF_TET):
102 {
103 return "TETRA";
104 }
105 case(XDMF_PYRAMID):
106 {
107 return "PYRAMID";
108 }
109 case(XDMF_WEDGE):
110 {
111 return "WEDGE";
112 }
113 case(XDMF_HEX):
114 {
115 return "HEX";
116 }
117 case(XDMF_EDGE_3):
118 {
119 return "EDGE";
120 }
121 case(XDMF_TRI_6):
122 {
123 return "TRIANGLE";
124 }
125 case(XDMF_QUAD_8):
126 {
127 return "QUAD";
128 }
129 case(XDMF_QUAD_9):
130 {
131 return "QUAD";
132 }
133 case(XDMF_TET_10):
134 {
135 return "TETRA";
136 }
137 case(XDMF_WEDGE_15):
138 {
139 return "WEDGE";
140 }
141 case(XDMF_HEX_20):
142 {
143 return "HEX";
144 }
145 case(XDMF_HEX_27):
146 {
147 return "HEX";
148 }
149 }
150 return "";
151 }
152
153 //
154 // Write contents of the XdmfGrid to exodus file.
155 //
write(const char * fileName,XdmfGrid * gridToWrite)156 void XdmfExodusWriter::write(const char * fileName, XdmfGrid * gridToWrite)
157 {
158 // Open Exodus File
159 int wordSize = 8;
160 int storeSize = 8;
161 int exodusHandle = ex_create(fileName, EX_CLOBBER, &wordSize, &storeSize);
162
163 // Initialize Exodus File
164 std::string title = gridToWrite->GetName();
165 if(title.length() > MAX_STR_LENGTH)
166 {
167 title = title.substr(0, MAX_STR_LENGTH);
168 }
169 int num_dim;
170
171 switch(gridToWrite->GetGeometry()->GetGeometryType())
172 {
173 case(XDMF_GEOMETRY_XYZ):
174 num_dim = 3;
175 break;
176 case(XDMF_GEOMETRY_XY):
177 num_dim = 2;
178 break;
179 case(XDMF_GEOMETRY_X_Y_Z):
180 num_dim = 3;
181 break;
182 case(XDMF_GEOMETRY_X_Y):
183 num_dim = 2;
184 break;
185 default:
186 std::cout << "Cannot write grid with geometry " << gridToWrite->GetGeometry()->GetGeometryTypeAsString() << " to exodus file." << std::endl;
187 return;
188 }
189
190 int num_nodes = gridToWrite->GetGeometry()->GetNumberOfPoints();
191 int num_elem = gridToWrite->GetTopology()->GetNumberOfElements();
192 int num_elem_blk = 1;
193 int num_node_sets = 0;
194 int num_side_sets = 0;
195
196 for (int i=0; i<gridToWrite->GetNumberOfSets(); ++i)
197 {
198 switch(gridToWrite->GetSets(i)->GetSetType())
199 {
200 case(XDMF_SET_TYPE_CELL):
201 {
202 num_side_sets++;
203 break;
204 }
205 case(XDMF_SET_TYPE_NODE):
206 {
207 num_node_sets++;
208 break;
209 }
210 }
211 }
212
213 ex_put_init(exodusHandle, title.c_str(), num_dim, num_nodes, num_elem, num_elem_blk, num_node_sets, num_side_sets);
214
215 // Write nodal coordinate values to exodus
216 double * x = new double[num_nodes];
217 double * y = new double[num_nodes];
218 double * z = new double[num_nodes];
219 if(gridToWrite->GetGeometry()->GetGeometryType() == XDMF_GEOMETRY_XYZ || gridToWrite->GetGeometry()->GetGeometryType() == XDMF_GEOMETRY_XY)
220 {
221 gridToWrite->GetGeometry()->GetPoints()->GetValues(0, x, num_nodes, 3);
222 gridToWrite->GetGeometry()->GetPoints()->GetValues(1, y, num_nodes, 3);
223 if(gridToWrite->GetGeometry()->GetGeometryType() == XDMF_GEOMETRY_XYZ)
224 {
225 gridToWrite->GetGeometry()->GetPoints()->GetValues(2, z, num_nodes, 3);
226 }
227 }
228 else if(gridToWrite->GetGeometry()->GetGeometryType() == XDMF_GEOMETRY_X_Y_Z || gridToWrite->GetGeometry()->GetGeometryType() == XDMF_GEOMETRY_X_Y)
229 {
230 gridToWrite->GetGeometry()->GetPoints()->GetValues(0, x, num_nodes);
231 gridToWrite->GetGeometry()->GetPoints()->GetValues(num_nodes, y, num_nodes);
232 if(gridToWrite->GetGeometry()->GetGeometryType() == XDMF_GEOMETRY_X_Y_Z)
233 {
234 gridToWrite->GetGeometry()->GetPoints()->GetValues(num_nodes*2, z, num_nodes);
235 }
236 }
237
238 ex_put_coord(exodusHandle, x ,y ,z);
239 delete [] x;
240 delete [] y;
241 delete [] z;
242
243 // Write Element block parameters
244 XdmfInt32 topType = gridToWrite->GetTopology()->GetTopologyType();
245 std::string cellType = this->DetermineExodusCellType(topType);
246 if (cellType.compare("") == 0)
247 {
248 std::cout << "Cannot write grid with topology " << gridToWrite->GetTopology()->GetTopologyTypeAsString() << std::endl;
249 return;
250 }
251 ex_put_elem_block(exodusHandle, 10, cellType.c_str(), num_elem, gridToWrite->GetTopology()->GetNodesPerElement(), num_side_sets);
252
253 // Write Element Connectivity
254 int * elem_connectivity = new int[num_elem * gridToWrite->GetTopology()->GetNodesPerElement()];
255 // Add 1 to connectivity array since exodus indices start at 1
256 *gridToWrite->GetTopology()->GetConnectivity() + 1;
257 gridToWrite->GetTopology()->GetConnectivity()->GetValues(0, elem_connectivity, num_elem * gridToWrite->GetTopology()->GetNodesPerElement());
258
259 if(topType == XDMF_HEX_20 || topType == XDMF_HEX_27)
260 {
261 int * ptr = elem_connectivity;
262 int k;
263 int itmp[4];
264
265 // Exodus Node ordering does not match Xdmf, we must convert.
266 for (int i=0; i<num_elem; i++)
267 {
268 ptr += 12;
269
270 for ( k = 0; k < 4; ++k, ++ptr)
271 {
272 itmp[k] = *ptr;
273 *ptr = ptr[4];
274 }
275
276 for ( k = 0; k < 4; ++k, ++ptr )
277 {
278 *ptr = itmp[k];
279 }
280
281 if(topType == XDMF_HEX_27)
282 {
283 itmp[0] = *ptr;
284 *(ptr++) = ptr[6];
285 itmp[1] = *ptr;
286 *(ptr++) = ptr[3];
287 itmp[2] = *ptr;
288 *(ptr++) = ptr[3];
289 itmp[3] = *ptr;
290 for ( k = 0; k < 4; ++k, ++ptr )
291 {
292 *ptr = itmp[k];
293 }
294 }
295 }
296 }
297 else if (topType == XDMF_WEDGE_15 || topType == XDMF_WEDGE_18)
298 {
299 int * ptr = elem_connectivity;
300 int k;
301 int itmp[3];
302
303 // Exodus Node ordering does not match Xdmf, we must convert.
304 for (int i=0; i<num_elem; i++)
305 {
306 ptr += 9;
307
308 for (k = 0; k < 3; ++k, ++ptr)
309 {
310 itmp[k] = *ptr;
311 *ptr = ptr[3];
312 }
313
314 for (k = 0; k < 3; ++k, ++ptr)
315 {
316 *ptr = itmp[k];
317 }
318
319 if(topType == XDMF_WEDGE_18)
320 {
321 itmp[0] = *(ptr);
322 itmp[1] = *(ptr+1);
323 itmp[2] = *(ptr+2);
324 *(ptr++) = itmp[2];
325 *(ptr++) = itmp[0];
326 *(ptr++) = itmp[1];
327 }
328 }
329 }
330
331 ex_put_elem_conn(exodusHandle, 10, elem_connectivity);
332 delete [] elem_connectivity;
333
334 // Write Attributes
335 int numGlobalAttributes = 0;
336 int numNodalAttributes = 0;
337 int numElementAttributes = 0;
338
339 std::vector<int> globalComponents;
340 std::vector<int> nodalComponents;
341 std::vector<int> elementComponents;
342 std::vector<std::string> globalAttributeNames;
343 std::vector<std::string> nodalAttributeNames;
344 std::vector<std::string> elementAttributeNames;
345
346 for(int i=0; i<gridToWrite->GetNumberOfAttributes(); ++i)
347 {
348 XdmfAttribute * currAttribute = gridToWrite->GetAttribute(i);
349 currAttribute->Update();
350 int numComponents = 0;
351 switch(currAttribute->GetAttributeCenter())
352 {
353 case(XDMF_ATTRIBUTE_CENTER_GRID):
354 {
355 numComponents = currAttribute->GetValues()->GetNumberOfElements();
356 globalComponents.push_back(numComponents);
357 numGlobalAttributes += numComponents;
358 nameHandler->ConstructAttributeName(currAttribute->GetName(), globalAttributeNames, numComponents);
359 break;
360 }
361 case(XDMF_ATTRIBUTE_CENTER_NODE):
362 {
363 numComponents = currAttribute->GetValues()->GetNumberOfElements() / num_nodes;
364 nodalComponents.push_back(numComponents);
365 numNodalAttributes += numComponents;
366 nameHandler->ConstructAttributeName(currAttribute->GetName(), nodalAttributeNames, numComponents);
367 break;
368 }
369 case(XDMF_ATTRIBUTE_CENTER_CELL):
370 {
371 numComponents = currAttribute->GetValues()->GetNumberOfElements() / num_elem;
372 elementComponents.push_back(numComponents);
373 numElementAttributes += numComponents;
374 nameHandler->ConstructAttributeName(currAttribute->GetName(), elementAttributeNames, numComponents);
375 break;
376 }
377 }
378 }
379
380 ex_put_var_param(exodusHandle, "g", numGlobalAttributes);
381 ex_put_var_param(exodusHandle, "n", numNodalAttributes);
382 ex_put_var_param(exodusHandle, "e", numElementAttributes);
383
384 char ** globalNames = new char*[numGlobalAttributes];
385 char ** nodalNames = new char*[numNodalAttributes];
386 char ** elementNames = new char*[numElementAttributes];
387
388 for(int i=0; i<numGlobalAttributes; ++i)
389 {
390 globalNames[i] = (char*)globalAttributeNames[i].c_str();
391 }
392
393 for(int i=0; i<numNodalAttributes; ++i)
394 {
395 nodalNames[i] = (char*)nodalAttributeNames[i].c_str();
396 }
397
398 for(int i=0; i<numElementAttributes; ++i)
399 {
400 elementNames[i] = (char*)elementAttributeNames[i].c_str();
401 }
402
403 ex_put_var_names(exodusHandle, "g", numGlobalAttributes, globalNames);
404 ex_put_var_names(exodusHandle, "n", numNodalAttributes, nodalNames);
405 ex_put_var_names(exodusHandle, "e", numElementAttributes, elementNames);
406
407 delete [] globalNames;
408 delete [] nodalNames;
409 delete [] elementNames;
410
411 double * globalAttributeVals = new double[numGlobalAttributes];
412
413 int globalIndex = 0;
414 int globalComponentIndex = 0;
415 int nodalIndex = 0;
416 int nodalComponentIndex = 0;
417 int elementIndex = 0;
418 int elementComponentIndex = 0;
419
420 for(int i=0; i<gridToWrite->GetNumberOfAttributes(); ++i)
421 {
422 XdmfAttribute * currAttribute = gridToWrite->GetAttribute(i);
423 switch(currAttribute->GetAttributeCenter())
424 {
425 case(XDMF_ATTRIBUTE_CENTER_GRID):
426 {
427 for(int j=0; j<globalComponents[globalComponentIndex]; ++j)
428 {
429 currAttribute->GetValues()->GetValues(j, &globalAttributeVals[globalIndex], 1);
430 globalIndex++;
431 }
432 globalComponentIndex++;
433 break;
434 }
435 case(XDMF_ATTRIBUTE_CENTER_NODE):
436 {
437 for(int j=0; j<nodalComponents[nodalComponentIndex]; ++j)
438 {
439 double * nodalValues = new double[num_nodes];
440 currAttribute->GetValues()->GetValues(j, nodalValues, num_nodes, nodalComponents[nodalComponentIndex]);
441 ex_put_nodal_var(exodusHandle, 1, nodalIndex+1, num_nodes, nodalValues);
442 ex_update(exodusHandle);
443 delete [] nodalValues;
444 nodalIndex++;
445 }
446 nodalComponentIndex++;
447 break;
448 }
449 case(XDMF_ATTRIBUTE_CENTER_CELL):
450 {
451 for(int j=0; j<elementComponents[elementComponentIndex]; ++j)
452 {
453 double * elementValues = new double[num_elem];
454 currAttribute->GetValues()->GetValues(j, elementValues, num_elem, elementComponents[elementComponentIndex]);
455 ex_put_elem_var(exodusHandle, 1, elementIndex+1, 10, num_elem, elementValues);
456 ex_update(exodusHandle);
457 delete [] elementValues;
458 elementIndex++;
459 }
460 elementComponentIndex++;
461 break;
462 }
463 }
464 }
465 ex_put_glob_vars(exodusHandle, 1, numGlobalAttributes, globalAttributeVals);
466 ex_update(exodusHandle);
467 delete [] globalAttributeVals;
468
469 // Write Sets
470 int setId = 20;
471 for (int i=0; i<gridToWrite->GetNumberOfSets(); ++i)
472 {
473 XdmfSet * currSet = gridToWrite->GetSets(i);
474 currSet->Update();
475 int numValues = currSet->GetIds()->GetNumberOfElements();
476 std::string name = currSet->GetName();
477 if(name.length() > MAX_STR_LENGTH)
478 {
479 name = name.substr(0, MAX_STR_LENGTH);
480 }
481 switch(currSet->GetSetType())
482 {
483 case(XDMF_SET_TYPE_CELL):
484 {
485 ex_put_side_set_param(exodusHandle, setId, numValues, 0);
486 int * values = new int[numValues];
487 // Add 1 to xdmf ids because exodus ids begin at 1
488 *currSet->GetIds() + 1;
489 currSet->GetIds()->GetValues(0, values, numValues);
490 ex_put_side_set(exodusHandle, setId, values, NULL);
491 ex_put_name(exodusHandle, EX_SIDE_SET, setId, name.c_str());
492 setId++;
493 delete [] values;
494 break;
495 }
496 case(XDMF_SET_TYPE_NODE):
497 {
498 ex_put_node_set_param(exodusHandle, setId, numValues, 0);
499 int * values = new int[numValues];
500 // Add 1 to xdmf ids because exodus ids begin at 1
501 *currSet->GetIds() + 1;
502 currSet->GetIds()->GetValues(0, values, numValues);
503 ex_put_node_set(exodusHandle, setId, values);
504 ex_put_name(exodusHandle, EX_NODE_SET, setId, name.c_str());
505 setId++;
506 delete [] values;
507 break;
508 }
509 }
510 }
511
512 // Close Exodus File
513 ex_close(exodusHandle);
514 }
515