1 // -*- c++ -*-
2 /*=========================================================================
3 
4   Program:   Visualization Toolkit
5   Module:    vtkSLACReader.h
6 
7   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
8   All rights reserved.
9   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
10 
11      This software is distributed WITHOUT ANY WARRANTY; without even
12      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13      PURPOSE.  See the above copyright notice for more information.
14 
15 =========================================================================*/
16 
17 /*-------------------------------------------------------------------------
18   Copyright 2008 Sandia Corporation.
19   Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
20   the U.S. Government retains certain rights in this software.
21 -------------------------------------------------------------------------*/
22 
23 /**
24  * @class   vtkSLACReader
25  *
26  *
27  *
28  * A reader for a data format used by Omega3p, Tau3p, and several other tools
29  * used at the Standford Linear Accelerator Center (SLAC).  The underlying
30  * format uses netCDF to store arrays, but also imposes several conventions
31  * to form an unstructured grid of elements.
32  *
33  */
34 
35 #ifndef vtkSLACReader_h
36 #define vtkSLACReader_h
37 
38 #include "vtkIONetCDFModule.h" // For export macro
39 #include "vtkMultiBlockDataSetAlgorithm.h"
40 
41 #include "vtkSmartPointer.h" // For internal method.
42 
43 class vtkDataArraySelection;
44 class vtkDoubleArray;
45 class vtkIdTypeArray;
46 class vtkInformationIntegerKey;
47 class vtkInformationObjectBaseKey;
48 
49 class VTKIONETCDF_EXPORT vtkSLACReader : public vtkMultiBlockDataSetAlgorithm
50 {
51 public:
52   vtkTypeMacro(vtkSLACReader, vtkMultiBlockDataSetAlgorithm);
53   static vtkSLACReader* New();
54   void PrintSelf(ostream& os, vtkIndent indent) override;
55 
56   vtkGetFilePathMacro(MeshFileName);
57   vtkSetFilePathMacro(MeshFileName);
58 
59   ///@{
60   /**
61    * There may be one mode file (usually for actual modes) or multiple mode
62    * files (which usually actually represent time series).  These methods
63    * set and clear the list of mode files (which can be a single mode file).
64    */
65   virtual void AddModeFileName(VTK_FILEPATH const char* fname);
66   virtual void RemoveAllModeFileNames();
67   virtual unsigned int GetNumberOfModeFileNames();
68   virtual VTK_FILEPATH const char* GetModeFileName(unsigned int idx);
69   ///@}
70 
71   ///@{
72   /**
73    * If on, reads the internal volume of the data set.  Set to off by default.
74    */
75   vtkGetMacro(ReadInternalVolume, vtkTypeBool);
76   vtkSetMacro(ReadInternalVolume, vtkTypeBool);
77   vtkBooleanMacro(ReadInternalVolume, vtkTypeBool);
78   ///@}
79 
80   ///@{
81   /**
82    * If on, reads the external surfaces of the data set.  Set to on by default.
83    */
84   vtkGetMacro(ReadExternalSurface, vtkTypeBool);
85   vtkSetMacro(ReadExternalSurface, vtkTypeBool);
86   vtkBooleanMacro(ReadExternalSurface, vtkTypeBool);
87   ///@}
88 
89   ///@{
90   /**
91    * If on, reads midpoint information for external surfaces and builds
92    * quadratic surface triangles.  Set to on by default.
93    */
94   vtkGetMacro(ReadMidpoints, vtkTypeBool);
95   vtkSetMacro(ReadMidpoints, vtkTypeBool);
96   vtkBooleanMacro(ReadMidpoints, vtkTypeBool);
97   ///@}
98 
99   ///@{
100   /**
101    * Variable array selection.
102    */
103   virtual int GetNumberOfVariableArrays();
104   virtual const char* GetVariableArrayName(int index);
105   virtual int GetVariableArrayStatus(const char* name);
106   virtual void SetVariableArrayStatus(const char* name, int status);
107   ///@}
108 
109   ///@{
110   /**
111    * Sets the scale factor for each mode. Each scale factor is reset to 1.
112    */
113   virtual void ResetFrequencyScales();
114   virtual void SetFrequencyScale(int index, double scale);
115   ///@}
116 
117   ///@{
118   /**
119    * Sets the phase offset for each mode. Each shift is reset to 0.
120    */
121   virtual void ResetPhaseShifts();
122   virtual void SetPhaseShift(int index, double shift);
123   ///@}
124 
125   ///@{
126   /**
127    * NOTE: This is not thread-safe.
128    */
129   virtual vtkDoubleArray* GetFrequencyScales();
130   virtual vtkDoubleArray* GetPhaseShifts();
131   ///@}
132 
133   /**
134    * Returns true if the given file can be read by this reader.
135    */
136   static int CanReadFile(VTK_FILEPATH const char* filename);
137 
138   /**
139    * This key is attached to the metadata information of all data sets in the
140    * output that are part of the internal volume.
141    */
142   static vtkInformationIntegerKey* IS_INTERNAL_VOLUME();
143 
144   /**
145    * This key is attached to the metadata information of all data sets in the
146    * output that are part of the external surface.
147    */
148   static vtkInformationIntegerKey* IS_EXTERNAL_SURFACE();
149 
150   ///@{
151   /**
152    * All the data sets stored in the multiblock output share the same point
153    * data.  For convenience, the point coordinates (vtkPoints) and point data
154    * (vtkPointData) are saved under these keys in the vtkInformation of the
155    * output data set.
156    */
157   static vtkInformationObjectBaseKey* POINTS();
158   static vtkInformationObjectBaseKey* POINT_DATA();
159   ///@}
160 
161   ///@{
162   /**
163    * Simple class used internally to define an edge based on the endpoints.  The
164    * endpoints are canonically identified by the lower and higher values.
165    */
166   class VTKIONETCDF_EXPORT EdgeEndpoints
167   {
168   public:
EdgeEndpoints()169     EdgeEndpoints()
170       : MinEndPoint(-1)
171       , MaxEndPoint(-1)
172     {
173     }
EdgeEndpoints(vtkIdType endpointA,vtkIdType endpointB)174     EdgeEndpoints(vtkIdType endpointA, vtkIdType endpointB)
175     {
176       if (endpointA < endpointB)
177       {
178         this->MinEndPoint = endpointA;
179         this->MaxEndPoint = endpointB;
180       }
181       else
182       {
183         this->MinEndPoint = endpointB;
184         this->MaxEndPoint = endpointA;
185       }
186     }
GetMinEndPoint()187     inline vtkIdType GetMinEndPoint() const { return this->MinEndPoint; }
GetMaxEndPoint()188     inline vtkIdType GetMaxEndPoint() const { return this->MaxEndPoint; }
189     inline bool operator==(const EdgeEndpoints& other) const
190     {
191       return ((this->GetMinEndPoint() == other.GetMinEndPoint()) &&
192         (this->GetMaxEndPoint() == other.GetMaxEndPoint()));
193     }
194 
195   protected:
196     vtkIdType MinEndPoint;
197     vtkIdType MaxEndPoint;
198   };
199   ///@}
200 
201   ///@{
202   /**
203    * Simple class used internally for holding midpoint information.
204    */
205   class VTKIONETCDF_EXPORT MidpointCoordinates
206   {
207   public:
208     MidpointCoordinates() = default;
MidpointCoordinates(const double coord[3],vtkIdType id)209     MidpointCoordinates(const double coord[3], vtkIdType id)
210     {
211       this->Coordinate[0] = coord[0];
212       this->Coordinate[1] = coord[1];
213       this->Coordinate[2] = coord[2];
214       this->ID = id;
215     }
216     double Coordinate[3];
217     vtkIdType ID;
218   };
219   ///@}
220 
221   enum
222   {
223     SURFACE_OUTPUT = 0,
224     VOLUME_OUTPUT = 1,
225     NUM_OUTPUTS = 2
226   };
227 
228 protected:
229   vtkSLACReader();
230   ~vtkSLACReader() override;
231 
232   class vtkInternal;
233   vtkInternal* Internal;
234 
235   // Friend so vtkInternal can access MidpointIdMap
236   // (so Sun CC compiler doesn't complain).
237   friend class vtkInternal;
238 
239   char* MeshFileName;
240 
241   vtkTypeBool ReadInternalVolume;
242   vtkTypeBool ReadExternalSurface;
243   vtkTypeBool ReadMidpoints;
244 
245   /**
246    * True if reading from a proper mode file.  Set in RequestInformation.
247    */
248   bool ReadModeData;
249 
250   /**
251    * True if "mode" files are a sequence of time steps.
252    */
253   bool TimeStepModes;
254 
255   /**
256    * True if mode files describe vibrating fields.
257    */
258   bool FrequencyModes;
259 
260   int RequestInformation(vtkInformation* request, vtkInformationVector** inputVector,
261     vtkInformationVector* outputVector) override;
262 
263   int RequestData(vtkInformation* request, vtkInformationVector** inputVector,
264     vtkInformationVector* outputVector) override;
265 
266   /**
267    * Callback registered with the VariableArraySelection.
268    */
269   static void SelectionModifiedCallback(
270     vtkObject* caller, unsigned long eid, void* clientdata, void* calldata);
271 
272   /**
273    * Convenience function that checks the dimensions of a 2D netCDF array that
274    * is supposed to be a set of tuples.  It makes sure that the number of
275    * dimensions is expected and that the number of components in each tuple
276    * agree with what is expected.  It then returns the number of tuples.  An
277    * error is emitted and 0 is returned if the checks fail.
278    */
279   virtual vtkIdType GetNumTuplesInVariable(int ncFD, int varId, int expectedNumComponents);
280 
281   /**
282    * Checks the winding of the tetrahedra in the mesh file.  Returns 1 if
283    * the winding conforms to VTK, 0 if the winding needs to be corrected.
284    */
285   virtual int CheckTetrahedraWinding(int meshFD);
286 
287   /**
288    * Read the connectivity information from the mesh file.  Returns 1 on
289    * success, 0 on failure.
290    */
291   virtual int ReadConnectivity(
292     int meshFD, vtkMultiBlockDataSet* surfaceOutput, vtkMultiBlockDataSet* volumeOutput);
293 
294   ///@{
295   /**
296    * Reads tetrahedron connectivity arrays.  Called by ReadConnectivity.
297    */
298   virtual int ReadTetrahedronInteriorArray(int meshFD, vtkIdTypeArray* connectivity);
299   virtual int ReadTetrahedronExteriorArray(int meshFD, vtkIdTypeArray* connectivity);
300   ///@}
301 
302   /**
303    * Reads point data arrays.  Called by ReadCoordinates and ReadFieldData.
304    */
305   virtual vtkSmartPointer<vtkDataArray> ReadPointDataArray(int ncFD, int varId);
306 
307   /**
308    * Helpful constants equal to the amount of identifiers per tet.
309    */
310   enum
311   {
312     NumPerTetInt = 5,
313     NumPerTetExt = 9
314   };
315 
316   ///@{
317   /**
318    * Manages a map from edges to midpoint coordinates.
319    */
320   class VTKIONETCDF_EXPORT MidpointCoordinateMap
321   {
322   public:
323     MidpointCoordinateMap();
324     ~MidpointCoordinateMap();
325     ///@}
326 
327     void AddMidpoint(const EdgeEndpoints& edge, const MidpointCoordinates& midpoint);
328     void RemoveMidpoint(const EdgeEndpoints& edge);
329     void RemoveAllMidpoints();
330     vtkIdType GetNumberOfMidpoints() const;
331 
332     /**
333      * Finds the coordinates for the given edge or returns nullptr if it
334      * does not exist.
335      */
336     MidpointCoordinates* FindMidpoint(const EdgeEndpoints& edge);
337 
338   protected:
339     class vtkInternal;
340     vtkInternal* Internal;
341 
342   private:
343     // Too lazy to implement these.
344     MidpointCoordinateMap(const MidpointCoordinateMap&) = delete;
345     void operator=(const MidpointCoordinateMap&) = delete;
346   };
347 
348   ///@{
349   /**
350    * Manages a map from edges to the point id of the midpoint.
351    */
352   class VTKIONETCDF_EXPORT MidpointIdMap
353   {
354   public:
355     MidpointIdMap();
356     ~MidpointIdMap();
357     ///@}
358 
359     void AddMidpoint(const EdgeEndpoints& edge, vtkIdType midpoint);
360     void RemoveMidpoint(const EdgeEndpoints& edge);
361     void RemoveAllMidpoints();
362     vtkIdType GetNumberOfMidpoints() const;
363 
364     /**
365      * Finds the id for the given edge or returns nullptr if it does not exist.
366      */
367     vtkIdType* FindMidpoint(const EdgeEndpoints& edge);
368 
369     /**
370      * Initialize iteration.  The iteration can occur in any order.
371      */
372     void InitTraversal();
373     /**
374      * Get the next midpoint in the iteration.  Return 0 if the end is reached.
375      */
376     bool GetNextMidpoint(EdgeEndpoints& edge, vtkIdType& midpoint);
377 
378   protected:
379     class vtkInternal;
380     vtkInternal* Internal;
381 
382   private:
383     // Too lazy to implement these.
384     MidpointIdMap(const MidpointIdMap&) = delete;
385     void operator=(const MidpointIdMap&) = delete;
386   };
387 
388   /**
389    * Read in the point coordinate data from the mesh file.  Returns 1 on
390    * success, 0 on failure.
391    */
392   virtual int ReadCoordinates(int meshFD, vtkMultiBlockDataSet* output);
393 
394   /**
395    * Reads in the midpoint coordinate data from the mesh file and returns a map
396    * from edges to midpoints.  This method is called by ReadMidpointData.
397    * Returns 1 on success, 0 on failure.
398    */
399   virtual int ReadMidpointCoordinates(
400     int meshFD, vtkMultiBlockDataSet* output, MidpointCoordinateMap& map);
401 
402   /**
403    * Read in the midpoint data from the mesh file.  Returns 1 on success,
404    * 0 on failure.  Also fills a midpoint id map that will be passed into
405    * InterpolateMidpointFieldData.
406    */
407   virtual int ReadMidpointData(
408     int meshFD, vtkMultiBlockDataSet* output, MidpointIdMap& midpointIds);
409 
410   /**
411    * Instead of reading data from the mesh file, restore the data from the
412    * previous mesh file read.
413    */
414   virtual int RestoreMeshCache(vtkMultiBlockDataSet* surfaceOutput,
415     vtkMultiBlockDataSet* volumeOutput, vtkMultiBlockDataSet* compositeOutput);
416 
417   /**
418    * Read in the field data from the mode file.  Returns 1 on success, 0
419    * on failure.
420    */
421   virtual int ReadFieldData(const int* modeFDArray, int numModeFDs, vtkMultiBlockDataSet* output);
422 
423   /**
424    * Takes the data read on the fields and interpolates data for the midpoints.
425    * map is the same map that was created in ReadMidpointData.
426    */
427   virtual int InterpolateMidpointData(vtkMultiBlockDataSet* output, MidpointIdMap& map);
428 
429   /**
430    * A time stamp for the last time the mesh file was read.  This is used to
431    * determine whether the mesh needs to be read in again or if we just need
432    * to read the mode data.
433    */
434   vtkTimeStamp MeshReadTime;
435 
436   /**
437    * Returns 1 if the mesh is up to date, 0 if the mesh needs to be read from
438    * disk.
439    */
440   virtual int MeshUpToDate();
441 
442 private:
443   vtkSLACReader(const vtkSLACReader&) = delete;
444   void operator=(const vtkSLACReader&) = delete;
445 };
446 
447 #endif // vtkSLACReader_h
448