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