1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkExodusIIWriter.h
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 /*----------------------------------------------------------------------------
16  Copyright (c) Sandia Corporation
17  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
18 ----------------------------------------------------------------------------*/
19 
20 /**
21  * @class   vtkExodusIIWriter
22  * @brief   Write Exodus II files
23  *
24  *     This is a vtkWriter that writes it's vtkUnstructuredGrid
25  *     input out to an Exodus II file.  Go to http://endo.sandia.gov/SEACAS/
26  *     for more information about the Exodus II format.
27  *
28  *     Exodus files contain much information that is not captured
29  *     in a vtkUnstructuredGrid, such as time steps, information
30  *     lines, node sets, and side sets.  This information can be
31  *     stored in a vtkModelMetadata object.
32  *
33  *     The vtkExodusReader and vtkPExodusReader can create
34  *     a vtkModelMetadata object and embed it in a vtkUnstructuredGrid
35  *     in a series of field arrays.  This writer searches for these
36  *     field arrays and will use the metadata contained in them
37  *     when creating the new Exodus II file.
38  *
39  *     You can also explicitly give the vtkExodusIIWriter a
40  *     vtkModelMetadata object to use when writing the file.
41  *
42  *     In the absence of the information provided by vtkModelMetadata,
43  *     if this writer is not part of a parallel application, we will use
44  *     reasonable defaults for all the values in the output Exodus file.
45  *     If you don't provide a block ID element array, we'll create a
46  *     block for each cell type that appears in the unstructured grid.
47  *
48  *     However if this writer is part of a parallel application (hence
49  *     writing out a distributed Exodus file), then we need at the very
50  *     least a list of all the block IDs that appear in the file.  And
51  *     we need the element array of block IDs for the input unstructured grid.
52  *
53  *     In the absence of a vtkModelMetadata object, you can also provide
54  *     time step information which we will include in the output Exodus
55  *     file.
56  *
57  * @warning
58  *     If the input floating point field arrays and point locations are all
59  *     floats or all doubles, this class will operate more efficiently.
60  *     Mixing floats and doubles will slow you down, because Exodus II
61  *     requires that we write only floats or only doubles.
62  *
63  * @warning
64  *     We use the terms "point" and "node" interchangeably.
65  *     Also, we use the terms "element" and "cell" interchangeably.
66  */
67 
68 #ifndef vtkExodusIIWriter_h
69 #define vtkExodusIIWriter_h
70 
71 #include "vtkIOExodusModule.h" // For export macro
72 #include "vtkSmartPointer.h"   // For vtkSmartPointer
73 #include "vtkWriter.h"
74 
75 #include <map>    // STL Header
76 #include <string> // STL Header
77 #include <vector> // STL Header
78 
79 class vtkModelMetadata;
80 class vtkDoubleArray;
81 class vtkIntArray;
82 class vtkUnstructuredGrid;
83 
84 class VTKIOEXODUS_EXPORT vtkExodusIIWriter : public vtkWriter
85 {
86 public:
87   static vtkExodusIIWriter* New();
88   vtkTypeMacro(vtkExodusIIWriter, vtkWriter);
89   void PrintSelf(ostream& os, vtkIndent indent) override;
90 
91   /**
92    * Specify the vtkModelMetadata object which contains the Exodus file
93    * model information (metadata) absent in the vtkUnstructuredGrid.  If you
94    * have this object, you don't need to set any other values before writing.
95    * (Just the FileName and the Input.)
96    * Note that the vtkExodusReader can create and attach a vtkModelMetadata
97    * object to it's output.  If this has happened, the ExodusIIWriter will
98    * find it and use it.
99    */
100 
101   void SetModelMetadata(vtkModelMetadata*);
102   vtkGetObjectMacro(ModelMetadata, vtkModelMetadata);
103 
104   /**
105    * Name for the output file.  If writing in parallel, the number
106    * of processes and the process rank will be appended to the name,
107    * so each process is writing out a separate file.
108    * If not set, this class will make up a file name.
109    */
110 
111   vtkSetFilePathMacro(FileName);
112   vtkGetFilePathMacro(FileName);
113 
114   /**
115    * If StoreDoubles is ON, the floating point fields in the Exodus file
116    * will be double precision fields.  The default is determined by the
117    * max precision of the input.  If the field data appears to be doubles,
118    * then StoreDoubles will be ON, otherwise StoreDoubles will be OFF.
119    */
120 
121   vtkSetMacro(StoreDoubles, int);
122   vtkGetMacro(StoreDoubles, int);
123 
124   /**
125    * We never write out ghost cells.  This variable is here to satisfy
126    * the behavior of ParaView on invoking a parallel writer.
127    */
128 
129   vtkSetMacro(GhostLevel, int);
130   vtkGetMacro(GhostLevel, int);
131 
132   /**
133    * By default, the integer array containing the global Block Ids of the
134    * cells is not included when the new Exodus II file is written out.  If
135    * you do want to include this array, set WriteOutBlockIdArray to ON.
136    */
137 
138   vtkSetMacro(WriteOutBlockIdArray, vtkTypeBool);
139   vtkGetMacro(WriteOutBlockIdArray, vtkTypeBool);
140   vtkBooleanMacro(WriteOutBlockIdArray, vtkTypeBool);
141 
142   /**
143    * By default, the integer array containing the global Node Ids
144    * is not included when the new Exodus II file is written out.  If
145    * you do want to include this array, set WriteOutGlobalNodeIdArray to ON.
146    */
147 
148   vtkSetMacro(WriteOutGlobalNodeIdArray, vtkTypeBool);
149   vtkGetMacro(WriteOutGlobalNodeIdArray, vtkTypeBool);
150   vtkBooleanMacro(WriteOutGlobalNodeIdArray, vtkTypeBool);
151 
152   /**
153    * By default, the integer array containing the global Element Ids
154    * is not included when the new Exodus II file is written out.  If you
155    * do want to include this array, set WriteOutGlobalElementIdArray to ON.
156    */
157 
158   vtkSetMacro(WriteOutGlobalElementIdArray, vtkTypeBool);
159   vtkGetMacro(WriteOutGlobalElementIdArray, vtkTypeBool);
160   vtkBooleanMacro(WriteOutGlobalElementIdArray, vtkTypeBool);
161 
162   /**
163    * When WriteAllTimeSteps is turned ON, the writer is executed once for
164    * each timestep available from the reader.
165    */
166 
167   vtkSetMacro(WriteAllTimeSteps, vtkTypeBool);
168   vtkGetMacro(WriteAllTimeSteps, vtkTypeBool);
169   vtkBooleanMacro(WriteAllTimeSteps, vtkTypeBool);
170 
171   vtkSetStringMacro(BlockIdArrayName);
172   vtkGetStringMacro(BlockIdArrayName);
173 
174   /**
175    * In certain cases we know that metadata doesn't exist and
176    * we want to ignore that warning.
177    */
178 
179   vtkSetMacro(IgnoreMetaDataWarning, bool);
180   vtkGetMacro(IgnoreMetaDataWarning, bool);
181   vtkBooleanMacro(IgnoreMetaDataWarning, bool);
182 
183 protected:
184   vtkExodusIIWriter();
185   ~vtkExodusIIWriter() override;
186 
187   vtkModelMetadata* ModelMetadata;
188 
189   char* BlockIdArrayName;
190 
191   char* FileName;
192   int fid;
193 
194   int NumberOfProcesses;
195   int MyRank;
196 
197   int PassDoubles;
198 
199   int StoreDoubles;
200   int GhostLevel;
201   vtkTypeBool WriteOutBlockIdArray;
202   vtkTypeBool WriteOutGlobalNodeIdArray;
203   vtkTypeBool WriteOutGlobalElementIdArray;
204   vtkTypeBool WriteAllTimeSteps;
205   int NumberOfTimeSteps;
206 
207   int CurrentTimeIndex;
208   int FileTimeOffset;
209   bool TopologyChanged;
210   bool IgnoreMetaDataWarning;
211 
212   vtkDataObject* OriginalInput;
213   std::vector<vtkSmartPointer<vtkUnstructuredGrid>> FlattenedInput;
214   std::vector<vtkSmartPointer<vtkUnstructuredGrid>> NewFlattenedInput;
215 
216   std::vector<vtkStdString> FlattenedNames;
217   std::vector<vtkStdString> NewFlattenedNames;
218 
219   std::vector<vtkIntArray*> BlockIdList;
220 
221   struct Block
222   {
BlockBlock223     Block()
224     {
225       this->Name = nullptr;
226       this->Type = 0;
227       this->NumElements = 0;
228       this->ElementStartIndex = -1;
229       this->NodesPerElement = 0;
230       this->EntityCounts = std::vector<int>();
231       this->EntityNodeOffsets = std::vector<int>();
232       this->GridIndex = 0;
233       this->OutputIndex = -1;
234       this->NumAttributes = 0;
235       this->BlockAttributes = nullptr;
236     };
237     const char* Name;
238     int Type;
239     int NumElements;
240     int ElementStartIndex;
241     int NodesPerElement;
242     std::vector<int> EntityCounts;
243     std::vector<int> EntityNodeOffsets;
244     size_t GridIndex;
245     // std::vector<int> CellIndex;
246     int OutputIndex;
247     int NumAttributes;
248     float* BlockAttributes; // Owned by metamodel or null.  Don't delete.
249   };
250   std::map<int, Block> BlockInfoMap;
251   int NumCells, NumPoints, MaxId;
252 
253   std::vector<vtkIdType*> GlobalElementIdList;
254   std::vector<vtkIdType*> GlobalNodeIdList;
255 
256   int AtLeastOneGlobalElementIdList;
257   int AtLeastOneGlobalNodeIdList;
258 
259   struct VariableInfo
260   {
261     int NumComponents;
262     int InIndex;
263     int ScalarOutOffset;
264     std::vector<std::string> OutNames;
265   };
266   std::map<std::string, VariableInfo> GlobalVariableMap;
267   std::map<std::string, VariableInfo> BlockVariableMap;
268   std::map<std::string, VariableInfo> NodeVariableMap;
269   int NumberOfScalarGlobalArrays;
270   int NumberOfScalarElementArrays;
271   int NumberOfScalarNodeArrays;
272 
273   std::vector<std::vector<int>> CellToElementOffset;
274 
275   // By BlockId, and within block ID by element variable, with variables
276   // appearing in the same order in which they appear in OutputElementArrayNames
277 
278   int* BlockElementVariableTruthTable;
279   int AllVariablesDefinedInAllBlocks;
280 
281   int BlockVariableTruthValue(int blockIdx, int varIdx);
282 
283   char* StrDupWithNew(const char* s);
284   void StringUppercase(std::string& str);
285 
286   vtkTypeBool ProcessRequest(vtkInformation* request, vtkInformationVector** inputVector,
287     vtkInformationVector* outputVector) override;
288 
289   int RequestInformation(vtkInformation* request, vtkInformationVector** inputVector,
290     vtkInformationVector* outputVector);
291 
292   virtual int RequestUpdateExtent(vtkInformation* request, vtkInformationVector** inputVector,
293     vtkInformationVector* outputVector);
294 
295   int FillInputPortInformation(int port, vtkInformation* info) override;
296 
297   int RequestData(vtkInformation* request, vtkInformationVector** inputVector,
298     vtkInformationVector* outputVector) override;
299 
300   void WriteData() override;
301 
302   int FlattenHierarchy(vtkDataObject* input, const char* name, bool& changed);
303 
304   int CreateNewExodusFile();
305   void CloseExodusFile();
306 
307   int IsDouble();
308   void RemoveGhostCells();
309   int CheckParametersInternal(int numberOfProcesses, int myRank);
310   virtual int CheckParameters();
311   // If writing in parallel multiple time steps exchange after each time step
312   // if we should continue the execution. Pass local continueExecution as a
313   // parameter and return the global continueExecution.
314   virtual int GlobalContinueExecuting(int localContinueExecution);
315   int CheckInputArrays();
316   virtual void CheckBlockInfoMap();
317   int ConstructBlockInfoMap();
318   int ConstructVariableInfoMaps();
319   int ParseMetadata();
320   int CreateDefaultMetadata();
321   char* GetCellTypeName(int t);
322 
323   int CreateBlockIdMetadata(vtkModelMetadata* em);
324   int CreateBlockVariableMetadata(vtkModelMetadata* em);
325   int CreateSetsMetadata(vtkModelMetadata* em);
326 
327   void ConvertVariableNames(std::map<std::string, VariableInfo>& variableMap);
328   char** FlattenOutVariableNames(
329     int nScalarArrays, const std::map<std::string, VariableInfo>& variableMap);
330   std::string CreateNameForScalarArray(const char* root, int component, int numComponents);
331 
332   std::map<vtkIdType, vtkIdType>* LocalNodeIdMap;
333   std::map<vtkIdType, vtkIdType>* LocalElementIdMap;
334 
335   vtkIdType GetNodeLocalId(vtkIdType id);
336   vtkIdType GetElementLocalId(vtkIdType id);
337   int GetElementType(vtkIdType id);
338 
339   int WriteInitializationParameters();
340   int WriteInformationRecords();
341   int WritePoints();
342   int WriteCoordinateNames();
343   int WriteGlobalPointIds();
344   int WriteBlockInformation();
345   int WriteGlobalElementIds();
346   int WriteVariableArrayNames();
347   int WriteNodeSetInformation();
348   int WriteSideSetInformation();
349   int WriteProperties();
350   int WriteNextTimeStep();
351   vtkIntArray* GetBlockIdArray(const char* BlockIdArrayName, vtkUnstructuredGrid* input);
352   static bool SameTypeOfCells(vtkIntArray* cellToBlockId, vtkUnstructuredGrid* input);
353 
354   double ExtractGlobalData(const char* name, int comp, int ts);
355   int WriteGlobalData(int timestep, vtkDataArray* buffer);
356   void ExtractCellData(const char* name, int comp, vtkDataArray* buffer);
357   int WriteCellData(int timestep, vtkDataArray* buffer);
358   void ExtractPointData(const char* name, int comp, vtkDataArray* buffer);
359   int WritePointData(int timestep, vtkDataArray* buffer);
360 
361   /**
362    * Get the maximum length name in the input data set. If it is smaller
363    * than 32 characters long we just return the ExodusII default of 32.
364    */
365   virtual unsigned int GetMaxNameLength();
366 
367 private:
368   vtkExodusIIWriter(const vtkExodusIIWriter&) = delete;
369   void operator=(const vtkExodusIIWriter&) = delete;
370 };
371 
372 #endif
373